Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17dce343 authored by Yohei Yukawa's avatar Yohei Yukawa Committed by Android Git Automerger
Browse files

am be27832b: am 12952c79: Merge "Allow FloatingToolbar to be outside of the...

am be27832b: am 12952c79: Merge "Allow FloatingToolbar to be outside of the attached window." into mnc-dev

* commit 'be27832b':
  Allow FloatingToolbar to be outside of the attached window.
parents 16567cf2 be27832b
Loading
Loading
Loading
Loading
+39 −39
Original line number Original line Diff line number Diff line
@@ -41,13 +41,13 @@ public class FloatingActionMode extends ActionMode {
    private final ActionMode.Callback2 mCallback;
    private final ActionMode.Callback2 mCallback;
    private final MenuBuilder mMenu;
    private final MenuBuilder mMenu;
    private final Rect mContentRect;
    private final Rect mContentRect;
    private final Rect mContentRectOnWindow;
    private final Rect mContentRectOnScreen;
    private final Rect mPreviousContentRectOnWindow;
    private final Rect mPreviousContentRectOnScreen;
    private final int[] mViewPosition;
    private final int[] mViewPositionOnScreen;
    private final int[] mPreviousViewPosition;
    private final int[] mPreviousViewPositionOnScreen;
    private final int[] mRootViewPosition;
    private final int[] mRootViewPositionOnScreen;
    private final Rect mViewRect;
    private final Rect mViewRectOnScreen;
    private final Rect mPreviousViewRect;
    private final Rect mPreviousViewRectOnScreen;
    private final Rect mScreenRect;
    private final Rect mScreenRect;
    private final View mOriginatingView;
    private final View mOriginatingView;
    private final int mBottomAllowance;
    private final int mBottomAllowance;
@@ -77,16 +77,16 @@ public class FloatingActionMode extends ActionMode {
                MenuItem.SHOW_AS_ACTION_IF_ROOM);
                MenuItem.SHOW_AS_ACTION_IF_ROOM);
        setType(ActionMode.TYPE_FLOATING);
        setType(ActionMode.TYPE_FLOATING);
        mContentRect = new Rect();
        mContentRect = new Rect();
        mContentRectOnWindow = new Rect();
        mContentRectOnScreen = new Rect();
        mPreviousContentRectOnWindow = new Rect();
        mPreviousContentRectOnScreen = new Rect();
        mViewPosition = new int[2];
        mViewPositionOnScreen = new int[2];
        mPreviousViewPosition = new int[2];
        mPreviousViewPositionOnScreen = new int[2];
        mRootViewPosition = new int[2];
        mRootViewPositionOnScreen = new int[2];
        mViewRect = new Rect();
        mViewRectOnScreen = new Rect();
        mPreviousViewRect = new Rect();
        mPreviousViewRectOnScreen = new Rect();
        mScreenRect = new Rect();
        mScreenRect = new Rect();
        mOriginatingView = Preconditions.checkNotNull(originatingView);
        mOriginatingView = Preconditions.checkNotNull(originatingView);
        mOriginatingView.getLocationInWindow(mViewPosition);
        mOriginatingView.getLocationOnScreen(mViewPositionOnScreen);
        // Allow the content rect to overshoot a little bit beyond the
        // Allow the content rect to overshoot a little bit beyond the
        // bottom view bound if necessary.
        // bottom view bound if necessary.
        mBottomAllowance = context.getResources()
        mBottomAllowance = context.getResources()
