Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(935)

Unified Diff: content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java

Issue 2263043002: android_webview: Let AwContents manage TouchHandleDrawable (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix build Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/public/android/BUILD.gn ('k') | content/public/browser/android/synchronous_compositor_client.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java b/content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java
deleted file mode 100644
index dce0644ca968d5776a59fb724a9aae67b72a5d2a..0000000000000000000000000000000000000000
--- a/content/public/android/java/src/org/chromium/content/browser/input/PopupTouchHandleDrawable.java
+++ /dev/null
@@ -1,518 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.content.browser.input;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.SystemClock;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.animation.AnimationUtils;
-import android.widget.PopupWindow;
-
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-import org.chromium.content.browser.ContainerViewObserver;
-import org.chromium.content.browser.ContentViewCore;
-import org.chromium.content.browser.PositionObserver;
-import org.chromium.content.browser.ViewPositionObserver;
-import org.chromium.content_public.browser.GestureStateListener;
-import org.chromium.ui.touch_selection.TouchHandleOrientation;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-/**
- * View that displays a selection or insertion handle for text editing.
- *
- * While a HandleView is logically a child of some other view, it does not exist in that View's
- * hierarchy.
- *
- */
-@JNINamespace("content")
-public class PopupTouchHandleDrawable extends View {
- private final PopupWindow mContainer;
- private final PositionObserver.Listener mParentPositionListener;
- private final ContainerViewObserver mParentViewObserver;
- private ContentViewCore mContentViewCore;
- private PositionObserver mParentPositionObserver;
- private Drawable mDrawable;
-
- // The position of the handle relative to the parent view.
- private int mPositionX;
- private int mPositionY;
-
- // The position of the parent relative to the application's root view.
- private int mParentPositionX;
- private int mParentPositionY;
-
- // The mirror values based on which the handles are inverted about X and Y axes.
- private boolean mMirrorHorizontal;
- private boolean mMirrorVertical;
-
- private float mAlpha;
-
- private final int[] mTempScreenCoords = new int[2];
-
- private int mOrientation = TouchHandleOrientation.UNDEFINED;
-
- // Length of the delay before fading in after the last page movement.
- private static final int MOVING_FADE_IN_DELAY_MS = 300;
- private static final int FADE_IN_DURATION_MS = 200;
- private Runnable mDeferredHandleFadeInRunnable;
- private long mFadeStartTime;
- private Runnable mTemporarilyHiddenExpiredRunnable;
- private long mTemporarilyHiddenExpireTime;
- private boolean mVisible;
- private boolean mScrolling;
- private boolean mFocused;
- private boolean mTemporarilyHidden;
- private boolean mAttachedToWindow;
- // This should be set only from onVisibilityInputChanged.
- private boolean mWasShowingAllowed;
-
- // Gesture accounting for handle hiding while scrolling.
- private final GestureStateListener mGestureStateListener;
-
- // There are no guarantees that the side effects of setting the position of
- // the PopupWindow and the visibility of its content View will be realized
- // in the same frame. Thus, to ensure the PopupWindow is seen in the right
- // location, when the PopupWindow reappears we delay the visibility update
- // by one frame after setting the position.
- private boolean mDelayVisibilityUpdateWAR;
-
- // Deferred runnable to avoid invalidating outside of frame dispatch,
- // in turn avoiding issues with sync barrier insertion.
- private Runnable mInvalidationRunnable;
- private boolean mHasPendingInvalidate;
-
- private PopupTouchHandleDrawable(ContentViewCore contentViewCore) {
- super(contentViewCore.getContainerView().getContext());
- mContentViewCore = contentViewCore;
- mContainer = new PopupWindow(mContentViewCore.getWindowAndroid().getContext().get(),
- null, android.R.attr.textSelectHandleWindowStyle);
- mContainer.setSplitTouchEnabled(true);
- mContainer.setClippingEnabled(false);
-
- // The built-in PopupWindow animation causes jank when transitioning between
- // visibility states. We use a custom fade-in animation when necessary.
- mContainer.setAnimationStyle(0);
-
- // The SUB_PANEL window layout type improves z-ordering with respect to
- // other popup-based elements.
- setWindowLayoutType(mContainer, WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
- mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
- mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
-
- mAlpha = 1.f;
- mVisible = getVisibility() == VISIBLE;
- mFocused = mContentViewCore.getContainerView().hasWindowFocus();
-
- mParentPositionObserver = new ViewPositionObserver(mContentViewCore.getContainerView());
- mParentPositionListener = new PositionObserver.Listener() {
- @Override
- public void onPositionChanged(int x, int y) {
- updateParentPosition(x, y);
- }
- };
- mParentViewObserver = new ContainerViewObserver() {
- @Override
- public void onContainerViewChanged(ViewGroup newContainerView) {
- // If the parent View ever changes, the parent position observer
- // must be updated accordingly.
- mParentPositionObserver.clearListener();
- mParentPositionObserver = new ViewPositionObserver(newContainerView);
- if (mContainer.isShowing()) {
- mParentPositionObserver.addListener(mParentPositionListener);
- }
- }
- };
- mGestureStateListener = new GestureStateListener() {
- @Override
- public void onScrollStarted(int scrollOffsetX, int scrollOffsetY) {
- setIsScrolling(true);
- }
- @Override
- public void onScrollEnded(int scrollOffsetX, int scrollOffsetY) {
- setIsScrolling(false);
- }
- @Override
- public void onFlingStartGesture(int vx, int vy, int scrollOffsetY, int scrollExtentY) {
- // Fling accounting is unreliable in WebView, as the embedder
- // can override onScroll() and suppress fling ticking. At best
- // we have to rely on the scroll offset changing to temporarily
- // and repeatedly keep the handles hidden.
- setIsScrolling(false);
- }
- @Override
- public void onScrollOffsetOrExtentChanged(int scrollOffsetY, int scrollExtentY) {
- temporarilyHide();
- }
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- setIsFocused(hasWindowFocus);
- }
- @Override
- public void onDestroyed() {
- destroy();
- }
- };
- mContentViewCore.addGestureStateListener(mGestureStateListener);
- mContentViewCore.addContainerViewObserver(mParentViewObserver);
- }
-
- private static void setWindowLayoutType(PopupWindow window, int layoutType) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- window.setWindowLayoutType(layoutType);
- return;
- }
-
- try {
- Method setWindowLayoutTypeMethod =
- PopupWindow.class.getMethod("setWindowLayoutType", int.class);
- setWindowLayoutTypeMethod.invoke(window, layoutType);
- } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException
- | RuntimeException e) {
- }
- }
-
- private static Drawable getHandleDrawable(Context context, int orientation) {
- switch (orientation) {
- case TouchHandleOrientation.LEFT: {
- return HandleViewResources.getLeftHandleDrawable(context);
- }
-
- case TouchHandleOrientation.RIGHT: {
- return HandleViewResources.getRightHandleDrawable(context);
- }
-
- case TouchHandleOrientation.CENTER: {
- return HandleViewResources.getCenterHandleDrawable(context);
- }
-
- case TouchHandleOrientation.UNDEFINED:
- default:
- assert false;
- return HandleViewResources.getCenterHandleDrawable(context);
- }
- }
-
- @SuppressLint("ClickableViewAccessibility")
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mContentViewCore == null) return false;
- // Convert from PopupWindow local coordinates to
- // parent view local coordinates prior to forwarding.
- mContentViewCore.getContainerView().getLocationOnScreen(mTempScreenCoords);
- final float offsetX = event.getRawX() - event.getX() - mTempScreenCoords[0];
- final float offsetY = event.getRawY() - event.getY() - mTempScreenCoords[1];
- final MotionEvent offsetEvent = MotionEvent.obtainNoHistory(event);
- offsetEvent.offsetLocation(offsetX, offsetY);
- final boolean handled = mContentViewCore.onTouchHandleEvent(offsetEvent);
- offsetEvent.recycle();
- return handled;
- }
-
- @CalledByNative
- private static PopupTouchHandleDrawable create(ContentViewCore contentViewCore) {
- return new PopupTouchHandleDrawable(contentViewCore);
- }
-
- @CalledByNative
- private void setOrientation(int orientation, boolean mirrorVertical, boolean mirrorHorizontal) {
- assert (orientation >= TouchHandleOrientation.LEFT
- && orientation <= TouchHandleOrientation.UNDEFINED);
-
- final boolean orientationChanged = mOrientation != orientation;
- final boolean mirroringChanged =
- mMirrorHorizontal != mirrorHorizontal || mMirrorVertical != mirrorVertical;
- mOrientation = orientation;
- mMirrorHorizontal = mirrorHorizontal;
- mMirrorVertical = mirrorVertical;
-
- // Create new InvertedDrawable only if orientation has changed.
- // Otherwise, change the mirror values to scale canvas on draw() calls.
- if (orientationChanged) mDrawable = getHandleDrawable(getContext(), mOrientation);
-
- if (mDrawable != null) mDrawable.setAlpha((int) (255 * mAlpha));
-
- if (orientationChanged || mirroringChanged) scheduleInvalidate();
- }
-
- private void updateParentPosition(int parentPositionX, int parentPositionY) {
- if (mParentPositionX == parentPositionX && mParentPositionY == parentPositionY) return;
- mParentPositionX = parentPositionX;
- mParentPositionY = parentPositionY;
- temporarilyHide();
- }
-
- private int getContainerPositionX() {
- return mParentPositionX + mPositionX;
- }
-
- private int getContainerPositionY() {
- return mParentPositionY + mPositionY;
- }
-
- private void updatePosition() {
- mContainer.update(getContainerPositionX(), getContainerPositionY(),
- getRight() - getLeft(), getBottom() - getTop());
- }
-
- private boolean isShowingAllowed() {
- return mAttachedToWindow && mVisible && mFocused && !mScrolling && !mTemporarilyHidden;
- }
-
- private void updateVisibility() {
- int newVisibility = isShowingAllowed() ? VISIBLE : INVISIBLE;
-
- // When regaining visibility, delay the visibility update by one frame
- // to ensure the PopupWindow has first been positioned properly.
- if (newVisibility == VISIBLE && getVisibility() != VISIBLE) {
- if (!mDelayVisibilityUpdateWAR) {
- mDelayVisibilityUpdateWAR = true;
- scheduleInvalidate();
- return;
- }
- }
- mDelayVisibilityUpdateWAR = false;
-
- setVisibility(newVisibility);
- }
-
- private void setIsScrolling(boolean scrolling) {
- if (mScrolling == scrolling) return;
- mScrolling = scrolling;
- onVisibilityInputChanged();
- }
-
- private void setIsFocused(boolean focused) {
- if (mFocused == focused) return;
- mFocused = focused;
- onVisibilityInputChanged();
- }
-
- private void setTemporarilyHidden(boolean hidden) {
- if (mTemporarilyHidden == hidden) return;
-
- mTemporarilyHidden = hidden;
- if (mTemporarilyHidden) {
- if (mTemporarilyHiddenExpiredRunnable == null) {
- mTemporarilyHiddenExpiredRunnable = new Runnable() {
- @Override
- public void run() {
- setTemporarilyHidden(false);
- }
- };
- }
- removeCallbacks(mTemporarilyHiddenExpiredRunnable);
- long now = SystemClock.uptimeMillis();
- long delay = Math.max(0, mTemporarilyHiddenExpireTime - now);
- postDelayed(mTemporarilyHiddenExpiredRunnable, delay);
- } else if (mTemporarilyHiddenExpiredRunnable != null) {
- removeCallbacks(mTemporarilyHiddenExpiredRunnable);
- }
- onVisibilityInputChanged();
- }
-
- private void onVisibilityInputChanged() {
- if (!mContainer.isShowing()) return;
- boolean allowed = isShowingAllowed();
- if (mWasShowingAllowed == allowed) return;
- mWasShowingAllowed = allowed;
- cancelFadeIn();
- if (allowed) {
- if (mDeferredHandleFadeInRunnable == null) {
- mDeferredHandleFadeInRunnable = new Runnable() {
- @Override
- public void run() {
- beginFadeIn();
- }
- };
- }
- postOnAnimation(mDeferredHandleFadeInRunnable);
- } else {
- updateVisibility();
- }
- }
-
- private void updateAlpha() {
- if (mAlpha == 1.f) return;
- long currentTimeMillis = AnimationUtils.currentAnimationTimeMillis();
- mAlpha = Math.min(1.f, (float) (currentTimeMillis - mFadeStartTime) / FADE_IN_DURATION_MS);
- mDrawable.setAlpha((int) (255 * mAlpha));
- scheduleInvalidate();
- }
-
- private void temporarilyHide() {
- if (!mContainer.isShowing()) return;
- mTemporarilyHiddenExpireTime = SystemClock.uptimeMillis() + MOVING_FADE_IN_DELAY_MS;
- setTemporarilyHidden(true);
- }
-
- private void doInvalidate() {
- if (!mContainer.isShowing()) return;
- updateVisibility();
- updatePosition();
- invalidate();
- }
-
- private void scheduleInvalidate() {
- if (mInvalidationRunnable == null) {
- mInvalidationRunnable = new Runnable() {
- @Override
- public void run() {
- mHasPendingInvalidate = false;
- doInvalidate();
- }
- };
- }
-
- if (mHasPendingInvalidate) return;
- mHasPendingInvalidate = true;
- postOnAnimation(mInvalidationRunnable);
- }
-
- private void cancelFadeIn() {
- if (mDeferredHandleFadeInRunnable == null) return;
- removeCallbacks(mDeferredHandleFadeInRunnable);
- }
-
- private void beginFadeIn() {
- if (getVisibility() == VISIBLE) return;
- mAlpha = 0.f;
- mFadeStartTime = AnimationUtils.currentAnimationTimeMillis();
- doInvalidate();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mDrawable == null) {
- setMeasuredDimension(0, 0);
- return;
- }
- setMeasuredDimension(mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
- }
-
- @Override
- protected void onDraw(Canvas c) {
- if (mDrawable == null) return;
- final boolean needsMirror = mMirrorHorizontal || mMirrorVertical;
- if (needsMirror) {
- c.save();
- float scaleX = mMirrorHorizontal ? -1.f : 1.f;
- float scaleY = mMirrorVertical ? -1.f : 1.f;
- c.scale(scaleX, scaleY, getWidth() / 2.0f, getHeight() / 2.0f);
- }
- updateAlpha();
- mDrawable.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop());
- mDrawable.draw(c);
- if (needsMirror) c.restore();
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mAttachedToWindow = true;
- onVisibilityInputChanged();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mAttachedToWindow = false;
- onVisibilityInputChanged();
- }
-
- @CalledByNative
- private void destroy() {
- if (mContentViewCore == null) return;
- hide();
- mContentViewCore.removeGestureStateListener(mGestureStateListener);
- mContentViewCore.removeContainerViewObserver(mParentViewObserver);
- mContentViewCore = null;
- }
-
- @CalledByNative
- private void show() {
- if (mContentViewCore == null) return;
- if (mContainer.isShowing()) return;
-
- // While hidden, the parent position may have become stale. It must be updated before
- // checking isPositionVisible().
- updateParentPosition(mParentPositionObserver.getPositionX(),
- mParentPositionObserver.getPositionY());
- mParentPositionObserver.addListener(mParentPositionListener);
- mContainer.setContentView(this);
- try {
- mContainer.showAtLocation(mContentViewCore.getContainerView(), 0,
- getContainerPositionX(), getContainerPositionY());
- } catch (WindowManager.BadTokenException e) {
- hide();
- }
- }
-
- @CalledByNative
- private void hide() {
- mTemporarilyHiddenExpireTime = 0;
- setTemporarilyHidden(false);
- mAlpha = 1.0f;
- if (mContainer.isShowing()) {
- try {
- mContainer.dismiss();
- } catch (IllegalArgumentException e) {
- // Intentionally swallowed due to bad Android implemention. See crbug.com/633224.
- }
- }
- mParentPositionObserver.clearListener();
- }
-
- @CalledByNative
- private void setOrigin(float originX, float originY) {
- if (mPositionX == originX && mPositionY == originY) return;
- mPositionX = (int) originX;
- mPositionY = (int) originY;
- if (getVisibility() == VISIBLE) scheduleInvalidate();
- }
-
- @CalledByNative
- private void setVisible(boolean visible) {
- if (mVisible == visible) return;
- mVisible = visible;
- onVisibilityInputChanged();
- }
-
- @CalledByNative
- private int getPositionX() {
- return mPositionX;
- }
-
- @CalledByNative
- private float getHandleHorizontalPaddingRatio() {
- return HandleViewResources.getHandleHorizontalPaddingRatio();
- }
-
- @CalledByNative
- private int getPositionY() {
- return mPositionY;
- }
-
- @CalledByNative
- private int getVisibleWidth() {
- if (mDrawable == null) return 0;
- return mDrawable.getIntrinsicWidth();
- }
-
- @CalledByNative
- private int getVisibleHeight() {
- if (mDrawable == null) return 0;
- return mDrawable.getIntrinsicHeight();
- }
-}
« no previous file with comments | « content/public/android/BUILD.gn ('k') | content/public/browser/android/synchronous_compositor_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698