diff options
| -rw-r--r-- | core/java/com/android/internal/view/FloatingActionMode.java | 78 | ||||
| -rw-r--r-- | core/java/com/android/internal/widget/FloatingToolbar.java | 87 |
2 files changed, 91 insertions, 74 deletions
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index ef2fef0e4d68..41628d048752 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -41,13 +41,13 @@ public class FloatingActionMode extends ActionMode { private final ActionMode.Callback2 mCallback; private final MenuBuilder mMenu; private final Rect mContentRect; - private final Rect mContentRectOnWindow; - private final Rect mPreviousContentRectOnWindow; - private final int[] mViewPosition; - private final int[] mPreviousViewPosition; - private final int[] mRootViewPosition; - private final Rect mViewRect; - private final Rect mPreviousViewRect; + private final Rect mContentRectOnScreen; + private final Rect mPreviousContentRectOnScreen; + private final int[] mViewPositionOnScreen; + private final int[] mPreviousViewPositionOnScreen; + private final int[] mRootViewPositionOnScreen; + private final Rect mViewRectOnScreen; + private final Rect mPreviousViewRectOnScreen; private final Rect mScreenRect; private final View mOriginatingView; private final int mBottomAllowance; @@ -77,16 +77,16 @@ public class FloatingActionMode extends ActionMode { MenuItem.SHOW_AS_ACTION_IF_ROOM); setType(ActionMode.TYPE_FLOATING); mContentRect = new Rect(); - mContentRectOnWindow = new Rect(); - mPreviousContentRectOnWindow = new Rect(); - mViewPosition = new int[2]; - mPreviousViewPosition = new int[2]; - mRootViewPosition = new int[2]; - mViewRect = new Rect(); - mPreviousViewRect = new Rect(); + mContentRectOnScreen = new Rect(); + mPreviousContentRectOnScreen = new Rect(); + mViewPositionOnScreen = new int[2]; + mPreviousViewPositionOnScreen = new int[2]; + mRootViewPositionOnScreen = new int[2]; + mViewRectOnScreen = new Rect(); + mPreviousViewRectOnScreen = new Rect(); mScreenRect = new Rect(); mOriginatingView = Preconditions.checkNotNull(originatingView); - mOriginatingView.getLocationInWindow(mViewPosition); + mOriginatingView.getLocationOnScreen(mViewPositionOnScreen); // Allow the content rect to overshoot a little bit beyond the // bottom view bound if necessary. mBottomAllowance = context.getResources() @@ -138,52 +138,53 @@ public class FloatingActionMode extends ActionMode { public void updateViewLocationInWindow() { checkToolbarInitialized(); - mOriginatingView.getLocationInWindow(mViewPosition); - mOriginatingView.getRootView().getLocationInWindow(mRootViewPosition); - mOriginatingView.getGlobalVisibleRect(mViewRect); - mViewRect.offset(mRootViewPosition[0], mRootViewPosition[1]); + mOriginatingView.getLocationOnScreen(mViewPositionOnScreen); + mOriginatingView.getRootView().getLocationOnScreen(mRootViewPositionOnScreen); + mOriginatingView.getGlobalVisibleRect(mViewRectOnScreen); + mViewRectOnScreen.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]); - if (!Arrays.equals(mViewPosition, mPreviousViewPosition) - || !mViewRect.equals(mPreviousViewRect)) { + if (!Arrays.equals(mViewPositionOnScreen, mPreviousViewPositionOnScreen) + || !mViewRectOnScreen.equals(mPreviousViewRectOnScreen)) { repositionToolbar(); - mPreviousViewPosition[0] = mViewPosition[0]; - mPreviousViewPosition[1] = mViewPosition[1]; - mPreviousViewRect.set(mViewRect); + mPreviousViewPositionOnScreen[0] = mViewPositionOnScreen[0]; + mPreviousViewPositionOnScreen[1] = mViewPositionOnScreen[1]; + mPreviousViewRectOnScreen.set(mViewRectOnScreen); } } private void repositionToolbar() { checkToolbarInitialized(); - mContentRectOnWindow.set(mContentRect); - mContentRectOnWindow.offset(mViewPosition[0], mViewPosition[1]); + mContentRectOnScreen.set(mContentRect); + mContentRectOnScreen.offset(mViewPositionOnScreen[0], mViewPositionOnScreen[1]); if (isContentRectWithinBounds()) { mFloatingToolbarVisibilityHelper.setOutOfBounds(false); // Make sure that content rect is not out of the view's visible bounds. - mContentRectOnWindow.set( - Math.max(mContentRectOnWindow.left, mViewRect.left), - Math.max(mContentRectOnWindow.top, mViewRect.top), - Math.min(mContentRectOnWindow.right, mViewRect.right), - Math.min(mContentRectOnWindow.bottom, mViewRect.bottom + mBottomAllowance)); - - if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) { + mContentRectOnScreen.set( + Math.max(mContentRectOnScreen.left, mViewRectOnScreen.left), + Math.max(mContentRectOnScreen.top, mViewRectOnScreen.top), + Math.min(mContentRectOnScreen.right, mViewRectOnScreen.right), + Math.min(mContentRectOnScreen.bottom, + mViewRectOnScreen.bottom + mBottomAllowance)); + + if (!mContentRectOnScreen.equals(mPreviousContentRectOnScreen)) { // Content rect is moving. mOriginatingView.removeCallbacks(mMovingOff); mFloatingToolbarVisibilityHelper.setMoving(true); mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY); - mFloatingToolbar.setContentRect(mContentRectOnWindow); + mFloatingToolbar.setContentRect(mContentRectOnScreen); mFloatingToolbar.updateLayout(); } } else { mFloatingToolbarVisibilityHelper.setOutOfBounds(true); mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); - mContentRectOnWindow.setEmpty(); + mContentRectOnScreen.setEmpty(); } - mPreviousContentRectOnWindow.set(mContentRectOnWindow); + mPreviousContentRectOnScreen.set(mContentRectOnScreen); } private boolean isContentRectWithinBounds() { @@ -193,8 +194,8 @@ public class FloatingActionMode extends ActionMode { mContext.getResources().getDisplayMetrics().widthPixels, mContext.getResources().getDisplayMetrics().heightPixels); - return Rect.intersects(mContentRectOnWindow, mScreenRect) - && Rect.intersects(mContentRectOnWindow, mViewRect); + return Rect.intersects(mContentRectOnScreen, mScreenRect) + && Rect.intersects(mContentRectOnScreen, mViewRectOnScreen); } @Override @@ -269,7 +270,6 @@ public class FloatingActionMode extends ActionMode { mOriginatingView.removeCallbacks(mHideOff); } - /** * A helper for showing/hiding the floating toolbar depending on certain states. */ diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index a6e80345fb8a..b3f688bbbd04 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -285,6 +285,7 @@ public final class FloatingToolbar { private final Context mContext; private final View mParent; + private final int[] mParentPositionOnScreen = new int[2]; private final PopupWindow mPopupWindow; private final ViewGroup mContentContainer; private final int mMarginHorizontal; @@ -337,8 +338,8 @@ public final class FloatingToolbar { } }; - private final Rect mViewPort = new Rect(); - private final Point mCoords = new Point(); + private final Rect mViewPortOnScreen = new Rect(); + private final Point mCoordsOnScreen = new Point(); private final Rect mTmpRect = new Rect(); private final Region mTouchableRegion = new Region(); @@ -428,8 +429,8 @@ public final class FloatingToolbar { * Shows this popup at the specified coordinates. * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. */ - public void show(Rect contentRect) { - Preconditions.checkNotNull(contentRect); + public void show(Rect contentRectOnScreen) { + Preconditions.checkNotNull(contentRectOnScreen); if (isShowing()) { return; @@ -447,9 +448,15 @@ public final class FloatingToolbar { // The "show" animation will make this visible. mContentContainer.setAlpha(0); } - refreshCoordinatesAndOverflowDirection(contentRect); + refreshCoordinatesAndOverflowDirection(contentRectOnScreen); preparePopupContent(); - mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoords.x, mCoords.y); + // We need to specify the offset relative to mParent. + // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can + // specify the popup poision in screen coordinates. + mParent.getLocationOnScreen(mParentPositionOnScreen); + final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0]; + final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1]; + mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, relativeX, relativeY); setTouchableSurfaceInsetsComputer(); runShowAnimation(); } @@ -502,17 +509,23 @@ public final class FloatingToolbar { * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. * This is a no-op if this popup is not showing. */ - public void updateCoordinates(Rect contentRect) { - Preconditions.checkNotNull(contentRect); + public void updateCoordinates(Rect contentRectOnScreen) { + Preconditions.checkNotNull(contentRectOnScreen); if (!isShowing() || !mPopupWindow.isShowing()) { return; } cancelOverflowAnimations(); - refreshCoordinatesAndOverflowDirection(contentRect); + refreshCoordinatesAndOverflowDirection(contentRectOnScreen); preparePopupContent(); - mPopupWindow.update(mCoords.x, mCoords.y, getWidth(), getHeight()); + // We need to specify the offset relative to mParent. + // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can + // specify the popup poision in screen coordinates. + mParent.getLocationOnScreen(mParentPositionOnScreen); + final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0]; + final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1]; + mPopupWindow.update(relativeX, relativeY, getWidth(), getHeight()); } /** @@ -536,47 +549,47 @@ public final class FloatingToolbar { return mContext; } - private void refreshCoordinatesAndOverflowDirection(Rect contentRect) { + private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) { refreshViewPort(); - int x = contentRect.centerX() - getWidth() / 2; + int x = contentRectOnScreen.centerX() - getWidth() / 2; // Update x so that the toolbar isn't rendered behind the nav bar in landscape. - x = Math.max(0, Math.min(x, mViewPort.right - getWidth())); + x = Math.max(0, Math.min(x, mViewPortOnScreen.right - getWidth())); int y; - int availableHeightAboveContent = contentRect.top - mViewPort.top; - int availableHeightBelowContent = mViewPort.bottom - contentRect.bottom; + int availableHeightAboveContent = contentRectOnScreen.top - mViewPortOnScreen.top; + int availableHeightBelowContent = mViewPortOnScreen.bottom - contentRectOnScreen.bottom; if (mOverflowPanel == null) { // There is no overflow. if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()) { // There is enough space at the top of the content. - y = contentRect.top - getToolbarHeightWithVerticalMargin(); + y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin(); } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()) { // There is enough space at the bottom of the content. - y = contentRect.bottom; + y = contentRectOnScreen.bottom; } else if (availableHeightBelowContent >= getEstimatedToolbarHeight(mContext)) { // Just enough space to fit the toolbar with no vertical margins. - y = contentRect.bottom - mMarginVertical; + y = contentRectOnScreen.bottom - mMarginVertical; } else { // Not enough space. Prefer to position as high as possible. y = Math.max( - mViewPort.top, - contentRect.top - getToolbarHeightWithVerticalMargin()); + mViewPortOnScreen.top, + contentRectOnScreen.top - getToolbarHeightWithVerticalMargin()); } } else { // There is an overflow. int margin = 2 * mMarginVertical; int minimumOverflowHeightWithMargin = mOverflowPanel.getMinimumHeight() + margin; - int availableHeightThroughContentDown = - mViewPort.bottom - contentRect.top + getToolbarHeightWithVerticalMargin(); - int availableHeightThroughContentUp = - contentRect.bottom - mViewPort.top + getToolbarHeightWithVerticalMargin(); + int availableHeightThroughContentDown = mViewPortOnScreen.bottom - + contentRectOnScreen.top + getToolbarHeightWithVerticalMargin(); + int availableHeightThroughContentUp = contentRectOnScreen.bottom - + mViewPortOnScreen.top + getToolbarHeightWithVerticalMargin(); if (availableHeightAboveContent >= minimumOverflowHeightWithMargin) { // There is enough space at the top of the content rect for the overflow. // Position above and open upwards. updateOverflowHeight(availableHeightAboveContent - margin); - y = contentRect.top - getHeight(); + y = contentRectOnScreen.top - getHeight(); mOverflowDirection = OVERFLOW_DIRECTION_UP; } else if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin() && availableHeightThroughContentDown >= minimumOverflowHeightWithMargin) { @@ -584,33 +597,34 @@ public final class FloatingToolbar { // but not the overflow. // Position above but open downwards. updateOverflowHeight(availableHeightThroughContentDown - margin); - y = contentRect.top - getToolbarHeightWithVerticalMargin(); + y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin(); mOverflowDirection = OVERFLOW_DIRECTION_DOWN; } else if (availableHeightBelowContent >= minimumOverflowHeightWithMargin) { // There is enough space at the bottom of the content rect for the overflow. // Position below and open downwards. updateOverflowHeight(availableHeightBelowContent - margin); - y = contentRect.bottom; + y = contentRectOnScreen.bottom; mOverflowDirection = OVERFLOW_DIRECTION_DOWN; } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin() - && mViewPort.height() >= minimumOverflowHeightWithMargin) { + && mViewPortOnScreen.height() >= minimumOverflowHeightWithMargin) { // There is enough space at the bottom of the content rect for the main panel // but not the overflow. // Position below but open upwards. updateOverflowHeight(availableHeightThroughContentUp - margin); - y = contentRect.bottom + getToolbarHeightWithVerticalMargin() - getHeight(); + y = contentRectOnScreen.bottom + getToolbarHeightWithVerticalMargin() - + getHeight(); mOverflowDirection = OVERFLOW_DIRECTION_UP; } else { // Not enough space. // Position at the top of the view port and open downwards. - updateOverflowHeight(mViewPort.height() - margin); - y = mViewPort.top; + updateOverflowHeight(mViewPortOnScreen.height() - margin); + y = mViewPortOnScreen.top; mOverflowDirection = OVERFLOW_DIRECTION_DOWN; } mOverflowPanel.setOverflowDirection(mOverflowDirection); } - mCoords.set(x, y); + mCoordsOnScreen.set(x, y); } private int getToolbarHeightWithVerticalMargin() { @@ -913,18 +927,18 @@ public final class FloatingToolbar { private void refreshViewPort() { - mParent.getWindowVisibleDisplayFrame(mViewPort); + mParent.getWindowVisibleDisplayFrame(mViewPortOnScreen); } private boolean viewPortHasChanged() { mParent.getWindowVisibleDisplayFrame(mTmpRect); - return !mTmpRect.equals(mViewPort); + return !mTmpRect.equals(mViewPortOnScreen); } private int getToolbarWidth(int suggestedWidth) { int width = suggestedWidth; refreshViewPort(); - int maximumWidth = mViewPort.width() - 2 * mParent.getResources() + int maximumWidth = mViewPortOnScreen.width() - 2 * mParent.getResources() .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); if (width <= 0) { width = mParent.getResources() @@ -1443,6 +1457,9 @@ public final class FloatingToolbar { private static PopupWindow createPopupWindow(View content) { ViewGroup popupContentHolder = new LinearLayout(content.getContext()); PopupWindow popupWindow = new PopupWindow(popupContentHolder); + // TODO: Use .setLayoutInScreenEnabled(true) instead of .setClippingEnabled(false) + // unless FLAG_LAYOUT_IN_SCREEN has any unintentional side-effects. + popupWindow.setClippingEnabled(false); popupWindow.setWindowLayoutType( WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL); popupWindow.setAnimationStyle(0); |