This source file includes following definitions.
- setOrientation
- onMeasure
- updateParentPosition
- getContainerPositionX
- getContainerPositionY
- onPositionChanged
- showContainer
- show
- hide
- isShowing
- isPositionVisible
- moveTo
- onDraw
- onTouchEvent
- isDragging
- getPositionX
- getPositionY
- updatePosition
- positionAt
- getAdjustedPositionX
- getAdjustedPositionY
- getRootViewRelativePositionX
- getRootViewRelativePositionY
- getLineAdjustedPositionY
- getDrawable
- updateAlpha
- beginFadeIn
- showPastePopupWindow
package org.chromium.content.browser.input;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.view.animation.AnimationUtils;
import android.widget.PopupWindow;
import com.google.common.annotations.VisibleForTesting;
import org.chromium.content.browser.PositionObserver;
public class HandleView extends View {
private static final float FADE_DURATION = 200.f;
private Drawable mDrawable;
private final PopupWindow mContainer;
private int mPositionX;
private int mPositionY;
private int mParentPositionX;
private int mParentPositionY;
private float mHotspotX;
private float mHotspotY;
private final CursorController mController;
private boolean mIsDragging;
private float mTouchToWindowOffsetX;
private float mTouchToWindowOffsetY;
private final int mLineOffsetY;
private float mDownPositionX, mDownPositionY;
private long mTouchTimer;
private boolean mIsInsertionHandle = false;
private float mAlpha;
private long mFadeStartTime;
private final View mParent;
private InsertionHandleController.PastePopupMenu mPastePopupWindow;
private final int mTextSelectHandleLeftRes;
private final int mTextSelectHandleRightRes;
private final int mTextSelectHandleRes;
private Drawable mSelectHandleLeft;
private Drawable mSelectHandleRight;
private Drawable mSelectHandleCenter;
private final Rect mTempRect = new Rect();
static final int LEFT = 0;
static final int CENTER = 1;
static final int RIGHT = 2;
private final PositionObserver mParentPositionObserver;
private final PositionObserver.Listener mParentPositionListener;
private static final float LINE_OFFSET_Y_DIP = 5.0f;
private static final int[] TEXT_VIEW_HANDLE_ATTRS = {
android.R.attr.textSelectHandleLeft,
android.R.attr.textSelectHandle,
android.R.attr.textSelectHandleRight,
};
HandleView(CursorController controller, int pos, View parent,
PositionObserver parentPositionObserver) {
super(parent.getContext());
Context context = parent.getContext();
mParent = parent;
mController = controller;
mContainer = new PopupWindow(context, null, android.R.attr.textSelectHandleWindowStyle);
mContainer.setSplitTouchEnabled(true);
mContainer.setClippingEnabled(false);
TypedArray a = context.obtainStyledAttributes(TEXT_VIEW_HANDLE_ATTRS);
mTextSelectHandleLeftRes = a.getResourceId(a.getIndex(LEFT), 0);
mTextSelectHandleRes = a.getResourceId(a.getIndex(CENTER), 0);
mTextSelectHandleRightRes = a.getResourceId(a.getIndex(RIGHT), 0);
a.recycle();
setOrientation(pos);
mLineOffsetY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
LINE_OFFSET_Y_DIP, context.getResources().getDisplayMetrics());
mAlpha = 1.f;
mParentPositionListener = new PositionObserver.Listener() {
@Override
public void onPositionChanged(int x, int y) {
updateParentPosition(x, y);
}
};
mParentPositionObserver = parentPositionObserver;
}
void setOrientation(int pos) {
int handleWidth;
switch (pos) {
case LEFT: {
if (mSelectHandleLeft == null) {
mSelectHandleLeft = getContext().getResources().getDrawable(
mTextSelectHandleLeftRes);
}
mDrawable = mSelectHandleLeft;
handleWidth = mDrawable.getIntrinsicWidth();
mHotspotX = (handleWidth * 3) / 4f;
break;
}
case RIGHT: {
if (mSelectHandleRight == null) {
mSelectHandleRight = getContext().getResources().getDrawable(
mTextSelectHandleRightRes);
}
mDrawable = mSelectHandleRight;
handleWidth = mDrawable.getIntrinsicWidth();
mHotspotX = handleWidth / 4f;
break;
}
case CENTER:
default: {
if (mSelectHandleCenter == null) {
mSelectHandleCenter = getContext().getResources().getDrawable(
mTextSelectHandleRes);
}
mDrawable = mSelectHandleCenter;
handleWidth = mDrawable.getIntrinsicWidth();
mHotspotX = handleWidth / 2f;
mIsInsertionHandle = true;
break;
}
}
mHotspotY = 0;
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mDrawable.getIntrinsicWidth(),
mDrawable.getIntrinsicHeight());
}
private void updateParentPosition(int parentPositionX, int parentPositionY) {
if (mPastePopupWindow != null) mPastePopupWindow.hide();
mTouchToWindowOffsetX += parentPositionX - mParentPositionX;
mTouchToWindowOffsetY += parentPositionY - mParentPositionY;
mParentPositionX = parentPositionX;
mParentPositionY = parentPositionY;
onPositionChanged();
}
private int getContainerPositionX() {
return mParentPositionX + mPositionX;
}
private int getContainerPositionY() {
return mParentPositionY + mPositionY;
}
private void onPositionChanged() {
mContainer.update(getContainerPositionX(), getContainerPositionY(),
getRight() - getLeft(), getBottom() - getTop());
}
private void showContainer() {
mContainer.showAtLocation(mParent, 0, getContainerPositionX(), getContainerPositionY());
}
void show() {
updateParentPosition(mParentPositionObserver.getPositionX(),
mParentPositionObserver.getPositionY());
if (!isPositionVisible()) {
hide();
return;
}
mParentPositionObserver.addListener(mParentPositionListener);
mContainer.setContentView(this);
showContainer();
if (mPastePopupWindow != null) {
mPastePopupWindow.hide();
}
}
void hide() {
mIsDragging = false;
mContainer.dismiss();
mParentPositionObserver.removeListener(mParentPositionListener);
if (mPastePopupWindow != null) {
mPastePopupWindow.hide();
}
}
boolean isShowing() {
return mContainer.isShowing();
}
@VisibleForTesting
boolean isPositionVisible() {
if (mIsDragging) {
return true;
}
final Rect clip = mTempRect;
clip.left = 0;
clip.top = 0;
clip.right = mParent.getWidth();
clip.bottom = mParent.getHeight();
final ViewParent parent = mParent.getParent();
if (parent == null || !parent.getChildVisibleRect(mParent, clip, null)) {
return false;
}
final int posX = getContainerPositionX() + (int) mHotspotX;
final int posY = getContainerPositionY() + (int) mHotspotY;
boolean result = posX >= clip.left && posX <= clip.right &&
posY >= clip.top && posY <= clip.bottom;
final Rect clippingRect = mController.getVisibleClippingRectangle();
if (result && clippingRect != null) {
return clippingRect.contains(getAdjustedPositionX(), getAdjustedPositionY());
}
return result;
}
void moveTo(int x, int y) {
int previousPositionX = mPositionX;
int previousPositionY = mPositionY;
mPositionX = x;
mPositionY = y;
if (isPositionVisible()) {
if (mContainer.isShowing()) {
onPositionChanged();
if (mPastePopupWindow != null &&
(previousPositionX != mPositionX || previousPositionY != mPositionY)) {
mPastePopupWindow.hide();
}
} else {
show();
}
if (mIsDragging) {
if (mPastePopupWindow != null) {
mPastePopupWindow.hide();
}
}
} else {
hide();
}
}
@Override
protected void onDraw(Canvas c) {
updateAlpha();
mDrawable.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop());
mDrawable.draw(c);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
mDownPositionX = ev.getRawX();
mDownPositionY = ev.getRawY();
mTouchToWindowOffsetX = mDownPositionX - mPositionX;
mTouchToWindowOffsetY = mDownPositionY - mPositionY;
mIsDragging = true;
mController.beforeStartUpdatingPosition(this);
mTouchTimer = SystemClock.uptimeMillis();
break;
}
case MotionEvent.ACTION_MOVE: {
updatePosition(ev.getRawX(), ev.getRawY());
break;
}
case MotionEvent.ACTION_UP:
if (mIsInsertionHandle) {
long delay = SystemClock.uptimeMillis() - mTouchTimer;
if (delay < ViewConfiguration.getTapTimeout()) {
if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) {
mPastePopupWindow.hide();
} else {
showPastePopupWindow();
}
}
}
mIsDragging = false;
break;
case MotionEvent.ACTION_CANCEL:
mIsDragging = false;
break;
default:
return false;
}
return true;
}
boolean isDragging() {
return mIsDragging;
}
int getPositionX() {
return mPositionX;
}
int getPositionY() {
return mPositionY;
}
private void updatePosition(float rawX, float rawY) {
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
final float newPosY = rawY - mTouchToWindowOffsetY + mHotspotY - mLineOffsetY;
mController.updatePosition(this, Math.round(newPosX), Math.round(newPosY));
}
void positionAt(int x, int y) {
moveTo(x - Math.round(mHotspotX), y - Math.round(mHotspotY));
}
int getAdjustedPositionX() {
return mPositionX + Math.round(mHotspotX);
}
int getAdjustedPositionY() {
return mPositionY + Math.round(mHotspotY);
}
int getRootViewRelativePositionX() {
return getContainerPositionX() + Math.round(mHotspotX);
}
int getRootViewRelativePositionY() {
return getContainerPositionY() + Math.round(mHotspotY);
}
int getLineAdjustedPositionY() {
return (int) (mPositionY + mHotspotY - mLineOffsetY);
}
Drawable getDrawable() {
return mDrawable;
}
private void updateAlpha() {
if (mAlpha == 1.f) return;
mAlpha = Math.min(1.f,
(AnimationUtils.currentAnimationTimeMillis() - mFadeStartTime) / FADE_DURATION);
mDrawable.setAlpha((int) (255 * mAlpha));
invalidate();
}
void beginFadeIn() {
if (getVisibility() == VISIBLE) return;
mAlpha = 0.f;
mFadeStartTime = AnimationUtils.currentAnimationTimeMillis();
setVisibility(VISIBLE);
}
void showPastePopupWindow() {
InsertionHandleController ihc = (InsertionHandleController) mController;
if (mIsInsertionHandle && ihc.canPaste()) {
if (mPastePopupWindow == null) {
mPastePopupWindow = ihc.new PastePopupMenu();
}
mPastePopupWindow.show();
}
}
}