@@ -138,52 +138,53 @@ public class FloatingActionMode extends ActionMode {
    public void updateViewLocationInWindow() {
    public void updateViewLocationInWindow() {
        checkToolbarInitialized();
        checkToolbarInitialized();


        mOriginatingView.getLocationInWindow(mViewPosition);
        mOriginatingView.getLocationOnScreen(mViewPositionOnScreen);
        mOriginatingView.getRootView().getLocationInWindow(mRootViewPosition);
        mOriginatingView.getRootView().getLocationOnScreen(mRootViewPositionOnScreen);
        mOriginatingView.getGlobalVisibleRect(mViewRect);
        mOriginatingView.getGlobalVisibleRect(mViewRectOnScreen);
        mViewRect.offset(mRootViewPosition[0], mRootViewPosition[1]);
        mViewRectOnScreen.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]);


        if (!Arrays.equals(mViewPosition, mPreviousViewPosition)
        if (!Arrays.equals(mViewPositionOnScreen, mPreviousViewPositionOnScreen)
                || !mViewRect.equals(mPreviousViewRect)) {
                || !mViewRectOnScreen.equals(mPreviousViewRectOnScreen)) {
            repositionToolbar();
            repositionToolbar();
            mPreviousViewPosition[0] = mViewPosition[0];
            mPreviousViewPositionOnScreen[0] = mViewPositionOnScreen[0];
            mPreviousViewPosition[1] = mViewPosition[1];
            mPreviousViewPositionOnScreen[1] = mViewPositionOnScreen[1];
            mPreviousViewRect.set(mViewRect);
            mPreviousViewRectOnScreen.set(mViewRectOnScreen);
        }
        }
    }
    }


    private void repositionToolbar() {
    private void repositionToolbar() {
        checkToolbarInitialized();
        checkToolbarInitialized();


        mContentRectOnWindow.set(mContentRect);
        mContentRectOnScreen.set(mContentRect);
        mContentRectOnWindow.offset(mViewPosition[0], mViewPosition[1]);
        mContentRectOnScreen.offset(mViewPositionOnScreen[0], mViewPositionOnScreen[1]);


        if (isContentRectWithinBounds()) {
        if (isContentRectWithinBounds()) {
            mFloatingToolbarVisibilityHelper.setOutOfBounds(false);
            mFloatingToolbarVisibilityHelper.setOutOfBounds(false);
            // Make sure that content rect is not out of the view's visible bounds.
            // Make sure that content rect is not out of the view's visible bounds.
            mContentRectOnWindow.set(
            mContentRectOnScreen.set(
                    Math.max(mContentRectOnWindow.left, mViewRect.left),
                    Math.max(mContentRectOnScreen.left, mViewRectOnScreen.left),
                    Math.max(mContentRectOnWindow.top, mViewRect.top),
                    Math.max(mContentRectOnScreen.top, mViewRectOnScreen.top),
                    Math.min(mContentRectOnWindow.right, mViewRect.right),
                    Math.min(mContentRectOnScreen.right, mViewRectOnScreen.right),
                    Math.min(mContentRectOnWindow.bottom, mViewRect.bottom + mBottomAllowance));
                    Math.min(mContentRectOnScreen.bottom,

                            mViewRectOnScreen.bottom + mBottomAllowance));
            if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) {

            if (!mContentRectOnScreen.equals(mPreviousContentRectOnScreen)) {
                // Content rect is moving.
                // Content rect is moving.
                mOriginatingView.removeCallbacks(mMovingOff);
                mOriginatingView.removeCallbacks(mMovingOff);
                mFloatingToolbarVisibilityHelper.setMoving(true);
                mFloatingToolbarVisibilityHelper.setMoving(true);
                mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
                mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
                mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
                mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);


                mFloatingToolbar.setContentRect(mContentRectOnWindow);
                mFloatingToolbar.setContentRect(mContentRectOnScreen);
                mFloatingToolbar.updateLayout();
                mFloatingToolbar.updateLayout();
            }
            }
        } else {
        } else {
            mFloatingToolbarVisibilityHelper.setOutOfBounds(true);
            mFloatingToolbarVisibilityHelper.setOutOfBounds(true);
            mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
            mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
            mContentRectOnWindow.setEmpty();
            mContentRectOnScreen.setEmpty();
        }
        }


        mPreviousContentRectOnWindow.set(mContentRectOnWindow);
        mPreviousContentRectOnScreen.set(mContentRectOnScreen);
    }
    }


    private boolean isContentRectWithinBounds() {
    private boolean isContentRectWithinBounds() {
@@ -193,8 +194,8 @@ public class FloatingActionMode extends ActionMode {
            mContext.getResources().getDisplayMetrics().widthPixels,
            mContext.getResources().getDisplayMetrics().widthPixels,
            mContext.getResources().getDisplayMetrics().heightPixels);
            mContext.getResources().getDisplayMetrics().heightPixels);


        return Rect.intersects(mContentRectOnWindow, mScreenRect)
        return Rect.intersects(mContentRectOnScreen, mScreenRect)
            && Rect.intersects(mContentRectOnWindow, mViewRect);
            && Rect.intersects(mContentRectOnScreen, mViewRectOnScreen);
    }
    }


    @Override
    @Override
