mobile/android/base/TextSelectionHandle.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1  /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 package org.mozilla.gecko;
     7 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
     8 import org.mozilla.gecko.gfx.LayerView;
    10 import org.json.JSONObject;
    12 import android.content.Context;
    13 import android.content.res.TypedArray;
    14 import android.graphics.PointF;
    15 import android.util.AttributeSet;
    16 import android.util.Log;
    17 import android.view.MotionEvent;
    18 import android.view.View;
    19 import android.widget.ImageView;
    20 import android.widget.RelativeLayout;
    22 class TextSelectionHandle extends ImageView implements View.OnTouchListener {
    23     private static final String LOGTAG = "GeckoTextSelectionHandle";
    25     private enum HandleType { START, MIDDLE, END }; 
    27     private final HandleType mHandleType;
    28     private final int mWidth;
    29     private final int mHeight;
    30     private final int mShadow;
    32     private float mLeft;
    33     private float mTop;
    34     private boolean mIsRTL; 
    35     private PointF mGeckoPoint;
    36     private float mTouchStartX;
    37     private float mTouchStartY;
    38     private int mLayerViewX;
    39     private int mLayerViewY;
    41     private RelativeLayout.LayoutParams mLayoutParams;
    43     private static final int IMAGE_LEVEL_LTR = 0;
    44     private static final int IMAGE_LEVEL_RTL = 1;
    46     public TextSelectionHandle(Context context, AttributeSet attrs) {
    47         super(context, attrs);
    48         setOnTouchListener(this);
    50         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextSelectionHandle);
    51         int handleType = a.getInt(R.styleable.TextSelectionHandle_handleType, 0x01);
    53         if (handleType == 0x01)
    54             mHandleType = HandleType.START;
    55         else if (handleType == 0x02)
    56             mHandleType = HandleType.MIDDLE;
    57         else
    58             mHandleType = HandleType.END;
    60         mIsRTL = false;
    61         mGeckoPoint = new PointF(0.0f, 0.0f);
    63         mWidth = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_width);
    64         mHeight = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_height);
    65         mShadow = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_shadow);
    66     }
    68     @Override
    69     public boolean onTouch(View v, MotionEvent event) {
    70         switch (event.getActionMasked()) {
    71             case MotionEvent.ACTION_DOWN: {
    72                 mTouchStartX = event.getX();
    73                 mTouchStartY = event.getY();
    75                 int[] rect = new int[2];
    76                 GeckoAppShell.getLayerView().getLocationOnScreen(rect);
    77                 mLayerViewX = rect[0];
    78                 mLayerViewY = rect[1];
    79                 break;
    80             }
    81             case MotionEvent.ACTION_UP: {
    82                 mTouchStartX = 0;
    83                 mTouchStartY = 0;
    85                 // Reposition handles to line up with ends of selection
    86                 JSONObject args = new JSONObject();
    87                 try {
    88                     args.put("handleType", mHandleType.toString());
    89                 } catch (Exception e) {
    90                     Log.e(LOGTAG, "Error building JSON arguments for TextSelection:Position");
    91                 }
    92                 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("TextSelection:Position", args.toString()));
    93                 break;
    94             }
    95             case MotionEvent.ACTION_MOVE: {
    96                 move(event.getRawX(), event.getRawY());
    97                 break;
    98             }
    99         }
   100         return true;
   101     }
   103     private void move(float newX, float newY) {
   104         // newX and newY are absolute coordinates, so we need to adjust them to
   105         // account for other views on the screen (such as the URL bar). We also
   106         // need to include the offset amount of the touch location relative to
   107         // the top left of the handle (mTouchStartX and mTouchStartY).
   108         mLeft = newX - mLayerViewX - mTouchStartX;
   109         mTop = newY - mLayerViewY - mTouchStartY;
   111         LayerView layerView = GeckoAppShell.getLayerView();
   112         if (layerView == null) {
   113             Log.e(LOGTAG, "Can't move selection because layerView is null");
   114             return;
   115         }
   116         // Send x coordinate on the right side of the start handle, left side of the end handle.
   117         float left = mLeft + adjustLeftForHandle();
   119         PointF geckoPoint = new PointF(left, mTop);
   120         geckoPoint = layerView.convertViewPointToLayerPoint(geckoPoint);
   122         JSONObject args = new JSONObject();
   123         try {
   124             args.put("handleType", mHandleType.toString());
   125             args.put("x", (int) geckoPoint.x);
   126             args.put("y", (int) geckoPoint.y);
   127         } catch (Exception e) {
   128             Log.e(LOGTAG, "Error building JSON arguments for TextSelection:Move");
   129         }
   130         GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("TextSelection:Move", args.toString()));
   132         // If we're positioning a cursor, don't move the handle here. Gecko
   133         // will tell us the position of the caret, so we set the handle
   134         // position then. This allows us to lock the handle to wherever the
   135         // caret appears.
   136         if (!mHandleType.equals(HandleType.MIDDLE)) {
   137             setLayoutPosition();
   138         }
   139     }
   141     void positionFromGecko(int left, int top, boolean rtl) {
   142         LayerView layerView = GeckoAppShell.getLayerView();
   143         if (layerView == null) {
   144             Log.e(LOGTAG, "Can't position handle because layerView is null");
   145             return;
   146         }
   148         mGeckoPoint = new PointF(left, top);
   149         if (mIsRTL != rtl) {
   150             mIsRTL = rtl;
   151             setImageLevel(mIsRTL ? IMAGE_LEVEL_RTL : IMAGE_LEVEL_LTR);
   152         }
   154         ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
   155         PointF offset = metrics.getMarginOffset();
   156         repositionWithViewport(metrics.viewportRectLeft - offset.x, metrics.viewportRectTop - offset.y, metrics.zoomFactor);
   157     }
   159     void repositionWithViewport(float x, float y, float zoom) {
   160         PointF viewPoint = new PointF((mGeckoPoint.x * zoom) - x,
   161                                       (mGeckoPoint.y * zoom) - y);
   163         mLeft = viewPoint.x - adjustLeftForHandle();
   164         mTop = viewPoint.y;
   166         setLayoutPosition();
   167     }
   169     private float adjustLeftForHandle() {
   170         if (mHandleType.equals(HandleType.START))
   171             return mIsRTL ? mShadow : mWidth - mShadow;
   172         else if (mHandleType.equals(HandleType.MIDDLE))
   173             return mWidth / 2;
   174         else
   175             return mIsRTL ? mWidth - mShadow : mShadow;
   176     }
   178     private void setLayoutPosition() {
   179         if (mLayoutParams == null) {
   180             mLayoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
   181             // Set negative right/bottom margins so that the handles can be dragged outside of
   182             // the content area (if they are dragged to the left/top, the dyanmic margins set
   183             // below will take care of that).
   184             mLayoutParams.rightMargin = 0 - mWidth;
   185             mLayoutParams.bottomMargin = 0 - mHeight;
   186         }
   188         mLayoutParams.leftMargin = (int) mLeft;
   189         mLayoutParams.topMargin = (int) mTop;
   190         setLayoutParams(mLayoutParams);
   191     }
   192 }

mercurial