Loading core/java/com/android/internal/widget/FloatingToolbar.java +87 −60 Original line number Diff line number Diff line Loading @@ -79,7 +79,6 @@ public final class FloatingToolbar { private final FloatingToolbarPopup mPopup; private final Rect mContentRect = new Rect(); private final Point mCoordinates = new Point(); private Menu mMenu; private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>(); Loading @@ -87,7 +86,6 @@ public final class FloatingToolbar { private int mSuggestedWidth; private boolean mWidthChanged = true; private int mOverflowDirection; /** * Initializes a floating toolbar. Loading Loading @@ -157,11 +155,9 @@ public final class FloatingToolbar { mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); mShowingTitles = getMenuItemTitles(menuItems); } refreshCoordinates(); mPopup.setOverflowDirection(mOverflowDirection); mPopup.updateCoordinates(mCoordinates.x, mCoordinates.y); mPopup.updateCoordinates(mContentRect); if (!mPopup.isShowing()) { mPopup.show(mCoordinates.x, mCoordinates.y); mPopup.show(mContentRect); } mWidthChanged = false; return this; Loading Loading @@ -208,25 +204,6 @@ public final class FloatingToolbar { return mPopup.isHidden(); } /** * Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}. */ private void refreshCoordinates() { int x = mContentRect.centerX() - mPopup.getWidth() / 2; int y; if (mContentRect.top > mPopup.getHeight()) { y = mContentRect.top - mPopup.getHeight(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP; } else if (mContentRect.top > mPopup.getToolbarHeightWithVerticalMargin()) { y = mContentRect.top - mPopup.getToolbarHeightWithVerticalMargin(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } else { y = mContentRect.bottom; mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } mCoordinates.set(x, y); } /** * Returns true if this floating toolbar is currently showing the specified menu items. */ Loading Loading @@ -345,6 +322,8 @@ public final class FloatingToolbar { } }; private final Point mCoords = new Point(); private final Region mTouchableRegion = new Region(); private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = new ViewTreeObserver.OnComputeInternalInsetsListener() { Loading Loading @@ -404,6 +383,8 @@ public final class FloatingToolbar { */ public void layoutMenuItems(List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener, int suggestedWidth) { Preconditions.checkNotNull(menuItems); mContentContainer.removeAllViews(); if (mMainPanel == null) { mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow); Loading @@ -426,7 +407,9 @@ 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(int x, int y) { public void show(Rect contentRect) { Preconditions.checkNotNull(contentRect); if (isShowing()) { return; } Loading @@ -435,6 +418,7 @@ public final class FloatingToolbar { mDismissed = false; cancelDismissAndHideAnimations(); cancelOverflowAnimations(); // Make sure a panel is set as the content. if (mContentContainer.getChildCount() == 0) { setMainPanelAsContent(); Loading @@ -442,8 +426,10 @@ public final class FloatingToolbar { // The "show" animation will make this visible. mContentContainer.setAlpha(0); } updateOverflowHeight(contentRect.top - (mMarginVertical * 2)); refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y); mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoords.x, mCoords.y); setTouchableSurfaceInsetsComputer(); runShowAnimation(); } Loading Loading @@ -496,27 +482,17 @@ 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(int x, int y) { public void updateCoordinates(Rect contentRect) { Preconditions.checkNotNull(contentRect); if (!isShowing() || !mPopupWindow.isShowing()) { return; } cancelOverflowAnimations(); refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); mPopupWindow.update(x, y, getWidth(), getHeight()); } /** * Sets the direction in which the overflow will open. i.e. up or down. * * @param overflowDirection Either {@link #OVERFLOW_DIRECTION_UP} * or {@link #OVERFLOW_DIRECTION_DOWN}. */ public void setOverflowDirection(int overflowDirection) { mOverflowDirection = overflowDirection; if (mOverflowPanel != null) { mOverflowPanel.setOverflowDirection(mOverflowDirection); } mPopupWindow.update(mCoords.x, mCoords.y, getWidth(), getHeight()); } /** Loading @@ -540,7 +516,26 @@ public final class FloatingToolbar { return mContentContainer.getContext(); } int getToolbarHeightWithVerticalMargin() { private void refreshCoordinatesAndOverflowDirection(Rect contentRect) { int x = contentRect.centerX() - getWidth() / 2; int y; if (contentRect.top > getHeight()) { y = contentRect.top - getHeight(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP; } else if (contentRect.top > getToolbarHeightWithVerticalMargin()) { y = contentRect.top - getToolbarHeightWithVerticalMargin(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } else { y = contentRect.bottom; mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } mCoords.set(x, y); if (mOverflowPanel != null) { mOverflowPanel.setOverflowDirection(mOverflowDirection); } } private int getToolbarHeightWithVerticalMargin() { return getEstimatedToolbarHeight(mParent.getContext()) + mMarginVertical * 2; } Loading Loading @@ -693,16 +688,24 @@ public final class FloatingToolbar { } // Reset position. if (mMainPanel != null && mContentContainer.getChildAt(0) == mMainPanel.getView()) { if (isMainPanelContent()) { positionMainPanel(); } if (mOverflowPanel != null && mContentContainer.getChildAt(0) == mOverflowPanel.getView()) { if (isOverflowPanelContent()) { positionOverflowPanel(); } } private boolean isMainPanelContent() { return mMainPanel != null && mContentContainer.getChildAt(0) == mMainPanel.getView(); } private boolean isOverflowPanelContent() { return mOverflowPanel != null && mContentContainer.getChildAt(0) == mOverflowPanel.getView(); } /** * Sets the current content to be the main view panel. */ Loading Loading @@ -765,6 +768,25 @@ public final class FloatingToolbar { setContentAreaAsTouchableSurface(); } private void updateOverflowHeight(int height) { if (mOverflowPanel != null) { mOverflowPanel.setSuggestedHeight(height); // Re-measure the popup and it's contents. boolean mainPanelContent = isMainPanelContent(); boolean overflowPanelContent = isOverflowPanelContent(); mContentContainer.removeAllViews(); // required to update popup size. updatePopupSize(); // Reset the appropriate content. if (mainPanelContent) { setMainPanelAsContent(); } if (overflowPanelContent) { setOverflowPanelAsContent(); } } } private void updatePopupSize() { int width = 0; int height = 0; Loading Loading @@ -864,6 +886,8 @@ public final class FloatingToolbar { * @return The menu items that are not included in this main panel. */ public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int suggestedWidth) { Preconditions.checkNotNull(menuItems); final int toolbarWidth = getAdjustedToolbarWidth(mContext, suggestedWidth) // Reserve space for the "open overflow" button. - getEstimatedOpenOverflowButtonWidth(mContext); Loading Loading @@ -972,6 +996,7 @@ public final class FloatingToolbar { private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener; private int mOverflowWidth = 0; private int mSuggestedHeight; /** * Initializes a floating toolbar popup overflow view panel. Loading @@ -981,6 +1006,7 @@ public final class FloatingToolbar { */ public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) { mCloseOverflow = Preconditions.checkNotNull(closeOverflow); mSuggestedHeight = getScreenHeight(context); mContentView = new LinearLayout(context); mContentView.setOrientation(LinearLayout.VERTICAL); Loading Loading @@ -1043,6 +1069,11 @@ public final class FloatingToolbar { mContentView.addView(mBackButtonContainer, index); } public void setSuggestedHeight(int height) { mSuggestedHeight = height; setListViewHeight(); } /** * Returns the content view of the overflow. */ Loading Loading @@ -1074,9 +1105,17 @@ public final class FloatingToolbar { int itemHeight = getEstimatedToolbarHeight(mContentView.getContext()); int height = mListView.getAdapter().getCount() * itemHeight; int maxHeight = mContentView.getContext().getResources(). getDimensionPixelSize(R.dimen.floating_toolbar_maximum_overflow_height); int minHeight = mContentView.getContext().getResources(). getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height); int availableHeight = mSuggestedHeight - (mSuggestedHeight % itemHeight) - itemHeight; // reserve space for the back button. ViewGroup.LayoutParams params = mListView.getLayoutParams(); params.height = Math.min(height, maxHeight); if (availableHeight >= minHeight) { params.height = Math.min(Math.min(availableHeight, maxHeight), height); } else { params.height = Math.min(maxHeight, height); } mListView.setLayoutParams(params); } Loading Loading @@ -1271,16 +1310,4 @@ public final class FloatingToolbar { private static int getScreenHeight(Context context) { return context.getResources().getDisplayMetrics().heightPixels; } /** * Returns value, restricted to the range min->max (inclusive). * If maximum is less than minimum, the result is undefined. * * @param value The value to clamp. * @param minimum The minimum value in the range. * @param maximum The maximum value in the range. Must not be less than minimum. */ private static int clamp(int value, int minimum, int maximum) { return Math.max(minimum, Math.min(value, maximum)); } } core/res/res/values/dimens.xml +2 −1 Original line number Diff line number Diff line Loading @@ -392,7 +392,8 @@ <dimen name="floating_toolbar_text_size">14sp</dimen> <dimen name="floating_toolbar_menu_button_minimum_width">48dp</dimen> <dimen name="floating_toolbar_preferred_width">328dp</dimen> <dimen name="floating_toolbar_minimum_overflow_height">144dp</dimen> <dimen name="floating_toolbar_minimum_overflow_height">96dp</dimen> <dimen name="floating_toolbar_maximum_overflow_height">192dp</dimen> <dimen name="floating_toolbar_horizontal_margin">16dp</dimen> <dimen name="floating_toolbar_vertical_margin">8dp</dimen> Loading core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -2256,6 +2256,7 @@ <java-symbol type="dimen" name="floating_toolbar_menu_button_minimum_width" /> <java-symbol type="dimen" name="floating_toolbar_preferred_width" /> <java-symbol type="dimen" name="floating_toolbar_minimum_overflow_height" /> <java-symbol type="dimen" name="floating_toolbar_maximum_overflow_height" /> <java-symbol type="dimen" name="floating_toolbar_horizontal_margin" /> <java-symbol type="dimen" name="floating_toolbar_vertical_margin" /> Loading Loading
core/java/com/android/internal/widget/FloatingToolbar.java +87 −60 Original line number Diff line number Diff line Loading @@ -79,7 +79,6 @@ public final class FloatingToolbar { private final FloatingToolbarPopup mPopup; private final Rect mContentRect = new Rect(); private final Point mCoordinates = new Point(); private Menu mMenu; private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>(); Loading @@ -87,7 +86,6 @@ public final class FloatingToolbar { private int mSuggestedWidth; private boolean mWidthChanged = true; private int mOverflowDirection; /** * Initializes a floating toolbar. Loading Loading @@ -157,11 +155,9 @@ public final class FloatingToolbar { mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); mShowingTitles = getMenuItemTitles(menuItems); } refreshCoordinates(); mPopup.setOverflowDirection(mOverflowDirection); mPopup.updateCoordinates(mCoordinates.x, mCoordinates.y); mPopup.updateCoordinates(mContentRect); if (!mPopup.isShowing()) { mPopup.show(mCoordinates.x, mCoordinates.y); mPopup.show(mContentRect); } mWidthChanged = false; return this; Loading Loading @@ -208,25 +204,6 @@ public final class FloatingToolbar { return mPopup.isHidden(); } /** * Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}. */ private void refreshCoordinates() { int x = mContentRect.centerX() - mPopup.getWidth() / 2; int y; if (mContentRect.top > mPopup.getHeight()) { y = mContentRect.top - mPopup.getHeight(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP; } else if (mContentRect.top > mPopup.getToolbarHeightWithVerticalMargin()) { y = mContentRect.top - mPopup.getToolbarHeightWithVerticalMargin(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } else { y = mContentRect.bottom; mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } mCoordinates.set(x, y); } /** * Returns true if this floating toolbar is currently showing the specified menu items. */ Loading Loading @@ -345,6 +322,8 @@ public final class FloatingToolbar { } }; private final Point mCoords = new Point(); private final Region mTouchableRegion = new Region(); private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = new ViewTreeObserver.OnComputeInternalInsetsListener() { Loading Loading @@ -404,6 +383,8 @@ public final class FloatingToolbar { */ public void layoutMenuItems(List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener, int suggestedWidth) { Preconditions.checkNotNull(menuItems); mContentContainer.removeAllViews(); if (mMainPanel == null) { mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow); Loading @@ -426,7 +407,9 @@ 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(int x, int y) { public void show(Rect contentRect) { Preconditions.checkNotNull(contentRect); if (isShowing()) { return; } Loading @@ -435,6 +418,7 @@ public final class FloatingToolbar { mDismissed = false; cancelDismissAndHideAnimations(); cancelOverflowAnimations(); // Make sure a panel is set as the content. if (mContentContainer.getChildCount() == 0) { setMainPanelAsContent(); Loading @@ -442,8 +426,10 @@ public final class FloatingToolbar { // The "show" animation will make this visible. mContentContainer.setAlpha(0); } updateOverflowHeight(contentRect.top - (mMarginVertical * 2)); refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y); mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoords.x, mCoords.y); setTouchableSurfaceInsetsComputer(); runShowAnimation(); } Loading Loading @@ -496,27 +482,17 @@ 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(int x, int y) { public void updateCoordinates(Rect contentRect) { Preconditions.checkNotNull(contentRect); if (!isShowing() || !mPopupWindow.isShowing()) { return; } cancelOverflowAnimations(); refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); mPopupWindow.update(x, y, getWidth(), getHeight()); } /** * Sets the direction in which the overflow will open. i.e. up or down. * * @param overflowDirection Either {@link #OVERFLOW_DIRECTION_UP} * or {@link #OVERFLOW_DIRECTION_DOWN}. */ public void setOverflowDirection(int overflowDirection) { mOverflowDirection = overflowDirection; if (mOverflowPanel != null) { mOverflowPanel.setOverflowDirection(mOverflowDirection); } mPopupWindow.update(mCoords.x, mCoords.y, getWidth(), getHeight()); } /** Loading @@ -540,7 +516,26 @@ public final class FloatingToolbar { return mContentContainer.getContext(); } int getToolbarHeightWithVerticalMargin() { private void refreshCoordinatesAndOverflowDirection(Rect contentRect) { int x = contentRect.centerX() - getWidth() / 2; int y; if (contentRect.top > getHeight()) { y = contentRect.top - getHeight(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP; } else if (contentRect.top > getToolbarHeightWithVerticalMargin()) { y = contentRect.top - getToolbarHeightWithVerticalMargin(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } else { y = contentRect.bottom; mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } mCoords.set(x, y); if (mOverflowPanel != null) { mOverflowPanel.setOverflowDirection(mOverflowDirection); } } private int getToolbarHeightWithVerticalMargin() { return getEstimatedToolbarHeight(mParent.getContext()) + mMarginVertical * 2; } Loading Loading @@ -693,16 +688,24 @@ public final class FloatingToolbar { } // Reset position. if (mMainPanel != null && mContentContainer.getChildAt(0) == mMainPanel.getView()) { if (isMainPanelContent()) { positionMainPanel(); } if (mOverflowPanel != null && mContentContainer.getChildAt(0) == mOverflowPanel.getView()) { if (isOverflowPanelContent()) { positionOverflowPanel(); } } private boolean isMainPanelContent() { return mMainPanel != null && mContentContainer.getChildAt(0) == mMainPanel.getView(); } private boolean isOverflowPanelContent() { return mOverflowPanel != null && mContentContainer.getChildAt(0) == mOverflowPanel.getView(); } /** * Sets the current content to be the main view panel. */ Loading Loading @@ -765,6 +768,25 @@ public final class FloatingToolbar { setContentAreaAsTouchableSurface(); } private void updateOverflowHeight(int height) { if (mOverflowPanel != null) { mOverflowPanel.setSuggestedHeight(height); // Re-measure the popup and it's contents. boolean mainPanelContent = isMainPanelContent(); boolean overflowPanelContent = isOverflowPanelContent(); mContentContainer.removeAllViews(); // required to update popup size. updatePopupSize(); // Reset the appropriate content. if (mainPanelContent) { setMainPanelAsContent(); } if (overflowPanelContent) { setOverflowPanelAsContent(); } } } private void updatePopupSize() { int width = 0; int height = 0; Loading Loading @@ -864,6 +886,8 @@ public final class FloatingToolbar { * @return The menu items that are not included in this main panel. */ public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int suggestedWidth) { Preconditions.checkNotNull(menuItems); final int toolbarWidth = getAdjustedToolbarWidth(mContext, suggestedWidth) // Reserve space for the "open overflow" button. - getEstimatedOpenOverflowButtonWidth(mContext); Loading Loading @@ -972,6 +996,7 @@ public final class FloatingToolbar { private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener; private int mOverflowWidth = 0; private int mSuggestedHeight; /** * Initializes a floating toolbar popup overflow view panel. Loading @@ -981,6 +1006,7 @@ public final class FloatingToolbar { */ public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) { mCloseOverflow = Preconditions.checkNotNull(closeOverflow); mSuggestedHeight = getScreenHeight(context); mContentView = new LinearLayout(context); mContentView.setOrientation(LinearLayout.VERTICAL); Loading Loading @@ -1043,6 +1069,11 @@ public final class FloatingToolbar { mContentView.addView(mBackButtonContainer, index); } public void setSuggestedHeight(int height) { mSuggestedHeight = height; setListViewHeight(); } /** * Returns the content view of the overflow. */ Loading Loading @@ -1074,9 +1105,17 @@ public final class FloatingToolbar { int itemHeight = getEstimatedToolbarHeight(mContentView.getContext()); int height = mListView.getAdapter().getCount() * itemHeight; int maxHeight = mContentView.getContext().getResources(). getDimensionPixelSize(R.dimen.floating_toolbar_maximum_overflow_height); int minHeight = mContentView.getContext().getResources(). getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height); int availableHeight = mSuggestedHeight - (mSuggestedHeight % itemHeight) - itemHeight; // reserve space for the back button. ViewGroup.LayoutParams params = mListView.getLayoutParams(); params.height = Math.min(height, maxHeight); if (availableHeight >= minHeight) { params.height = Math.min(Math.min(availableHeight, maxHeight), height); } else { params.height = Math.min(maxHeight, height); } mListView.setLayoutParams(params); } Loading Loading @@ -1271,16 +1310,4 @@ public final class FloatingToolbar { private static int getScreenHeight(Context context) { return context.getResources().getDisplayMetrics().heightPixels; } /** * Returns value, restricted to the range min->max (inclusive). * If maximum is less than minimum, the result is undefined. * * @param value The value to clamp. * @param minimum The minimum value in the range. * @param maximum The maximum value in the range. Must not be less than minimum. */ private static int clamp(int value, int minimum, int maximum) { return Math.max(minimum, Math.min(value, maximum)); } }
core/res/res/values/dimens.xml +2 −1 Original line number Diff line number Diff line Loading @@ -392,7 +392,8 @@ <dimen name="floating_toolbar_text_size">14sp</dimen> <dimen name="floating_toolbar_menu_button_minimum_width">48dp</dimen> <dimen name="floating_toolbar_preferred_width">328dp</dimen> <dimen name="floating_toolbar_minimum_overflow_height">144dp</dimen> <dimen name="floating_toolbar_minimum_overflow_height">96dp</dimen> <dimen name="floating_toolbar_maximum_overflow_height">192dp</dimen> <dimen name="floating_toolbar_horizontal_margin">16dp</dimen> <dimen name="floating_toolbar_vertical_margin">8dp</dimen> Loading
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -2256,6 +2256,7 @@ <java-symbol type="dimen" name="floating_toolbar_menu_button_minimum_width" /> <java-symbol type="dimen" name="floating_toolbar_preferred_width" /> <java-symbol type="dimen" name="floating_toolbar_minimum_overflow_height" /> <java-symbol type="dimen" name="floating_toolbar_maximum_overflow_height" /> <java-symbol type="dimen" name="floating_toolbar_horizontal_margin" /> <java-symbol type="dimen" name="floating_toolbar_vertical_margin" /> Loading