@@ -269,7 +270,6 @@ public class FloatingActionMode extends ActionMode {
        mOriginatingView.removeCallbacks(mHideOff);
        mOriginatingView.removeCallbacks(mHideOff);
    }
    }



    /**
    /**
     * A helper for showing/hiding the floating toolbar depending on certain states.
     * A helper for showing/hiding the floating toolbar depending on certain states.
     */
     */
+52 −35
Original line number Original line Diff line number Diff line
@@ -285,6 +285,7 @@ public final class FloatingToolbar {


        private final Context mContext;
        private final Context mContext;
        private final View mParent;
        private final View mParent;
        private final int[] mParentPositionOnScreen = new int[2];
        private final PopupWindow mPopupWindow;
        private final PopupWindow mPopupWindow;
        private final ViewGroup mContentContainer;
        private final ViewGroup mContentContainer;
        private final int mMarginHorizontal;
        private final int mMarginHorizontal;
@@ -337,8 +338,8 @@ public final class FloatingToolbar {
            }
            }
        };
        };


        private final Rect mViewPort = new Rect();
        private final Rect mViewPortOnScreen = new Rect();
        private final Point mCoords = new Point();
        private final Point mCoordsOnScreen = new Point();
        private final Rect mTmpRect = new Rect();
        private final Rect mTmpRect = new Rect();


        private final Region mTouchableRegion = new Region();
        private final Region mTouchableRegion = new Region();
