Loading core/java/com/android/internal/view/FloatingActionMode.java +39 −39 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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() Loading Loading @@ -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() { Loading @@ -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 Loading Loading @@ -269,7 +270,6 @@ public class FloatingActionMode extends ActionMode { mOriginatingView.removeCallbacks(mHideOff); } /** * A helper for showing/hiding the floating toolbar depending on certain states. */ Loading core/java/com/android/internal/widget/FloatingToolbar.java +52 −35 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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; Loading @@ -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(); } Loading Loading @@ -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()); } /** Loading @@ -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) { Loading @@ -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() { Loading Loading @@ -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() Loading Loading @@ -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); Loading Loading
core/java/com/android/internal/view/FloatingActionMode.java +39 −39 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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() Loading Loading @@ -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() { Loading @@ -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 Loading Loading @@ -269,7 +270,6 @@ public class FloatingActionMode extends ActionMode { mOriginatingView.removeCallbacks(mHideOff); } /** * A helper for showing/hiding the floating toolbar depending on certain states. */ Loading
core/java/com/android/internal/widget/FloatingToolbar.java +52 −35 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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; Loading @@ -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(); } Loading Loading @@ -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()); } /** Loading @@ -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) { Loading @@ -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() { Loading Loading @@ -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() Loading Loading @@ -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); Loading