@@ -428,8 +429,8 @@ public final class FloatingToolbar {
         * Shows this popup at the specified coordinates.
         * Shows this popup at the specified coordinates.
         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
         */
         */
        public void show(Rect contentRect) {
        public void show(Rect contentRectOnScreen) {
            Preconditions.checkNotNull(contentRect);
            Preconditions.checkNotNull(contentRectOnScreen);


            if (isShowing()) {
            if (isShowing()) {
                return;
                return;
@@ -447,9 +448,15 @@ public final class FloatingToolbar {
                // The "show" animation will make this visible.
                // The "show" animation will make this visible.
                mContentContainer.setAlpha(0);
                mContentContainer.setAlpha(0);
            }
            }
            refreshCoordinatesAndOverflowDirection(contentRect);
            refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
            preparePopupContent();
            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();
            setTouchableSurfaceInsetsComputer();
            runShowAnimation();
            runShowAnimation();
        }
        }
@@ -502,17 +509,23 @@ public final class FloatingToolbar {
         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
         * 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.
         * This is a no-op if this popup is not showing.
         */
         */
        public void updateCoordinates(Rect contentRect) {
        public void updateCoordinates(Rect contentRectOnScreen) {
            Preconditions.checkNotNull(contentRect);
            Preconditions.checkNotNull(contentRectOnScreen);


            if (!isShowing() || !mPopupWindow.isShowing()) {
            if (!isShowing() || !mPopupWindow.isShowing()) {
                return;
                return;
            }
            }


            cancelOverflowAnimations();
            cancelOverflowAnimations();
            refreshCoordinatesAndOverflowDirection(contentRect);
            refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
            preparePopupContent();
            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;
            return mContext;
        }
        }


        private void refreshCoordinatesAndOverflowDirection(Rect contentRect) {
        private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) {
            refreshViewPort();
            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.
            // 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 y;


            int availableHeightAboveContent = contentRect.top - mViewPort.top;
            int availableHeightAboveContent = contentRectOnScreen.top - mViewPortOnScreen.top;
            int availableHeightBelowContent = mViewPort.bottom - contentRect.bottom;
            int availableHeightBelowContent = mViewPortOnScreen.bottom - contentRectOnScreen.bottom;


            if (mOverflowPanel == null) {  // There is no overflow.
            if (mOverflowPanel == null) {  // There is no overflow.
                if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()) {
                if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()) {
                    // There is enough space at the top of the content.
                    // There is enough space at the top of the content.
                    y = contentRect.top - getToolbarHeightWithVerticalMargin();
                    y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin();
                } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()) {
                } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()) {
                    // There is enough space at the bottom of the content.
                    // There is enough space at the bottom of the content.
                    y = contentRect.bottom;
                    y = contentRectOnScreen.bottom;
                } else if (availableHeightBelowContent >= getEstimatedToolbarHeight(mContext)) {
                } else if (availableHeightBelowContent >= getEstimatedToolbarHeight(mContext)) {
                    // Just enough space to fit the toolbar with no vertical margins.
                    // Just enough space to fit the toolbar with no vertical margins.
                    y = contentRect.bottom - mMarginVertical;
                    y = contentRectOnScreen.bottom - mMarginVertical;
                } else {
                } else {
                    // Not enough space. Prefer to position as high as possible.
                    // Not enough space. Prefer to position as high as possible.
                    y = Math.max(
                    y = Math.max(
                            mViewPort.top,
                            mViewPortOnScreen.top,
                            contentRect.top - getToolbarHeightWithVerticalMargin());
                            contentRectOnScreen.top - getToolbarHeightWithVerticalMargin());
                }
                }
            } else {  // There is an overflow.
            } else {  // There is an overflow.
                int margin = 2 * mMarginVertical;
                int margin = 2 * mMarginVertical;
                int minimumOverflowHeightWithMargin = mOverflowPanel.getMinimumHeight() + margin;
                int minimumOverflowHeightWithMargin = mOverflowPanel.getMinimumHeight() + margin;
                int availableHeightThroughContentDown =
                int availableHeightThroughContentDown = mViewPortOnScreen.bottom -
                        mViewPort.bottom - contentRect.top + getToolbarHeightWithVerticalMargin();
                        contentRectOnScreen.top + getToolbarHeightWithVerticalMargin();
                int availableHeightThroughContentUp =
                int availableHeightThroughContentUp = contentRectOnScreen.bottom -
                        contentRect.bottom - mViewPort.top + getToolbarHeightWithVerticalMargin();
                        mViewPortOnScreen.top + getToolbarHeightWithVerticalMargin();


                if (availableHeightAboveContent >= minimumOverflowHeightWithMargin) {
                if (availableHeightAboveContent >= minimumOverflowHeightWithMargin) {
                    // There is enough space at the top of the content rect for the overflow.
                    // There is enough space at the top of the content rect for the overflow.
                    // Position above and open upwards.
                    // Position above and open upwards.
                    updateOverflowHeight(availableHeightAboveContent - margin);
                    updateOverflowHeight(availableHeightAboveContent - margin);
                    y = contentRect.top - getHeight();
                    y = contentRectOnScreen.top - getHeight();
                    mOverflowDirection = OVERFLOW_DIRECTION_UP;
                    mOverflowDirection = OVERFLOW_DIRECTION_UP;
                } else if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()
                } else if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()
                        && availableHeightThroughContentDown >= minimumOverflowHeightWithMargin) {
                        && availableHeightThroughContentDown >= minimumOverflowHeightWithMargin) {
@@ -584,33 +597,34 @@ public final class FloatingToolbar {
                    // but not the overflow.
                    // but not the overflow.
                    // Position above but open downwards.
                    // Position above but open downwards.
                    updateOverflowHeight(availableHeightThroughContentDown - margin);
                    updateOverflowHeight(availableHeightThroughContentDown - margin);
                    y = contentRect.top - getToolbarHeightWithVerticalMargin();
                    y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin();
                    mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
                    mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
                } else if (availableHeightBelowContent >= minimumOverflowHeightWithMargin) {
                } else if (availableHeightBelowContent >= minimumOverflowHeightWithMargin) {
                    // There is enough space at the bottom of the content rect for the overflow.
                    // There is enough space at the bottom of the content rect for the overflow.
                    // Position below and open downwards.
                    // Position below and open downwards.
                    updateOverflowHeight(availableHeightBelowContent - margin);
                    updateOverflowHeight(availableHeightBelowContent - margin);
                    y = contentRect.bottom;
                    y = contentRectOnScreen.bottom;
                    mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
                    mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
                } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()
                } 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
                    // There is enough space at the bottom of the content rect for the main panel
                    // but not the overflow.
                    // but not the overflow.
                    // Position below but open upwards.
                    // Position below but open upwards.
                    updateOverflowHeight(availableHeightThroughContentUp - margin);
                    updateOverflowHeight(availableHeightThroughContentUp - margin);
                    y = contentRect.bottom + getToolbarHeightWithVerticalMargin() - getHeight();
                    y = contentRectOnScreen.bottom + getToolbarHeightWithVerticalMargin() -
                            getHeight();
                    mOverflowDirection = OVERFLOW_DIRECTION_UP;
                    mOverflowDirection = OVERFLOW_DIRECTION_UP;
                } else {
                } else {
                    // Not enough space.
                    // Not enough space.
                    // Position at the top of the view port and open downwards.
                    // Position at the top of the view port and open downwards.
                    updateOverflowHeight(mViewPort.height() - margin);
                    updateOverflowHeight(mViewPortOnScreen.height() - margin);
                    y = mViewPort.top;
                    y = mViewPortOnScreen.top;
                    mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
                    mOverflowDirection = OVERFLOW_DIRECTION_DOWN;
                }
                }
                mOverflowPanel.setOverflowDirection(mOverflowDirection);
                mOverflowPanel.setOverflowDirection(mOverflowDirection);
            }
            }


            mCoords.set(x, y);
            mCoordsOnScreen.set(x, y);
        }
        }


        private int getToolbarHeightWithVerticalMargin() {
        private int getToolbarHeightWithVerticalMargin() {
@@ -913,18 +927,18 @@ public final class FloatingToolbar {




        private void refreshViewPort() {
        private void refreshViewPort() {
            mParent.getWindowVisibleDisplayFrame(mViewPort);
            mParent.getWindowVisibleDisplayFrame(mViewPortOnScreen);
        }
        }


        private boolean viewPortHasChanged() {
        private boolean viewPortHasChanged() {
            mParent.getWindowVisibleDisplayFrame(mTmpRect);
            mParent.getWindowVisibleDisplayFrame(mTmpRect);
            return !mTmpRect.equals(mViewPort);
            return !mTmpRect.equals(mViewPortOnScreen);
        }
        }


        private int getToolbarWidth(int suggestedWidth) {
        private int getToolbarWidth(int suggestedWidth) {
            int width = suggestedWidth;
            int width = suggestedWidth;
            refreshViewPort();
            refreshViewPort();
            int maximumWidth = mViewPort.width() - 2 * mParent.getResources()
            int maximumWidth = mViewPortOnScreen.width() - 2 * mParent.getResources()
                    .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
                    .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
            if (width <= 0) {
            if (width <= 0) {
                width = mParent.getResources()
                width = mParent.getResources()
@@ -1443,6 +1457,9 @@ public final class FloatingToolbar {
    private static PopupWindow createPopupWindow(View content) {
    private static PopupWindow createPopupWindow(View content) {
        ViewGroup popupContentHolder = new LinearLayout(content.getContext());
        ViewGroup popupContentHolder = new LinearLayout(content.getContext());
        PopupWindow popupWindow = new PopupWindow(popupContentHolder);
        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(
        popupWindow.setWindowLayoutType(
                WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
                WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
        popupWindow.setAnimationStyle(0);
        popupWindow.setAnimationStyle(0);