diff options
Diffstat (limited to 'core/java')
13 files changed, 1045 insertions, 770 deletions
diff --git a/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java b/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java index c452e0615685..08a720555833 100644 --- a/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java +++ b/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java @@ -16,12 +16,21 @@ package android.service.selectiontoolbar; -import android.util.Log; +import static android.view.selectiontoolbar.SelectionToolbarManager.ERROR_DO_NOT_ALLOW_MULTIPLE_TOOL_BAR; +import static android.view.selectiontoolbar.SelectionToolbarManager.NO_TOOLBAR_ID; + +import android.util.Pair; +import android.util.Slog; +import android.util.SparseArray; import android.view.selectiontoolbar.ShowInfo; +import java.util.UUID; + /** * The default implementation of {@link SelectionToolbarRenderService}. * + * <p><b>NOTE:<b/> The requests are handled on the service main thread. + * * @hide */ // TODO(b/214122495): fix class not found then move to system service folder @@ -29,22 +38,97 @@ public final class DefaultSelectionToolbarRenderService extends SelectionToolbar private static final String TAG = "DefaultSelectionToolbarRenderService"; + // TODO(b/215497659): handle remove if the client process dies. + // Only show one toolbar, dismiss the old ones and remove from cache + private final SparseArray<Pair<Long, RemoteSelectionToolbar>> mToolbarCache = + new SparseArray<>(); + + /** + * Only allow one package to create one toolbar. + */ + private boolean canShowToolbar(int uid, ShowInfo showInfo) { + if (showInfo.getWidgetToken() != NO_TOOLBAR_ID) { + return true; + } + return mToolbarCache.indexOfKey(uid) < 0; + } + @Override - public void onShow(ShowInfo showInfo, + public void onShow(int callingUid, ShowInfo showInfo, SelectionToolbarRenderService.RemoteCallbackWrapper callbackWrapper) { - // TODO: Add implementation - Log.w(TAG, "onShow()"); + if (!canShowToolbar(callingUid, showInfo)) { + Slog.e(TAG, "Do not allow multiple toolbar for the app."); + callbackWrapper.onError(ERROR_DO_NOT_ALLOW_MULTIPLE_TOOL_BAR); + return; + } + long widgetToken = showInfo.getWidgetToken() == NO_TOOLBAR_ID + ? UUID.randomUUID().getMostSignificantBits() + : showInfo.getWidgetToken(); + + if (mToolbarCache.indexOfKey(callingUid) < 0) { + RemoteSelectionToolbar toolbar = new RemoteSelectionToolbar(this, + widgetToken, showInfo.getHostInputToken(), + callbackWrapper, this::transferTouch); + mToolbarCache.put(callingUid, new Pair<>(widgetToken, toolbar)); + } + Slog.v(TAG, "onShow() for " + widgetToken); + Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.get(callingUid); + if (toolbarPair.first == widgetToken) { + toolbarPair.second.show(showInfo); + } else { + Slog.w(TAG, "onShow() for unknown " + widgetToken); + } } @Override public void onHide(long widgetToken) { - // TODO: Add implementation - Log.w(TAG, "onHide()"); + RemoteSelectionToolbar toolbar = getRemoteSelectionToolbarByTokenLocked(widgetToken); + if (toolbar != null) { + Slog.v(TAG, "onHide() for " + widgetToken); + toolbar.hide(widgetToken); + } } @Override public void onDismiss(long widgetToken) { - // TODO: Add implementation - Log.w(TAG, "onDismiss()"); + RemoteSelectionToolbar toolbar = getRemoteSelectionToolbarByTokenLocked(widgetToken); + if (toolbar != null) { + Slog.v(TAG, "onDismiss() for " + widgetToken); + toolbar.dismiss(widgetToken); + removeRemoteSelectionToolbarByTokenLocked(widgetToken); + } + } + + @Override + public void onToolbarShowTimeout(int callingUid) { + Slog.w(TAG, "onToolbarShowTimeout for callingUid = " + callingUid); + Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.get(callingUid); + if (toolbarPair != null) { + RemoteSelectionToolbar remoteToolbar = toolbarPair.second; + remoteToolbar.dismiss(toolbarPair.first); + remoteToolbar.onToolbarShowTimeout(); + mToolbarCache.remove(callingUid); + } + } + + private RemoteSelectionToolbar getRemoteSelectionToolbarByTokenLocked(long widgetToken) { + for (int i = 0; i < mToolbarCache.size(); i++) { + Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.valueAt(i); + if (toolbarPair.first == widgetToken) { + return toolbarPair.second; + } + } + return null; + } + + private void removeRemoteSelectionToolbarByTokenLocked(long widgetToken) { + for (int i = 0; i < mToolbarCache.size(); i++) { + Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.valueAt(i); + if (toolbarPair.first == widgetToken) { + mToolbarCache.remove(mToolbarCache.keyAt(i)); + return; + } + } } } + diff --git a/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java b/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java new file mode 100644 index 000000000000..5e4262b970eb --- /dev/null +++ b/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.selectiontoolbar; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.IBinder; +import android.view.MotionEvent; +import android.widget.LinearLayout; + +/** + * This class is the root view for the selection toolbar. It is responsible for + * detecting the click on the item and to also transfer input focus to the application. + * + * @hide + */ +@SuppressLint("ViewConstructor") +public class FloatingToolbarRoot extends LinearLayout { + + private final IBinder mTargetInputToken; + private final SelectionToolbarRenderService.TransferTouchListener mTransferTouchListener; + private float mDownX; + private float mDownY; + + public FloatingToolbarRoot(Context context, IBinder targetInputToken, + SelectionToolbarRenderService.TransferTouchListener transferTouchListener) { + super(context); + mTargetInputToken = targetInputToken; + mTransferTouchListener = transferTouchListener; + setFocusable(false); + } + + @Override + @SuppressLint("ClickableViewAccessibility") + public boolean dispatchTouchEvent(MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: { + mDownX = event.getX(); + mDownY = event.getY(); + // TODO: Check x, y if we need to transfer touch focus to application + //mTransferTouchListener.onTransferTouch(getViewRootImpl().getInputToken(), + // mTargetInputToken); + } + } + return super.dispatchTouchEvent(event); + } +} diff --git a/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderService.aidl b/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderService.aidl index 2bd99acbf24a..79281b8b361d 100644 --- a/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderService.aidl +++ b/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderService.aidl @@ -25,7 +25,8 @@ import android.view.selectiontoolbar.ShowInfo; * @hide */ oneway interface ISelectionToolbarRenderService { - void onShow(in ShowInfo showInfo, in ISelectionToolbarCallback callback); + void onConnected(in IBinder callback); + void onShow(int callingUid, in ShowInfo showInfo, in ISelectionToolbarCallback callback); void onHide(long widgetToken); - void onDismiss(long widgetToken); + void onDismiss(int callingUid, long widgetToken); } diff --git a/core/java/android/view/selectiontoolbar/SelectionContext.aidl b/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderServiceCallback.aidl index 52068312d4a1..f6c47ddf1e00 100644 --- a/core/java/android/view/selectiontoolbar/SelectionContext.aidl +++ b/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderServiceCallback.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,9 +14,15 @@ * limitations under the License. */ -package android.view.selectiontoolbar; +package android.service.selectiontoolbar; + +import android.os.IBinder; /** + * The interface from the SelectionToolbarRenderService to the system. + * * @hide */ -parcelable SelectionContext; +oneway interface ISelectionToolbarRenderServiceCallback { + void transferTouch(in IBinder source, in IBinder target); +} diff --git a/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java b/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java index 95ecc4e16446..cbe232b7b39a 100644 --- a/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java +++ b/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java @@ -21,72 +21,63 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.annotation.Nullable; import android.content.Context; import android.content.res.TypedArray; -import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.Region; import android.graphics.drawable.AnimatedVectorDrawable; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.IBinder; import android.text.TextUtils; +import android.util.Log; import android.util.Size; import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.MotionEvent; +import android.view.SurfaceControlViewHost; import android.view.View; -import android.view.View.MeasureSpec; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.animation.Transformation; +import android.view.selectiontoolbar.ShowInfo; +import android.view.selectiontoolbar.ToolbarMenuItem; +import android.view.selectiontoolbar.WidgetInfo; import android.widget.ArrayAdapter; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; -import android.widget.PopupWindow; import android.widget.TextView; import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; -import com.android.internal.widget.floatingtoolbar.FloatingToolbarPopup; +import com.android.internal.widget.floatingtoolbar.FloatingToolbar; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Objects; /** - * A popup window used by the floating toolbar to render menu items in the local app process. + * This class is responsible for rendering/animation of the selection toolbar in the remote + * system process. It holds 2 panels (i.e. main panel and overflow panel) and an overflow + * button to transition between panels. * - * This class is responsible for the rendering/animation of the floating toolbar. - * It holds 2 panels (i.e. main panel and overflow panel) and an overflow button - * to transition between panels. + * @hide */ - -final class RemoteSelectionToolbar implements FloatingToolbarPopup { +// TODO(b/215497659): share code with LocalFloatingToolbarPopup +final class RemoteSelectionToolbar { + private static final String TAG = "RemoteSelectionToolbar"; /* Minimum and maximum number of items allowed in the overflow. */ private static final int MIN_OVERFLOW_SIZE = 2; private static final int MAX_OVERFLOW_SIZE = 4; private final Context mContext; - private final View mParent; // Parent for the popup window. - private final PopupWindow mPopupWindow; /* Margins between the popup window and its content. */ private final int mMarginHorizontal; @@ -121,23 +112,22 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { private final Animation.AnimationListener mOverflowAnimationListener; private final Rect mViewPortOnScreen = new Rect(); // portion of screen we can draw in. - private final Point mCoordsOnWindow = new Point(); // popup window coordinates. - /* Temporary data holders. Reset values before using. */ - private final int[] mTmpCoords = new int[2]; - - private final Region mTouchableRegion = new Region(); - private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = - info -> { - info.contentInsets.setEmpty(); - info.visibleInsets.setEmpty(); - info.touchableRegion.set(mTouchableRegion); - info.setTouchableInsets( - ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); - }; private final int mLineHeight; private final int mIconTextSpacing; + private final long mSelectionToolbarToken; + private IBinder mHostInputToken; + private final SelectionToolbarRenderService.RemoteCallbackWrapper mCallbackWrapper; + private final SelectionToolbarRenderService.TransferTouchListener mTransferTouchListener; + private int mPopupWidth; + private int mPopupHeight; + // Coordinates to show the toolbar relative to the specified view port + private final Point mRelativeCoordsForToolbar = new Point(); + private List<ToolbarMenuItem> mMenuItems; + private SurfaceControlViewHost mSurfaceControlViewHost; + private SurfaceControlViewHost.SurfacePackage mSurfacePackage; + /** * @see OverflowPanelViewHelper#preparePopupContent(). */ @@ -145,7 +135,6 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { @Override public void run() { setPanelsStatesAtRestingPosition(); - setContentAreaAsTouchableSurface(); mContentContainer.setAlpha(1); } }; @@ -159,26 +148,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { private Size mMainPanelSize; /* Menu items and click listeners */ - private final Map<MenuItemRepr, MenuItem> mMenuItems = new LinkedHashMap<>(); - private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener; - private final View.OnClickListener mMenuItemButtonOnClickListener = - new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mOnMenuItemClickListener == null) { - return; - } - final Object tag = v.getTag(); - if (!(tag instanceof MenuItemRepr)) { - return; - } - final MenuItem menuItem = mMenuItems.get((MenuItemRepr) tag); - if (menuItem == null) { - return; - } - mOnMenuItemClickListener.onMenuItemClick(menuItem); - } - }; + private final View.OnClickListener mMenuItemButtonOnClickListener; private boolean mOpenOverflowUpwards; // Whether the overflow opens upwards or downwards. private boolean mIsOverflowOpen; @@ -186,27 +156,26 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { private int mTransitionDurationScale; // Used to scale the toolbar transition duration. private final Rect mPreviousContentRect = new Rect(); - private int mSuggestedWidth; - private boolean mWidthChanged = true; - /** - * Initializes a new floating toolbar popup. - * - * @param parent A parent view to get the {@link android.view.View#getWindowToken()} token - * from. - */ - RemoteSelectionToolbar(Context context, View parent) { - mParent = Objects.requireNonNull(parent); + private final Rect mTempContentRect = new Rect(); + + RemoteSelectionToolbar(Context context, long selectionToolbarToken, IBinder hostInputToken, + SelectionToolbarRenderService.RemoteCallbackWrapper callbackWrapper, + SelectionToolbarRenderService.TransferTouchListener transferTouchListener) { mContext = applyDefaultTheme(context); + mSelectionToolbarToken = selectionToolbarToken; + mCallbackWrapper = callbackWrapper; + mTransferTouchListener = transferTouchListener; + mHostInputToken = hostInputToken; + mContentContainer = createContentContainer(mContext); - mPopupWindow = createPopupWindow(mContentContainer); - mMarginHorizontal = parent.getResources() + mMarginHorizontal = mContext.getResources() .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); - mMarginVertical = parent.getResources() + mMarginVertical = mContext.getResources() .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin); - mLineHeight = context.getResources() + mLineHeight = mContext.getResources() .getDimensionPixelSize(R.dimen.floating_toolbar_height); - mIconTextSpacing = context.getResources() + mIconTextSpacing = mContext.getResources() .getDimensionPixelSize(R.dimen.floating_toolbar_icon_text_spacing); // Interpolators @@ -252,46 +221,54 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mPopupWindow.dismiss(); + // TODO(b/215497659): should dismiss window after animation mContentContainer.removeAllViews(); + mSurfaceControlViewHost.release(); + mSurfaceControlViewHost = null; + mSurfacePackage = null; } }); mHideAnimation = createExitAnimation( mContentContainer, 0, // startDelay - new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mPopupWindow.dismiss(); - } - }); + null); // TODO(b/215497659): should handle hide after animation + mMenuItemButtonOnClickListener = v -> { + Object tag = v.getTag(); + if (!(tag instanceof ToolbarMenuItem)) { + return; + } + mCallbackWrapper.onMenuItemClicked((ToolbarMenuItem) tag); + }; } - @Override - public boolean setOutsideTouchable( - boolean outsideTouchable, @Nullable PopupWindow.OnDismissListener onDismiss) { - boolean ret = false; - if (mPopupWindow.isOutsideTouchable() ^ outsideTouchable) { - mPopupWindow.setOutsideTouchable(outsideTouchable); - mPopupWindow.setFocusable(!outsideTouchable); - mPopupWindow.update(); - ret = true; + private WidgetInfo createWidgetInfo() { + mTempContentRect.set(mRelativeCoordsForToolbar.x, mRelativeCoordsForToolbar.y, + mRelativeCoordsForToolbar.x + mPopupWidth, + mRelativeCoordsForToolbar.y + mPopupHeight); + return new WidgetInfo(mSelectionToolbarToken, mTempContentRect, getSurfacePackage()); + } + + private SurfaceControlViewHost.SurfacePackage getSurfacePackage() { + if (mSurfaceControlViewHost == null) { + final FloatingToolbarRoot contentHolder = new FloatingToolbarRoot(mContext, + mHostInputToken, mTransferTouchListener); + contentHolder.addView(mContentContainer); + mSurfaceControlViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), + mHostInputToken); + mSurfaceControlViewHost.setView(contentHolder, mPopupWidth, mPopupHeight); + } + if (mSurfacePackage == null) { + mSurfacePackage = mSurfaceControlViewHost.getSurfacePackage(); } - mPopupWindow.setOnDismissListener(onDismiss); - return ret; + return mSurfacePackage; } - /** - * Lays out buttons for the specified menu items. - * Requires a subsequent call to {@link FloatingToolbar#show()} to show the items. - */ private void layoutMenuItems( - List<MenuItem> menuItems, - MenuItem.OnMenuItemClickListener menuItemClickListener, + List<ToolbarMenuItem> menuItems, int suggestedWidth) { cancelOverflowAnimations(); clearPanels(); - updateMenuItems(menuItems, menuItemClickListener); + menuItems = layoutMainPanelItems(menuItems, getAdjustedToolbarWidth(suggestedWidth)); if (!menuItems.isEmpty()) { // Add remaining items to the overflow. @@ -300,148 +277,98 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { updatePopupSize(); } - /** - * Updates the popup's menu items without rebuilding the widget. - * Use in place of layoutMenuItems() when the popup's views need not be reconstructed. - * - * @see #isLayoutRequired(List<MenuItem>) - */ - private void updateMenuItems( - List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener) { - mMenuItems.clear(); - for (MenuItem menuItem : menuItems) { - mMenuItems.put(MenuItemRepr.of(menuItem), menuItem); - } - mOnMenuItemClickListener = menuItemClickListener; + public void onToolbarShowTimeout() { + mCallbackWrapper.onToolbarShowTimeout(); } /** - * Returns true if this popup needs a relayout to properly render the specified menu items. + * Show the specified selection toolbar. */ - private boolean isLayoutRequired(List<MenuItem> menuItems) { - return !MenuItemRepr.reprEquals(menuItems, mMenuItems.values()); - } + public void show(ShowInfo showInfo) { + debugLog("show() for " + showInfo); - @Override - public void setWidthChanged(boolean widthChanged) { - mWidthChanged = widthChanged; - } - - @Override - public void setSuggestedWidth(int suggestedWidth) { - // Check if there's been a substantial width spec change. - int difference = Math.abs(suggestedWidth - mSuggestedWidth); - mWidthChanged = difference > (mSuggestedWidth * 0.2); - mSuggestedWidth = suggestedWidth; - } + mMenuItems = showInfo.getMenuItems(); + mViewPortOnScreen.set(showInfo.getViewPortOnScreen()); - @Override - public void show(List<MenuItem> menuItems, - MenuItem.OnMenuItemClickListener menuItemClickListener, Rect contentRect) { - if (isLayoutRequired(menuItems) || mWidthChanged) { - dismiss(); - layoutMenuItems(menuItems, menuItemClickListener, mSuggestedWidth); - } else { - updateMenuItems(menuItems, menuItemClickListener); + debugLog("show(): layoutRequired=" + showInfo.isLayoutRequired()); + if (showInfo.isLayoutRequired()) { + layoutMenuItems(mMenuItems, showInfo.getSuggestedWidth()); } + Rect contentRect = showInfo.getContentRect(); if (!isShowing()) { show(contentRect); } else if (!mPreviousContentRect.equals(contentRect)) { updateCoordinates(contentRect); } - mWidthChanged = false; mPreviousContentRect.set(contentRect); } private void show(Rect contentRectOnScreen) { Objects.requireNonNull(contentRectOnScreen); - if (isShowing()) { - return; - } - mHidden = false; mDismissed = false; cancelDismissAndHideAnimations(); cancelOverflowAnimations(); - refreshCoordinatesAndOverflowDirection(contentRectOnScreen); preparePopupContent(); - // We need to specify the position in window coordinates. - // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can - // specify the popup position in screen coordinates. - mPopupWindow.showAtLocation( - mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x, mCoordsOnWindow.y); - setTouchableSurfaceInsetsComputer(); - runShowAnimation(); + mCallbackWrapper.onShown(createWidgetInfo()); + // TODO(b/215681595): Use Choreographer to coordinate for show between different thread + mShowAnimation.start(); } - @Override - public void dismiss() { + /** + * Dismiss the specified selection toolbar. + */ + public void dismiss(long floatingToolbarToken) { + debugLog("dismiss for " + floatingToolbarToken); if (mDismissed) { return; } - mHidden = false; mDismissed = true; - mHideAnimation.cancel(); - runDismissAnimation(); - setZeroTouchableSurface(); + mHideAnimation.cancel(); + mDismissAnimation.start(); } - @Override - public void hide() { + /** + * Hide the specified selection toolbar. + */ + public void hide(long floatingToolbarToken) { + debugLog("hide for " + floatingToolbarToken); if (!isShowing()) { return; } mHidden = true; - runHideAnimation(); - setZeroTouchableSurface(); + mHideAnimation.start(); } - @Override public boolean isShowing() { return !mDismissed && !mHidden; } - @Override - public boolean isHidden() { - return mHidden; - } - - /** - * Updates the coordinates of this popup. - * 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. - */ private void updateCoordinates(Rect contentRectOnScreen) { Objects.requireNonNull(contentRectOnScreen); - if (!isShowing() || !mPopupWindow.isShowing()) { + if (!isShowing()) { return; } - cancelOverflowAnimations(); refreshCoordinatesAndOverflowDirection(contentRectOnScreen); preparePopupContent(); - // We need to specify the position in window coordinates. - // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can - // specify the popup position in screen coordinates. - mPopupWindow.update( - mCoordsOnWindow.x, mCoordsOnWindow.y, - mPopupWindow.getWidth(), mPopupWindow.getHeight()); + WidgetInfo widgetInfo = createWidgetInfo(); + mSurfaceControlViewHost.relayout(mPopupWidth, mPopupHeight); + mCallbackWrapper.onWidgetUpdated(widgetInfo); } private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) { - refreshViewPort(); - // Initialize x ensuring that the toolbar isn't rendered behind the nav bar in // landscape. final int x = Math.min( - contentRectOnScreen.centerX() - mPopupWindow.getWidth() / 2, - mViewPortOnScreen.right - mPopupWindow.getWidth()); + contentRectOnScreen.centerX() - mPopupWidth / 2, + mViewPortOnScreen.right - mPopupWidth); final int y; @@ -484,7 +411,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { // There is enough space at the top of the content rect for the overflow. // Position above and open upwards. updateOverflowHeight(availableHeightAboveContent - margin); - y = contentRectOnScreen.top - mPopupWindow.getHeight(); + y = contentRectOnScreen.top - mPopupHeight; mOpenOverflowUpwards = true; } else if (availableHeightAboveContent >= toolbarHeightWithVerticalMargin && availableHeightThroughContentDown >= minimumOverflowHeightWithMargin) { @@ -507,7 +434,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { // Position below but open upwards. updateOverflowHeight(availableHeightThroughContentUp - margin); y = contentRectOnScreen.bottom + toolbarHeightWithVerticalMargin - - mPopupWindow.getHeight(); + - mPopupHeight; mOpenOverflowUpwards = true; } else { // Not enough space. @@ -517,45 +444,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { mOpenOverflowUpwards = false; } } - - // We later specify the location of PopupWindow relative to the attached window. - // The idea here is that 1) we can get the location of a View in both window coordinates - // and screen coordinates, where the offset between them should be equal to the window - // origin, and 2) we can use an arbitrary for this calculation while calculating the - // location of the rootview is supposed to be least expensive. - // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can avoid - // the following calculation. - mParent.getRootView().getLocationOnScreen(mTmpCoords); - int rootViewLeftOnScreen = mTmpCoords[0]; - int rootViewTopOnScreen = mTmpCoords[1]; - mParent.getRootView().getLocationInWindow(mTmpCoords); - int rootViewLeftOnWindow = mTmpCoords[0]; - int rootViewTopOnWindow = mTmpCoords[1]; - int windowLeftOnScreen = rootViewLeftOnScreen - rootViewLeftOnWindow; - int windowTopOnScreen = rootViewTopOnScreen - rootViewTopOnWindow; - mCoordsOnWindow.set( - Math.max(0, x - windowLeftOnScreen), Math.max(0, y - windowTopOnScreen)); - } - - /** - * Performs the "show" animation on the floating popup. - */ - private void runShowAnimation() { - mShowAnimation.start(); - } - - /** - * Performs the "dismiss" animation on the floating popup. - */ - private void runDismissAnimation() { - mDismissAnimation.start(); - } - - /** - * Performs the "hide" animation on the floating popup. - */ - private void runHideAnimation() { - mHideAnimation.start(); + mRelativeCoordsForToolbar.set(x, y); } private void cancelDismissAndHideAnimations() { @@ -628,12 +517,11 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { } }; widthAnimation.setInterpolator(mLogAccelerateInterpolator); - widthAnimation.setDuration(getAdjustedDuration(250)); + widthAnimation.setDuration(getAnimationDuration()); heightAnimation.setInterpolator(mFastOutSlowInInterpolator); - heightAnimation.setDuration(getAdjustedDuration(250)); + heightAnimation.setDuration(getAnimationDuration()); overflowButtonAnimation.setInterpolator(mFastOutSlowInInterpolator); - overflowButtonAnimation.setDuration(getAdjustedDuration(250)); - mOpenOverflowAnimation.getAnimations().clear(); + overflowButtonAnimation.setDuration(getAnimationDuration()); mOpenOverflowAnimation.getAnimations().clear(); mOpenOverflowAnimation.addAnimation(widthAnimation); mOpenOverflowAnimation.addAnimation(heightAnimation); @@ -704,11 +592,11 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { } }; widthAnimation.setInterpolator(mFastOutSlowInInterpolator); - widthAnimation.setDuration(getAdjustedDuration(250)); + widthAnimation.setDuration(getAnimationDuration()); heightAnimation.setInterpolator(mLogAccelerateInterpolator); - heightAnimation.setDuration(getAdjustedDuration(250)); + heightAnimation.setDuration(getAnimationDuration()); overflowButtonAnimation.setInterpolator(mFastOutSlowInInterpolator); - overflowButtonAnimation.setDuration(getAdjustedDuration(250)); + overflowButtonAnimation.setDuration(getAnimationDuration()); mCloseOverflowAnimation.getAnimations().clear(); mCloseOverflowAnimation.addAnimation(widthAnimation); mCloseOverflowAnimation.addAnimation(heightAnimation); @@ -756,7 +644,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { mOverflowPanel.setX(0); // align left } else { mContentContainer.setX(// align right - mPopupWindow.getWidth() - containerSize.getWidth() - mMarginHorizontal); + mPopupWidth - containerSize.getWidth() - mMarginHorizontal); mMainPanel.setX(-mContentContainer.getX()); // align right mOverflowButton.setX(0); // align left mOverflowPanel.setX(0); // align left @@ -798,7 +686,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { mOverflowPanel.setX(0); // align left } else { mContentContainer.setX(// align right - mPopupWindow.getWidth() - containerSize.getWidth() - mMarginHorizontal); + mPopupWidth - containerSize.getWidth() - mMarginHorizontal); mMainPanel.setX(0); // align left mOverflowButton.setX(// align right containerSize.getWidth() - mOverflowButtonSize.getWidth()); @@ -866,70 +754,23 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { width = Math.max(width, mOverflowPanelSize.getWidth()); height = Math.max(height, mOverflowPanelSize.getHeight()); } - mPopupWindow.setWidth(width + mMarginHorizontal * 2); - mPopupWindow.setHeight(height + mMarginVertical * 2); - maybeComputeTransitionDurationScale(); - } - private void refreshViewPort() { - mParent.getWindowVisibleDisplayFrame(mViewPortOnScreen); + mPopupWidth = width + mMarginHorizontal * 2; + mPopupHeight = height + mMarginVertical * 2; + maybeComputeTransitionDurationScale(); } private int getAdjustedToolbarWidth(int suggestedWidth) { int width = suggestedWidth; - refreshViewPort(); - int maximumWidth = mViewPortOnScreen.width() - 2 * mParent.getResources() + int maximumWidth = mViewPortOnScreen.width() - 2 * mContext.getResources() .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); if (width <= 0) { - width = mParent.getResources() + width = mContext.getResources() .getDimensionPixelSize(R.dimen.floating_toolbar_preferred_width); } return Math.min(width, maximumWidth); } - /** - * Sets the touchable region of this popup to be zero. This means that all touch events on - * this popup will go through to the surface behind it. - */ - private void setZeroTouchableSurface() { - mTouchableRegion.setEmpty(); - } - - /** - * Sets the touchable region of this popup to be the area occupied by its content. - */ - private void setContentAreaAsTouchableSurface() { - Objects.requireNonNull(mMainPanelSize); - final int width; - final int height; - if (mIsOverflowOpen) { - Objects.requireNonNull(mOverflowPanelSize); - width = mOverflowPanelSize.getWidth(); - height = mOverflowPanelSize.getHeight(); - } else { - width = mMainPanelSize.getWidth(); - height = mMainPanelSize.getHeight(); - } - mTouchableRegion.set( - (int) mContentContainer.getX(), - (int) mContentContainer.getY(), - (int) mContentContainer.getX() + width, - (int) mContentContainer.getY() + height); - } - - /** - * Make the touchable area of this popup be the area specified by mTouchableRegion. - * This should be called after the popup window has been dismissed (dismiss/hide) - * and is probably being re-shown with a new content root view. - */ - private void setTouchableSurfaceInsetsComputer() { - ViewTreeObserver viewTreeObserver = mPopupWindow.getContentView() - .getRootView() - .getViewTreeObserver(); - viewTreeObserver.removeOnComputeInternalInsetsListener(mInsetsComputer); - viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer); - } - private boolean isInRTLMode() { return mContext.getApplicationInfo().hasRtlSupport() && mContext.getResources().getConfiguration().getLayoutDirection() @@ -946,18 +787,14 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { * * @return The menu items that are not included in this main panel. */ - public List<MenuItem> layoutMainPanelItems( - List<MenuItem> menuItems, final int toolbarWidth) { - Objects.requireNonNull(menuItems); - - int availableWidth = toolbarWidth; - - final LinkedList<MenuItem> remainingMenuItems = new LinkedList<>(); + private List<ToolbarMenuItem> layoutMainPanelItems(List<ToolbarMenuItem> menuItems, + int toolbarWidth) { + final LinkedList<ToolbarMenuItem> remainingMenuItems = new LinkedList<>(); // add the overflow menu items to the end of the remainingMenuItems list. - final LinkedList<MenuItem> overflowMenuItems = new LinkedList(); - for (MenuItem menuItem : menuItems) { + final LinkedList<ToolbarMenuItem> overflowMenuItems = new LinkedList(); + for (ToolbarMenuItem menuItem : menuItems) { if (menuItem.getItemId() != android.R.id.textAssist - && menuItem.requiresOverflow()) { + && menuItem.getPriority() == ToolbarMenuItem.PRIORITY_OVERFLOW) { overflowMenuItems.add(menuItem); } else { remainingMenuItems.add(menuItem); @@ -968,25 +805,22 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { mMainPanel.removeAllViews(); mMainPanel.setPaddingRelative(0, 0, 0, 0); - int lastGroupId = -1; + int availableWidth = toolbarWidth; boolean isFirstItem = true; while (!remainingMenuItems.isEmpty()) { - final MenuItem menuItem = remainingMenuItems.peek(); - + ToolbarMenuItem menuItem = remainingMenuItems.peek(); // if this is the first item, regardless of requiresOverflow(), it should be // displayed on the main panel. Otherwise all items including this one will be // overflow items, and should be displayed in overflow panel. - if (!isFirstItem && menuItem.requiresOverflow()) { + if (!isFirstItem && menuItem.getPriority() == ToolbarMenuItem.PRIORITY_OVERFLOW) { break; } - final boolean showIcon = isFirstItem && menuItem.getItemId() == R.id.textAssist; final View menuItemButton = createMenuItemButton( mContext, menuItem, mIconTextSpacing, showIcon); if (!showIcon && menuItemButton instanceof LinearLayout) { ((LinearLayout) menuItemButton).setGravity(Gravity.CENTER); } - // Adding additional start padding for the first button to even out button spacing. if (isFirstItem) { menuItemButton.setPaddingRelative( @@ -995,7 +829,6 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { menuItemButton.getPaddingEnd(), menuItemButton.getPaddingBottom()); } - // Adding additional end padding for the last button to even out button spacing. boolean isLastItem = remainingMenuItems.size() == 1; if (isLastItem) { @@ -1005,18 +838,17 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { (int) (1.5 * menuItemButton.getPaddingEnd()), menuItemButton.getPaddingBottom()); } - - menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + menuItemButton.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); final int menuItemButtonWidth = Math.min( menuItemButton.getMeasuredWidth(), toolbarWidth); - // Check if we can fit an item while reserving space for the overflowButton. final boolean canFitWithOverflow = menuItemButtonWidth <= availableWidth - mOverflowButtonSize.getWidth(); final boolean canFitNoOverflow = isLastItem && menuItemButtonWidth <= availableWidth; if (canFitWithOverflow || canFitNoOverflow) { - setButtonTagAndClickListener(menuItemButton, menuItem); + menuItemButton.setTag(menuItem); + menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener); // Set tooltips for main panel items, but not overflow items (b/35726766). menuItemButton.setTooltipText(menuItem.getTooltipText()); mMainPanel.addView(menuItemButton); @@ -1028,22 +860,20 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { } else { break; } - lastGroupId = menuItem.getGroupId(); isFirstItem = false; } - if (!remainingMenuItems.isEmpty()) { // Reserve space for overflowButton. mMainPanel.setPaddingRelative(0, 0, mOverflowButtonSize.getWidth(), 0); } - mMainPanelSize = measure(mMainPanel); + return remainingMenuItems; } - private void layoutOverflowPanelItems(List<MenuItem> menuItems) { - ArrayAdapter<MenuItem> overflowPanelAdapter = - (ArrayAdapter<MenuItem>) mOverflowPanel.getAdapter(); + private void layoutOverflowPanelItems(List<ToolbarMenuItem> menuItems) { + ArrayAdapter<ToolbarMenuItem> overflowPanelAdapter = + (ArrayAdapter<ToolbarMenuItem>) mOverflowPanel.getAdapter(); overflowPanelAdapter.clear(); final int size = menuItems.size(); for (int i = 0; i < size; i++) { @@ -1055,7 +885,6 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { } else { mOverflowPanel.setY(mOverflowButtonSize.getHeight()); } - int width = Math.max(getOverflowWidth(), mOverflowButtonSize.getWidth()); int height = calculateOverflowHeight(MAX_OVERFLOW_SIZE); mOverflowPanelSize = new Size(width, height); @@ -1067,7 +896,6 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { */ private void preparePopupContent() { mContentContainer.removeAllViews(); - // Add views in the specified order so they stack up as expected. // Order: overflowPanel, mainPanel, overflowButton. if (hasOverflow()) { @@ -1078,7 +906,6 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { mContentContainer.addView(mOverflowButton); } setPanelsStatesAtRestingPosition(); - setContentAreaAsTouchableSurface(); // The positioning of contents in RTL is wrong when the view is first rendered. // Hide the view and post a runnable to recalculate positions and render the view. @@ -1093,12 +920,12 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { * Clears out the panels and their container. Resets their calculated sizes. */ private void clearPanels() { - mOverflowPanelSize = null; - mMainPanelSize = null; mIsOverflowOpen = false; + mMainPanelSize = null; mMainPanel.removeAllViews(); - ArrayAdapter<MenuItem> overflowPanelAdapter = - (ArrayAdapter<MenuItem>) mOverflowPanel.getAdapter(); + mOverflowPanelSize = null; + ArrayAdapter<ToolbarMenuItem> overflowPanelAdapter = + (ArrayAdapter<ToolbarMenuItem>) mOverflowPanel.getAdapter(); overflowPanelAdapter.clear(); mOverflowPanel.setAdapter(overflowPanelAdapter); mContentContainer.removeAllViews(); @@ -1116,7 +943,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { int overflowWidth = 0; final int count = mOverflowPanel.getAdapter().getCount(); for (int i = 0; i < count; i++) { - MenuItem menuItem = (MenuItem) mOverflowPanel.getAdapter().getItem(i); + ToolbarMenuItem menuItem = (ToolbarMenuItem) mOverflowPanel.getAdapter().getItem(i); overflowWidth = Math.max(mOverflowPanelViewHelper.calculateWidth(menuItem), overflowWidth); } @@ -1141,29 +968,24 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { + extension; } - private void setButtonTagAndClickListener(View menuItemButton, MenuItem menuItem) { - menuItemButton.setTag(MenuItemRepr.of(menuItem)); - menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener); - } - /** * NOTE: Use only in android.view.animation.* animations. Do not use in android.animation.* * animations. See comment about this in the code. */ - private int getAdjustedDuration(int originalDuration) { + private int getAnimationDuration() { if (mTransitionDurationScale < 150) { // For smaller transition, decrease the time. - return Math.max(originalDuration - 50, 0); + return 200; } else if (mTransitionDurationScale > 300) { // For bigger transition, increase the time. - return originalDuration + 50; + return 300; } // Scale the animation duration with getDurationScale(). This allows // android.view.animation.* animations to scale just like android.animation.* animations // when animator duration scale is adjusted in "Developer Options". // For this reason, do not use this method for android.animation.* animations. - return (int) (originalDuration * ValueAnimator.getDurationScale()); + return (int) (250 * ValueAnimator.getDurationScale()); } private void maybeComputeTransitionDurationScale() { @@ -1176,7 +998,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { } private ViewGroup createMainPanel() { - ViewGroup mainPanel = new LinearLayout(mContext) { + return new LinearLayout(mContext) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (isOverflowAnimating()) { @@ -1195,7 +1017,6 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { return isOverflowAnimating(); } }; - return mainPanel; } private ImageButton createOverflowButton() { @@ -1203,6 +1024,12 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { .inflate(R.layout.floating_popup_overflow_button, null); overflowButton.setImageDrawable(mOverflow); overflowButton.setOnClickListener(v -> { + if (isShowing()) { + preparePopupContent(); + WidgetInfo widgetInfo = createWidgetInfo(); + mSurfaceControlViewHost.relayout(mPopupWidth, mPopupHeight); + mCallbackWrapper.onWidgetUpdated(widgetInfo); + } if (mIsOverflowOpen) { overflowButton.setImageDrawable(mToOverflow); mToOverflow.start(); @@ -1224,7 +1051,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { overflowPanel.setDividerHeight(0); final ArrayAdapter adapter = - new ArrayAdapter<MenuItem>(mContext, 0) { + new ArrayAdapter<ToolbarMenuItem>(mContext, 0) { @Override public View getView(int position, View convertView, ViewGroup parent) { return mOverflowPanelViewHelper.getView( @@ -1232,14 +1059,11 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { } }; overflowPanel.setAdapter(adapter); - overflowPanel.setOnItemClickListener((parent, view, position, id) -> { - MenuItem menuItem = (MenuItem) overflowPanel.getAdapter().getItem(position); - if (mOnMenuItemClickListener != null) { - mOnMenuItemClickListener.onMenuItemClick(menuItem); - } + ToolbarMenuItem menuItem = + (ToolbarMenuItem) overflowPanel.getAdapter().getItem(position); + mCallbackWrapper.onMenuItemClicked(menuItem); }); - return overflowPanel; } @@ -1252,7 +1076,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { } private Animation.AnimationListener createOverflowAnimationListener() { - Animation.AnimationListener listener = new Animation.AnimationListener() { + return new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { // Disable the overflow button while it's animating. @@ -1270,7 +1094,6 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { // actually ends. mContentContainer.post(() -> { setPanelsStatesAtRestingPosition(); - setContentAreaAsTouchableSurface(); }); } @@ -1278,12 +1101,11 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { public void onAnimationRepeat(Animation animation) { } }; - return listener; } private static Size measure(View view) { Preconditions.checkState(view.getParent() == null); - view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); return new Size(view.getMeasuredWidth(), view.getMeasuredHeight()); } @@ -1372,13 +1194,11 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { * A helper for generating views for the overflow panel. */ private static final class OverflowPanelViewHelper { - + private final Context mContext; private final View mCalculator; private final int mIconTextSpacing; private final int mSidePadding; - private final Context mContext; - OverflowPanelViewHelper(Context context, int iconTextSpacing) { mContext = Objects.requireNonNull(context); mIconTextSpacing = iconTextSpacing; @@ -1387,7 +1207,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { mCalculator = createMenuButton(null); } - public View getView(MenuItem menuItem, int minimumWidth, View convertView) { + public View getView(ToolbarMenuItem menuItem, int minimumWidth, View convertView) { Objects.requireNonNull(menuItem); if (convertView != null) { updateMenuItemButton( @@ -1399,7 +1219,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { return convertView; } - public int calculateWidth(MenuItem menuItem) { + public int calculateWidth(ToolbarMenuItem menuItem) { updateMenuItemButton( mCalculator, menuItem, mIconTextSpacing, shouldShowIcon(menuItem)); mCalculator.measure( @@ -1407,18 +1227,18 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { return mCalculator.getMeasuredWidth(); } - private View createMenuButton(MenuItem menuItem) { + private View createMenuButton(ToolbarMenuItem menuItem) { View button = createMenuItemButton( mContext, menuItem, mIconTextSpacing, shouldShowIcon(menuItem)); button.setPadding(mSidePadding, 0, mSidePadding, 0); return button; } - private boolean shouldShowIcon(MenuItem menuItem) { + private boolean shouldShowIcon(ToolbarMenuItem menuItem) { if (menuItem != null) { return menuItem.getGroupId() == android.R.id.textAssist; } - return false; + return false; } } @@ -1426,7 +1246,7 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { * Creates and returns a menu button for the specified menu item. */ private static View createMenuItemButton( - Context context, MenuItem menuItem, int iconTextSpacing, boolean showIcon) { + Context context, ToolbarMenuItem menuItem, int iconTextSpacing, boolean showIcon) { final View menuItemButton = LayoutInflater.from(context) .inflate(R.layout.floating_popup_menu_button, null); if (menuItem != null) { @@ -1438,8 +1258,8 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { /** * Updates the specified menu item button with the specified menu item data. */ - private static void updateMenuItemButton( - View menuItemButton, MenuItem menuItem, int iconTextSpacing, boolean showIcon) { + private static void updateMenuItemButton(View menuItemButton, ToolbarMenuItem menuItem, + int iconTextSpacing, boolean showIcon) { final TextView buttonText = menuItemButton.findViewById( R.id.floating_toolbar_menu_item_text); buttonText.setEllipsize(null); @@ -1453,15 +1273,12 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { R.id.floating_toolbar_menu_item_image); if (menuItem.getIcon() == null || !showIcon) { buttonIcon.setVisibility(View.GONE); - if (buttonText != null) { - buttonText.setPaddingRelative(0, 0, 0, 0); - } + buttonText.setPaddingRelative(0, 0, 0, 0); } else { buttonIcon.setVisibility(View.VISIBLE); - buttonIcon.setImageDrawable(menuItem.getIcon()); - if (buttonText != null) { - buttonText.setPaddingRelative(iconTextSpacing, 0, 0, 0); - } + buttonIcon.setImageDrawable( + menuItem.getIcon().loadDrawable(menuItemButton.getContext())); + buttonText.setPaddingRelative(iconTextSpacing, 0, 0, 0); } final CharSequence contentDescription = menuItem.getContentDescription(); if (TextUtils.isEmpty(contentDescription)) { @@ -1476,27 +1293,11 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { .inflate(R.layout.floating_popup_container, null); contentContainer.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - contentContainer.setTag("floating_toolbar"); + contentContainer.setTag(FloatingToolbar.FLOATING_TOOLBAR_TAG); contentContainer.setClipToOutline(true); return contentContainer; } - private static PopupWindow createPopupWindow(ViewGroup content) { - ViewGroup popupContentHolder = new LinearLayout(content.getContext()); - PopupWindow popupWindow = new PopupWindow(popupContentHolder); - // TODO: Use .setIsLaidOutInScreen(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); - popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); - content.setLayoutParams(new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - popupContentHolder.addView(content); - return popupWindow; - } - /** * Creates an "appear" animation for the specified view. * @@ -1522,7 +1323,9 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { animation.playTogether( ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100)); animation.setStartDelay(startDelay); - animation.addListener(listener); + if (listener != null) { + animation.addListener(listener); + } return animation; } @@ -1538,82 +1341,9 @@ final class RemoteSelectionToolbar implements FloatingToolbarPopup { return new ContextThemeWrapper(originalContext, themeId); } - /** - * Represents the identity of a MenuItem that is rendered in a FloatingToolbarPopup. - */ - @VisibleForTesting - public static final class MenuItemRepr { - - public final int itemId; - public final int groupId; - @Nullable public final String title; - @Nullable private final Drawable mIcon; - - private MenuItemRepr( - int itemId, int groupId, @Nullable CharSequence title, @Nullable Drawable icon) { - this.itemId = itemId; - this.groupId = groupId; - this.title = (title == null) ? null : title.toString(); - mIcon = icon; - } - - /** - * Creates an instance of MenuItemRepr for the specified menu item. - */ - public static MenuItemRepr of(MenuItem menuItem) { - return new MenuItemRepr( - menuItem.getItemId(), - menuItem.getGroupId(), - menuItem.getTitle(), - menuItem.getIcon()); - } - - /** - * Returns this object's hashcode. - */ - @Override - public int hashCode() { - return Objects.hash(itemId, groupId, title, mIcon); - } - - /** - * Returns true if this object is the same as the specified object. - */ - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof MenuItemRepr)) { - return false; - } - final MenuItemRepr other = (MenuItemRepr) o; - return itemId == other.itemId - && groupId == other.groupId - && TextUtils.equals(title, other.title) - // Many Drawables (icons) do not implement equals(). Using equals() here instead - // of reference comparisons in case a Drawable subclass implements equals(). - && Objects.equals(mIcon, other.mIcon); - } - - /** - * Returns true if the two menu item collections are the same based on MenuItemRepr. - */ - public static boolean reprEquals( - Collection<MenuItem> menuItems1, Collection<MenuItem> menuItems2) { - if (menuItems1.size() != menuItems2.size()) { - return false; - } - - final Iterator<MenuItem> menuItems2Iter = menuItems2.iterator(); - for (MenuItem menuItem1 : menuItems1) { - final MenuItem menuItem2 = menuItems2Iter.next(); - if (!MenuItemRepr.of(menuItem1).equals(MenuItemRepr.of(menuItem2))) { - return false; - } - } - - return true; + private static void debugLog(String message) { + if (Log.isLoggable(FloatingToolbar.FLOATING_TOOLBAR_TAG, Log.DEBUG)) { + Log.v(TAG, message); } } } diff --git a/core/java/android/service/selectiontoolbar/SelectionToolbarRenderCallback.java b/core/java/android/service/selectiontoolbar/SelectionToolbarRenderCallback.java index 6468183880f4..a10b6a8ac8cb 100644 --- a/core/java/android/service/selectiontoolbar/SelectionToolbarRenderCallback.java +++ b/core/java/android/service/selectiontoolbar/SelectionToolbarRenderCallback.java @@ -31,14 +31,6 @@ public interface SelectionToolbarRenderCallback { */ void onShown(WidgetInfo widgetInfo); /** - * The selection toolbar is hidden. - */ - void onHidden(long widgetToken); - /** - * The selection toolbar is dismissed. - */ - void onDismissed(long widgetToken); - /** * The selection toolbar has changed. */ void onWidgetUpdated(WidgetInfo info); @@ -47,6 +39,10 @@ public interface SelectionToolbarRenderCallback { */ void onMenuItemClicked(ToolbarMenuItem item); /** + * The toolbar doesn't be dismissed after showing on a given timeout. + */ + void onToolbarShowTimeout(); + /** * The error occurred when operating on the selection toolbar. */ void onError(int errorCode); diff --git a/core/java/android/service/selectiontoolbar/SelectionToolbarRenderService.java b/core/java/android/service/selectiontoolbar/SelectionToolbarRenderService.java index 6f66c9f1ed3a..f33feaec6dde 100644 --- a/core/java/android/service/selectiontoolbar/SelectionToolbarRenderService.java +++ b/core/java/android/service/selectiontoolbar/SelectionToolbarRenderService.java @@ -28,6 +28,8 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import android.util.Pair; +import android.util.SparseArray; import android.view.selectiontoolbar.ISelectionToolbarCallback; import android.view.selectiontoolbar.ShowInfo; import android.view.selectiontoolbar.ToolbarMenuItem; @@ -42,6 +44,10 @@ public abstract class SelectionToolbarRenderService extends Service { private static final String TAG = "SelectionToolbarRenderService"; + // TODO(b/215497659): read from DeviceConfig + // The timeout to clean the cache if the client forgot to call dismiss() + private static final int CACHE_CLEAN_AFTER_SHOW_TIMEOUT_IN_MS = 10 * 60 * 1000; // 10 minutes + /** * The {@link Intent} that must be declared as handled by the service. * @@ -53,6 +59,10 @@ public abstract class SelectionToolbarRenderService extends Service { "android.service.selectiontoolbar.SelectionToolbarRenderService"; private Handler mHandler; + private ISelectionToolbarRenderServiceCallback mServiceCallback; + + private final SparseArray<Pair<RemoteCallbackWrapper, CleanCacheRunnable>> mCache = + new SparseArray<>(); /** * Binder to receive calls from system server. @@ -61,10 +71,18 @@ public abstract class SelectionToolbarRenderService extends Service { new ISelectionToolbarRenderService.Stub() { @Override - public void onShow(ShowInfo showInfo, ISelectionToolbarCallback callback) { + public void onShow(int callingUid, ShowInfo showInfo, ISelectionToolbarCallback callback) { + if (mCache.indexOfKey(callingUid) < 0) { + mCache.put(callingUid, new Pair<>(new RemoteCallbackWrapper(callback), + new CleanCacheRunnable(callingUid))); + } + Pair<RemoteCallbackWrapper, CleanCacheRunnable> toolbarPair = mCache.get(callingUid); + CleanCacheRunnable cleanRunnable = toolbarPair.second; + mHandler.removeCallbacks(cleanRunnable); mHandler.sendMessage(obtainMessage(SelectionToolbarRenderService::onShow, - SelectionToolbarRenderService.this, showInfo, - new RemoteCallbackWrapper(callback))); + SelectionToolbarRenderService.this, callingUid, showInfo, + toolbarPair.first)); + mHandler.postDelayed(cleanRunnable, CACHE_CLEAN_AFTER_SHOW_TIMEOUT_IN_MS); } @Override @@ -74,9 +92,20 @@ public abstract class SelectionToolbarRenderService extends Service { } @Override - public void onDismiss(long widgetToken) { + public void onDismiss(int callingUid, long widgetToken) { mHandler.sendMessage(obtainMessage(SelectionToolbarRenderService::onDismiss, SelectionToolbarRenderService.this, widgetToken)); + Pair<RemoteCallbackWrapper, CleanCacheRunnable> toolbarPair = mCache.get(callingUid); + if (toolbarPair != null) { + mHandler.removeCallbacks(toolbarPair.second); + mCache.remove(callingUid); + } + } + + @Override + public void onConnected(IBinder callback) { + mHandler.sendMessage(obtainMessage(SelectionToolbarRenderService::handleOnConnected, + SelectionToolbarRenderService.this, callback)); } }; @@ -97,11 +126,28 @@ public abstract class SelectionToolbarRenderService extends Service { return null; } + private void handleOnConnected(@NonNull IBinder callback) { + mServiceCallback = ISelectionToolbarRenderServiceCallback.Stub.asInterface(callback); + } + + protected void transferTouch(@NonNull IBinder source, @NonNull IBinder target) { + final ISelectionToolbarRenderServiceCallback callback = mServiceCallback; + if (callback == null) { + Log.e(TAG, "transferTouch(): no server callback"); + return; + } + try { + callback.transferTouch(source, target); + } catch (RemoteException e) { + // no-op + } + } /** * Called when showing the selection toolbar. */ - public abstract void onShow(ShowInfo showInfo, RemoteCallbackWrapper callbackWrapper); + public abstract void onShow(int callingUid, ShowInfo showInfo, + RemoteCallbackWrapper callbackWrapper); /** * Called when hiding the selection toolbar. @@ -115,13 +161,22 @@ public abstract class SelectionToolbarRenderService extends Service { public abstract void onDismiss(long widgetToken); /** - * Add avadoc. + * Called when showing the selection toolbar for a specific timeout. This avoids the client + * forgot to call dismiss to clean the state. + */ + public void onToolbarShowTimeout(int callingUid) { + // no-op + } + + /** + * Callback to notify the client toolbar events. */ public static final class RemoteCallbackWrapper implements SelectionToolbarRenderCallback { private final ISelectionToolbarCallback mRemoteCallback; RemoteCallbackWrapper(ISelectionToolbarCallback remoteCallback) { + // TODO(b/215497659): handle if the binder dies. mRemoteCallback = remoteCallback; } @@ -130,25 +185,16 @@ public abstract class SelectionToolbarRenderService extends Service { try { mRemoteCallback.onShown(widgetInfo); } catch (RemoteException e) { - e.rethrowAsRuntimeException(); + // no-op } } @Override - public void onHidden(long widgetToken) { + public void onToolbarShowTimeout() { try { - mRemoteCallback.onHidden(widgetToken); + mRemoteCallback.onToolbarShowTimeout(); } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - @Override - public void onDismissed(long widgetToken) { - try { - mRemoteCallback.onDismissed(widgetToken); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); + // no-op } } @@ -157,7 +203,7 @@ public abstract class SelectionToolbarRenderService extends Service { try { mRemoteCallback.onWidgetUpdated(widgetInfo); } catch (RemoteException e) { - e.rethrowAsRuntimeException(); + // no-op } } @@ -166,7 +212,7 @@ public abstract class SelectionToolbarRenderService extends Service { try { mRemoteCallback.onMenuItemClicked(item); } catch (RemoteException e) { - e.rethrowAsRuntimeException(); + // no-op } } @@ -175,8 +221,37 @@ public abstract class SelectionToolbarRenderService extends Service { try { mRemoteCallback.onError(errorCode); } catch (RemoteException e) { - e.rethrowAsRuntimeException(); + // no-op } } } + + private class CleanCacheRunnable implements Runnable { + + int mCleanUid; + + CleanCacheRunnable(int cleanUid) { + mCleanUid = cleanUid; + } + + @Override + public void run() { + Pair<RemoteCallbackWrapper, CleanCacheRunnable> toolbarPair = mCache.get(mCleanUid); + if (toolbarPair != null) { + Log.w(TAG, "CleanCacheRunnable: remove " + mCleanUid + " from cache."); + mCache.remove(mCleanUid); + onToolbarShowTimeout(mCleanUid); + } + } + } + + /** + * A listener to notify the service to the transfer touch focus. + */ + public interface TransferTouchListener { + /** + * Notify the service to transfer the touch focus. + */ + void onTransferTouch(IBinder source, IBinder target); + } } diff --git a/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl b/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl index 48af7b96b195..aaeb12012f68 100644 --- a/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl +++ b/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl @@ -25,9 +25,8 @@ import android.view.selectiontoolbar.WidgetInfo; */ oneway interface ISelectionToolbarCallback { void onShown(in WidgetInfo info); - void onHidden(long widgetToken); - void onDismissed(long widgetToken); void onWidgetUpdated(in WidgetInfo info); + void onToolbarShowTimeout(); void onMenuItemClicked(in ToolbarMenuItem item); void onError(int errorCode); } diff --git a/core/java/android/view/selectiontoolbar/SelectionContext.java b/core/java/android/view/selectiontoolbar/SelectionContext.java deleted file mode 100644 index 21b8d8f11d25..000000000000 --- a/core/java/android/view/selectiontoolbar/SelectionContext.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.view.selectiontoolbar; - -import android.annotation.NonNull; -import android.os.Parcelable; - -import com.android.internal.util.DataClass; - -/** - * The class holds information for a selection. - * - * @hide - */ -@DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true) -public final class SelectionContext implements Parcelable { - - /** - * The start index of a selection. - */ - private final int mStartIndex; - - /** - * The end index of a selection. - */ - private final int mEndIndex; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/selectiontoolbar/SelectionContext.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - /* package-private */ SelectionContext( - int startIndex, - int endIndex) { - this.mStartIndex = startIndex; - this.mEndIndex = endIndex; - - // onConstructed(); // You can define this method to get a callback - } - - /** - * The start index of a selection. - */ - @DataClass.Generated.Member - public int getStartIndex() { - return mStartIndex; - } - - /** - * The end index of a selection. - */ - @DataClass.Generated.Member - public int getEndIndex() { - return mEndIndex; - } - - @Override - @DataClass.Generated.Member - public String toString() { - // You can override field toString logic by defining methods like: - // String fieldNameToString() { ... } - - return "SelectionContext { " + - "startIndex = " + mStartIndex + ", " + - "endIndex = " + mEndIndex + - " }"; - } - - @Override - @DataClass.Generated.Member - public boolean equals(@android.annotation.Nullable Object o) { - // You can override field equality logic by defining either of the methods like: - // boolean fieldNameEquals(SelectionContext other) { ... } - // boolean fieldNameEquals(FieldType otherValue) { ... } - - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - @SuppressWarnings("unchecked") - SelectionContext that = (SelectionContext) o; - //noinspection PointlessBooleanExpression - return true - && mStartIndex == that.mStartIndex - && mEndIndex == that.mEndIndex; - } - - @Override - @DataClass.Generated.Member - public int hashCode() { - // You can override field hashCode logic by defining methods like: - // int fieldNameHashCode() { ... } - - int _hash = 1; - _hash = 31 * _hash + mStartIndex; - _hash = 31 * _hash + mEndIndex; - return _hash; - } - - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - dest.writeInt(mStartIndex); - dest.writeInt(mEndIndex); - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - /* package-private */ SelectionContext(@NonNull android.os.Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - int startIndex = in.readInt(); - int endIndex = in.readInt(); - - this.mStartIndex = startIndex; - this.mEndIndex = endIndex; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator<SelectionContext> CREATOR - = new Parcelable.Creator<SelectionContext>() { - @Override - public SelectionContext[] newArray(int size) { - return new SelectionContext[size]; - } - - @Override - public SelectionContext createFromParcel(@NonNull android.os.Parcel in) { - return new SelectionContext(in); - } - }; - - /** - * A builder for {@link SelectionContext} - */ - @SuppressWarnings("WeakerAccess") - @DataClass.Generated.Member - public static final class Builder { - - private int mStartIndex; - private int mEndIndex; - - private long mBuilderFieldsSet = 0L; - - /** - * Creates a new Builder. - * - * @param startIndex - * The start index of a selection. - * @param endIndex - * The end index of a selection. - */ - public Builder( - int startIndex, - int endIndex) { - mStartIndex = startIndex; - mEndIndex = endIndex; - } - - /** - * The start index of a selection. - */ - @DataClass.Generated.Member - public @NonNull Builder setStartIndex(int value) { - checkNotUsed(); - mBuilderFieldsSet |= 0x1; - mStartIndex = value; - return this; - } - - /** - * The end index of a selection. - */ - @DataClass.Generated.Member - public @NonNull Builder setEndIndex(int value) { - checkNotUsed(); - mBuilderFieldsSet |= 0x2; - mEndIndex = value; - return this; - } - - /** Builds the instance. This builder should not be touched after calling this! */ - public @NonNull SelectionContext build() { - checkNotUsed(); - mBuilderFieldsSet |= 0x4; // Mark builder used - - SelectionContext o = new SelectionContext( - mStartIndex, - mEndIndex); - return o; - } - - private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x4) != 0) { - throw new IllegalStateException( - "This Builder should not be reused. Use a new Builder instance instead"); - } - } - } - - @DataClass.Generated( - time = 1639488292248L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/SelectionContext.java", - inputSignatures = "private final int mStartIndex\nprivate final int mEndIndex\nclass SelectionContext extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java index ba45b85e08a3..6de031628768 100644 --- a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java +++ b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java @@ -47,6 +47,16 @@ public final class SelectionToolbarManager { private static final String REMOTE_SELECTION_TOOLBAR_ENABLED = "remote_selection_toolbar_enabled"; + /** + * Used to mark a toolbar that has no toolbar token id. + */ + public static final long NO_TOOLBAR_ID = 0; + + /** + * The error code that do not allow to create multiple toolbar. + */ + public static final int ERROR_DO_NOT_ALLOW_MULTIPLE_TOOL_BAR = 1; + @NonNull private final Context mContext; private final ISelectionToolbarManager mService; diff --git a/core/java/android/view/selectiontoolbar/ShowInfo.java b/core/java/android/view/selectiontoolbar/ShowInfo.java index bbbd5c0df0b4..594b6bc7400a 100644 --- a/core/java/android/view/selectiontoolbar/ShowInfo.java +++ b/core/java/android/view/selectiontoolbar/ShowInfo.java @@ -17,10 +17,14 @@ package android.view.selectiontoolbar; import android.annotation.NonNull; +import android.graphics.Rect; +import android.os.IBinder; import android.os.Parcelable; import com.android.internal.util.DataClass; +import java.util.List; + /** * The class holds menu information for render service to render the selection toolbar. @@ -29,14 +33,47 @@ import com.android.internal.util.DataClass; */ @DataClass(genToString = true, genEqualsHashCode = true) public final class ShowInfo implements Parcelable { + /** * The token that is used to identify the selection toolbar. This is initially set to 0 * until a selection toolbar has been created for the showToolbar request. */ private final long mWidgetToken; - // TODO: add members when the code really uses it + /** + * If the toolbar menu items need to be re-layout. + */ + private final boolean mLayoutRequired; + /** + * The menu items to be rendered in the selection toolbar. + */ + @NonNull + private final List<ToolbarMenuItem> mMenuItems; + + /** + * A rect specifying where the selection toolbar on the screen. + */ + @NonNull + private final Rect mContentRect; + + /** + * A recommended maximum suggested width of the selection toolbar. + */ + private final int mSuggestedWidth; + + /** + * The portion of the screen that is available to the selection toolbar. + */ + @NonNull + private final Rect mViewPortOnScreen; + + /** + * The host application's input token, this allows the remote render service to transfer + * the touch focus to the host application. + */ + @NonNull + private final IBinder mHostInputToken; @@ -57,24 +94,108 @@ public final class ShowInfo implements Parcelable { * Creates a new ShowInfo. * * @param widgetToken - * The token that is used to identify the selection toolbar. + * The token that is used to identify the selection toolbar. This is initially set to 0 + * until a selection toolbar has been created for the showToolbar request. + * @param layoutRequired + * If the toolbar menu items need to be re-layout. + * @param menuItems + * The menu items to be rendered in the selection toolbar. + * @param contentRect + * A rect specifying where the selection toolbar on the screen. + * @param suggestedWidth + * A recommended maximum suggested width of the selection toolbar. + * @param viewPortOnScreen + * The portion of the screen that is available to the selection toolbar. + * @param hostInputToken + * The host application's input token, this allows the remote render service to transfer + * the touch focus to the host application. */ @DataClass.Generated.Member public ShowInfo( - long widgetToken) { + long widgetToken, + boolean layoutRequired, + @NonNull List<ToolbarMenuItem> menuItems, + @NonNull Rect contentRect, + int suggestedWidth, + @NonNull Rect viewPortOnScreen, + @NonNull IBinder hostInputToken) { this.mWidgetToken = widgetToken; + this.mLayoutRequired = layoutRequired; + this.mMenuItems = menuItems; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMenuItems); + this.mContentRect = contentRect; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mContentRect); + this.mSuggestedWidth = suggestedWidth; + this.mViewPortOnScreen = viewPortOnScreen; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mViewPortOnScreen); + this.mHostInputToken = hostInputToken; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHostInputToken); // onConstructed(); // You can define this method to get a callback } /** - * The token that is used to identify the selection toolbar. + * The token that is used to identify the selection toolbar. This is initially set to 0 + * until a selection toolbar has been created for the showToolbar request. */ @DataClass.Generated.Member public long getWidgetToken() { return mWidgetToken; } + /** + * If the toolbar menu items need to be re-layout. + */ + @DataClass.Generated.Member + public boolean isLayoutRequired() { + return mLayoutRequired; + } + + /** + * The menu items to be rendered in the selection toolbar. + */ + @DataClass.Generated.Member + public @NonNull List<ToolbarMenuItem> getMenuItems() { + return mMenuItems; + } + + /** + * A rect specifying where the selection toolbar on the screen. + */ + @DataClass.Generated.Member + public @NonNull Rect getContentRect() { + return mContentRect; + } + + /** + * A recommended maximum suggested width of the selection toolbar. + */ + @DataClass.Generated.Member + public int getSuggestedWidth() { + return mSuggestedWidth; + } + + /** + * The portion of the screen that is available to the selection toolbar. + */ + @DataClass.Generated.Member + public @NonNull Rect getViewPortOnScreen() { + return mViewPortOnScreen; + } + + /** + * The host application's input token, this allows the remote render service to transfer + * the touch focus to the host application. + */ + @DataClass.Generated.Member + public @NonNull IBinder getHostInputToken() { + return mHostInputToken; + } + @Override @DataClass.Generated.Member public String toString() { @@ -82,7 +203,13 @@ public final class ShowInfo implements Parcelable { // String fieldNameToString() { ... } return "ShowInfo { " + - "widgetToken = " + mWidgetToken + + "widgetToken = " + mWidgetToken + ", " + + "layoutRequired = " + mLayoutRequired + ", " + + "menuItems = " + mMenuItems + ", " + + "contentRect = " + mContentRect + ", " + + "suggestedWidth = " + mSuggestedWidth + ", " + + "viewPortOnScreen = " + mViewPortOnScreen + ", " + + "hostInputToken = " + mHostInputToken + " }"; } @@ -99,7 +226,13 @@ public final class ShowInfo implements Parcelable { ShowInfo that = (ShowInfo) o; //noinspection PointlessBooleanExpression return true - && mWidgetToken == that.mWidgetToken; + && mWidgetToken == that.mWidgetToken + && mLayoutRequired == that.mLayoutRequired + && java.util.Objects.equals(mMenuItems, that.mMenuItems) + && java.util.Objects.equals(mContentRect, that.mContentRect) + && mSuggestedWidth == that.mSuggestedWidth + && java.util.Objects.equals(mViewPortOnScreen, that.mViewPortOnScreen) + && java.util.Objects.equals(mHostInputToken, that.mHostInputToken); } @Override @@ -110,6 +243,12 @@ public final class ShowInfo implements Parcelable { int _hash = 1; _hash = 31 * _hash + Long.hashCode(mWidgetToken); + _hash = 31 * _hash + Boolean.hashCode(mLayoutRequired); + _hash = 31 * _hash + java.util.Objects.hashCode(mMenuItems); + _hash = 31 * _hash + java.util.Objects.hashCode(mContentRect); + _hash = 31 * _hash + mSuggestedWidth; + _hash = 31 * _hash + java.util.Objects.hashCode(mViewPortOnScreen); + _hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken); return _hash; } @@ -119,7 +258,15 @@ public final class ShowInfo implements Parcelable { // You can override field parcelling by defining methods like: // void parcelFieldName(Parcel dest, int flags) { ... } + byte flg = 0; + if (mLayoutRequired) flg |= 0x2; + dest.writeByte(flg); dest.writeLong(mWidgetToken); + dest.writeParcelableList(mMenuItems, flags); + dest.writeTypedObject(mContentRect, flags); + dest.writeInt(mSuggestedWidth); + dest.writeTypedObject(mViewPortOnScreen, flags); + dest.writeStrongBinder(mHostInputToken); } @Override @@ -133,9 +280,31 @@ public final class ShowInfo implements Parcelable { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } + byte flg = in.readByte(); + boolean layoutRequired = (flg & 0x2) != 0; long widgetToken = in.readLong(); + List<ToolbarMenuItem> menuItems = new java.util.ArrayList<>(); + in.readParcelableList(menuItems, ToolbarMenuItem.class.getClassLoader()); + Rect contentRect = (Rect) in.readTypedObject(Rect.CREATOR); + int suggestedWidth = in.readInt(); + Rect viewPortOnScreen = (Rect) in.readTypedObject(Rect.CREATOR); + IBinder hostInputToken = (IBinder) in.readStrongBinder(); this.mWidgetToken = widgetToken; + this.mLayoutRequired = layoutRequired; + this.mMenuItems = menuItems; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMenuItems); + this.mContentRect = contentRect; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mContentRect); + this.mSuggestedWidth = suggestedWidth; + this.mViewPortOnScreen = viewPortOnScreen; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mViewPortOnScreen); + this.mHostInputToken = hostInputToken; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHostInputToken); // onConstructed(); // You can define this method to get a callback } @@ -155,10 +324,10 @@ public final class ShowInfo implements Parcelable { }; @DataClass.Generated( - time = 1639488262761L, + time = 1643186262604L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/ShowInfo.java", - inputSignatures = "private final long mWidgetToken\nclass ShowInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)") + inputSignatures = "private final long mWidgetToken\nprivate final boolean mLayoutRequired\nprivate final @android.annotation.NonNull java.util.List<android.view.selectiontoolbar.ToolbarMenuItem> mMenuItems\nprivate final @android.annotation.NonNull android.graphics.Rect mContentRect\nprivate final int mSuggestedWidth\nprivate final @android.annotation.NonNull android.graphics.Rect mViewPortOnScreen\nprivate final @android.annotation.NonNull android.os.IBinder mHostInputToken\nclass ShowInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java b/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java index 5af232c7a34d..89347c613310 100644 --- a/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java +++ b/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java @@ -18,7 +18,9 @@ package android.view.selectiontoolbar; import android.annotation.NonNull; import android.annotation.Nullable; +import android.graphics.drawable.Icon; import android.os.Parcelable; +import android.view.MenuItem; import com.android.internal.util.DataClass; @@ -31,10 +33,84 @@ import com.android.internal.util.DataClass; public final class ToolbarMenuItem implements Parcelable { /** + * The priority of menu item is unknown. + */ + public static final int PRIORITY_UNKNOWN = 0; + + /** + * The priority of menu item is shown in primary selection toolbar. + */ + public static final int PRIORITY_PRIMARY = 1; + + /** + * The priority of menu item is shown in overflow selection toolbar. + */ + public static final int PRIORITY_OVERFLOW = 2; + + /** * The id of the menu item. + * + * @see MenuItem#getItemId() */ private final int mItemId; + /** + * The title of the menu item. + * + * @see MenuItem#getTitle() + */ + @NonNull + private final CharSequence mTitle; + + /** + * The content description of the menu item. + * + * @see MenuItem#getContentDescription() + */ + @Nullable + private final CharSequence mContentDescription; + + /** + * The group id of the menu item. + * + * @see MenuItem#getGroupId() + */ + private final int mGroupId; + + /** + * The icon id of the menu item. + * + * @see MenuItem#getIcon() + */ + @Nullable + private final Icon mIcon; + + /** + * The tooltip text of the menu item. + * + * @see MenuItem#getTooltipText() + */ + @Nullable + private final CharSequence mTooltipText; + + /** + * The priority of the menu item used to display the order of the menu item. + */ + private final int mPriority; + + /** + * Returns the priority from a given {@link MenuItem}. + */ + public static int getPriorityFromMenuItem(MenuItem menuItem) { + if (menuItem.requiresActionButton()) { + return PRIORITY_PRIMARY; + } else if (menuItem.requiresOverflow()) { + return PRIORITY_OVERFLOW; + } + return PRIORITY_UNKNOWN; + } + + // Code below generated by codegen v1.0.23. @@ -50,22 +126,118 @@ public final class ToolbarMenuItem implements Parcelable { //@formatter:off + @android.annotation.IntDef(prefix = "PRIORITY_", value = { + PRIORITY_UNKNOWN, + PRIORITY_PRIMARY, + PRIORITY_OVERFLOW + }) + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) + @DataClass.Generated.Member + public @interface Priority {} + + @DataClass.Generated.Member + public static String priorityToString(@Priority int value) { + switch (value) { + case PRIORITY_UNKNOWN: + return "PRIORITY_UNKNOWN"; + case PRIORITY_PRIMARY: + return "PRIORITY_PRIMARY"; + case PRIORITY_OVERFLOW: + return "PRIORITY_OVERFLOW"; + default: return Integer.toHexString(value); + } + } + @DataClass.Generated.Member /* package-private */ ToolbarMenuItem( - int itemId) { + int itemId, + @NonNull CharSequence title, + @Nullable CharSequence contentDescription, + int groupId, + @Nullable Icon icon, + @Nullable CharSequence tooltipText, + int priority) { this.mItemId = itemId; + this.mTitle = title; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTitle); + this.mContentDescription = contentDescription; + this.mGroupId = groupId; + this.mIcon = icon; + this.mTooltipText = tooltipText; + this.mPriority = priority; // onConstructed(); // You can define this method to get a callback } /** * The id of the menu item. + * + * @see MenuItem#getItemId() */ @DataClass.Generated.Member public int getItemId() { return mItemId; } + /** + * The title of the menu item. + * + * @see MenuItem#getTitle() + */ + @DataClass.Generated.Member + public @NonNull CharSequence getTitle() { + return mTitle; + } + + /** + * The content description of the menu item. + * + * @see MenuItem#getContentDescription() + */ + @DataClass.Generated.Member + public @Nullable CharSequence getContentDescription() { + return mContentDescription; + } + + /** + * The group id of the menu item. + * + * @see MenuItem#getGroupId() + */ + @DataClass.Generated.Member + public int getGroupId() { + return mGroupId; + } + + /** + * The icon id of the menu item. + * + * @see MenuItem#getIcon() + */ + @DataClass.Generated.Member + public @Nullable Icon getIcon() { + return mIcon; + } + + /** + * The tooltip text of the menu item. + * + * @see MenuItem#getTooltipText() + */ + @DataClass.Generated.Member + public @Nullable CharSequence getTooltipText() { + return mTooltipText; + } + + /** + * The priority of the menu item used to display the order of the menu item. + */ + @DataClass.Generated.Member + public int getPriority() { + return mPriority; + } + @Override @DataClass.Generated.Member public String toString() { @@ -73,7 +245,13 @@ public final class ToolbarMenuItem implements Parcelable { // String fieldNameToString() { ... } return "ToolbarMenuItem { " + - "itemId = " + mItemId + + "itemId = " + mItemId + ", " + + "title = " + mTitle + ", " + + "contentDescription = " + mContentDescription + ", " + + "groupId = " + mGroupId + ", " + + "icon = " + mIcon + ", " + + "tooltipText = " + mTooltipText + ", " + + "priority = " + mPriority + " }"; } @@ -90,7 +268,13 @@ public final class ToolbarMenuItem implements Parcelable { ToolbarMenuItem that = (ToolbarMenuItem) o; //noinspection PointlessBooleanExpression return true - && mItemId == that.mItemId; + && mItemId == that.mItemId + && java.util.Objects.equals(mTitle, that.mTitle) + && java.util.Objects.equals(mContentDescription, that.mContentDescription) + && mGroupId == that.mGroupId + && java.util.Objects.equals(mIcon, that.mIcon) + && java.util.Objects.equals(mTooltipText, that.mTooltipText) + && mPriority == that.mPriority; } @Override @@ -101,6 +285,12 @@ public final class ToolbarMenuItem implements Parcelable { int _hash = 1; _hash = 31 * _hash + mItemId; + _hash = 31 * _hash + java.util.Objects.hashCode(mTitle); + _hash = 31 * _hash + java.util.Objects.hashCode(mContentDescription); + _hash = 31 * _hash + mGroupId; + _hash = 31 * _hash + java.util.Objects.hashCode(mIcon); + _hash = 31 * _hash + java.util.Objects.hashCode(mTooltipText); + _hash = 31 * _hash + mPriority; return _hash; } @@ -110,7 +300,18 @@ public final class ToolbarMenuItem implements Parcelable { // You can override field parcelling by defining methods like: // void parcelFieldName(Parcel dest, int flags) { ... } + byte flg = 0; + if (mContentDescription != null) flg |= 0x4; + if (mIcon != null) flg |= 0x10; + if (mTooltipText != null) flg |= 0x20; + dest.writeByte(flg); dest.writeInt(mItemId); + dest.writeCharSequence(mTitle); + if (mContentDescription != null) dest.writeCharSequence(mContentDescription); + dest.writeInt(mGroupId); + if (mIcon != null) dest.writeTypedObject(mIcon, flags); + if (mTooltipText != null) dest.writeCharSequence(mTooltipText); + dest.writeInt(mPriority); } @Override @@ -124,9 +325,24 @@ public final class ToolbarMenuItem implements Parcelable { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } + byte flg = in.readByte(); int itemId = in.readInt(); + CharSequence title = (CharSequence) in.readCharSequence(); + CharSequence contentDescription = (flg & 0x4) == 0 ? null : (CharSequence) in.readCharSequence(); + int groupId = in.readInt(); + Icon icon = (flg & 0x10) == 0 ? null : (Icon) in.readTypedObject(Icon.CREATOR); + CharSequence tooltipText = (flg & 0x20) == 0 ? null : (CharSequence) in.readCharSequence(); + int priority = in.readInt(); this.mItemId = itemId; + this.mTitle = title; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTitle); + this.mContentDescription = contentDescription; + this.mGroupId = groupId; + this.mIcon = icon; + this.mTooltipText = tooltipText; + this.mPriority = priority; // onConstructed(); // You can define this method to get a callback } @@ -153,6 +369,12 @@ public final class ToolbarMenuItem implements Parcelable { public static final class Builder { private int mItemId; + private @NonNull CharSequence mTitle; + private @Nullable CharSequence mContentDescription; + private int mGroupId; + private @Nullable Icon mIcon; + private @Nullable CharSequence mTooltipText; + private int mPriority; private long mBuilderFieldsSet = 0L; @@ -161,14 +383,42 @@ public final class ToolbarMenuItem implements Parcelable { * * @param itemId * The id of the menu item. + * @param title + * The title of the menu item. + * @param contentDescription + * The content description of the menu item. + * @param groupId + * The group id of the menu item. + * @param icon + * The icon id of the menu item. + * @param tooltipText + * The tooltip text of the menu item. + * @param priority + * The priority of the menu item used to display the order of the menu item. */ public Builder( - int itemId) { + int itemId, + @NonNull CharSequence title, + @Nullable CharSequence contentDescription, + int groupId, + @Nullable Icon icon, + @Nullable CharSequence tooltipText, + int priority) { mItemId = itemId; + mTitle = title; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTitle); + mContentDescription = contentDescription; + mGroupId = groupId; + mIcon = icon; + mTooltipText = tooltipText; + mPriority = priority; } /** * The id of the menu item. + * + * @see MenuItem#getItemId() */ @DataClass.Generated.Member public @NonNull Builder setItemId(int value) { @@ -178,18 +428,100 @@ public final class ToolbarMenuItem implements Parcelable { return this; } + /** + * The title of the menu item. + * + * @see MenuItem#getTitle() + */ + @DataClass.Generated.Member + public @NonNull Builder setTitle(@NonNull CharSequence value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mTitle = value; + return this; + } + + /** + * The content description of the menu item. + * + * @see MenuItem#getContentDescription() + */ + @DataClass.Generated.Member + public @NonNull Builder setContentDescription(@NonNull CharSequence value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mContentDescription = value; + return this; + } + + /** + * The group id of the menu item. + * + * @see MenuItem#getGroupId() + */ + @DataClass.Generated.Member + public @NonNull Builder setGroupId(int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x8; + mGroupId = value; + return this; + } + + /** + * The icon id of the menu item. + * + * @see MenuItem#getIcon() + */ + @DataClass.Generated.Member + public @NonNull Builder setIcon(@NonNull Icon value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x10; + mIcon = value; + return this; + } + + /** + * The tooltip text of the menu item. + * + * @see MenuItem#getTooltipText() + */ + @DataClass.Generated.Member + public @NonNull Builder setTooltipText(@NonNull CharSequence value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x20; + mTooltipText = value; + return this; + } + + /** + * The priority of the menu item used to display the order of the menu item. + */ + @DataClass.Generated.Member + public @NonNull Builder setPriority(int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x40; + mPriority = value; + return this; + } + /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull ToolbarMenuItem build() { checkNotUsed(); - mBuilderFieldsSet |= 0x2; // Mark builder used + mBuilderFieldsSet |= 0x80; // Mark builder used ToolbarMenuItem o = new ToolbarMenuItem( - mItemId); + mItemId, + mTitle, + mContentDescription, + mGroupId, + mIcon, + mTooltipText, + mPriority); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x2) != 0) { + if ((mBuilderFieldsSet & 0x80) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -197,10 +529,10 @@ public final class ToolbarMenuItem implements Parcelable { } @DataClass.Generated( - time = 1639488328542L, + time = 1643200806234L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java", - inputSignatures = "private final int mItemId\nclass ToolbarMenuItem extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true)") + inputSignatures = "public static final int PRIORITY_UNKNOWN\npublic static final int PRIORITY_PRIMARY\npublic static final int PRIORITY_OVERFLOW\nprivate final int mItemId\nprivate final @android.annotation.NonNull java.lang.CharSequence mTitle\nprivate final @android.annotation.Nullable java.lang.CharSequence mContentDescription\nprivate final int mGroupId\nprivate final @android.annotation.Nullable android.graphics.drawable.Icon mIcon\nprivate final @android.annotation.Nullable java.lang.CharSequence mTooltipText\nprivate final int mPriority\npublic static int getPriorityFromMenuItem(android.view.MenuItem)\nclass ToolbarMenuItem extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/view/selectiontoolbar/WidgetInfo.java b/core/java/android/view/selectiontoolbar/WidgetInfo.java index 961d8ac8e5e0..5d0fd473c914 100644 --- a/core/java/android/view/selectiontoolbar/WidgetInfo.java +++ b/core/java/android/view/selectiontoolbar/WidgetInfo.java @@ -17,7 +17,10 @@ package android.view.selectiontoolbar; import android.annotation.NonNull; +import android.graphics.Rect; +import android.os.Parcel; import android.os.Parcelable; +import android.view.SurfaceControlViewHost; import com.android.internal.util.DataClass; @@ -35,7 +38,18 @@ public final class WidgetInfo implements Parcelable { */ private final long mWidgetToken; - // TODO: add members when the code really uses it + /** + * A Rect that defines the size and positioning of the remote view with respect to + * its host window. + */ + @NonNull + private final Rect mContentRect; + + /** + * The SurfacePackage pointing to the remote view. + */ + @NonNull + private final SurfaceControlViewHost.SurfacePackage mSurfacePackage; @@ -57,11 +71,24 @@ public final class WidgetInfo implements Parcelable { * * @param widgetToken * The token that is used to identify the selection toolbar. + * @param contentRect + * A Rect that defines the size and positioning of the remote view with respect to + * its host window. + * @param surfacePackage + * The SurfacePackage pointing to the remote view. */ @DataClass.Generated.Member public WidgetInfo( - long widgetToken) { + long widgetToken, + @NonNull Rect contentRect, + @NonNull SurfaceControlViewHost.SurfacePackage surfacePackage) { this.mWidgetToken = widgetToken; + this.mContentRect = contentRect; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mContentRect); + this.mSurfacePackage = surfacePackage; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mSurfacePackage); // onConstructed(); // You can define this method to get a callback } @@ -74,6 +101,23 @@ public final class WidgetInfo implements Parcelable { return mWidgetToken; } + /** + * A Rect that defines the size and positioning of the remote view with respect to + * its host window. + */ + @DataClass.Generated.Member + public @NonNull Rect getContentRect() { + return mContentRect; + } + + /** + * The SurfacePackage pointing to the remote view. + */ + @DataClass.Generated.Member + public @NonNull SurfaceControlViewHost.SurfacePackage getSurfacePackage() { + return mSurfacePackage; + } + @Override @DataClass.Generated.Member public String toString() { @@ -81,7 +125,9 @@ public final class WidgetInfo implements Parcelable { // String fieldNameToString() { ... } return "WidgetInfo { " + - "widgetToken = " + mWidgetToken + + "widgetToken = " + mWidgetToken + ", " + + "contentRect = " + mContentRect + ", " + + "surfacePackage = " + mSurfacePackage + " }"; } @@ -98,7 +144,9 @@ public final class WidgetInfo implements Parcelable { WidgetInfo that = (WidgetInfo) o; //noinspection PointlessBooleanExpression return true - && mWidgetToken == that.mWidgetToken; + && mWidgetToken == that.mWidgetToken + && java.util.Objects.equals(mContentRect, that.mContentRect) + && java.util.Objects.equals(mSurfacePackage, that.mSurfacePackage); } @Override @@ -109,16 +157,20 @@ public final class WidgetInfo implements Parcelable { int _hash = 1; _hash = 31 * _hash + Long.hashCode(mWidgetToken); + _hash = 31 * _hash + java.util.Objects.hashCode(mContentRect); + _hash = 31 * _hash + java.util.Objects.hashCode(mSurfacePackage); return _hash; } @Override @DataClass.Generated.Member - public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { // You can override field parcelling by defining methods like: // void parcelFieldName(Parcel dest, int flags) { ... } dest.writeLong(mWidgetToken); + dest.writeTypedObject(mContentRect, flags); + dest.writeTypedObject(mSurfacePackage, flags); } @Override @@ -128,13 +180,21 @@ public final class WidgetInfo implements Parcelable { /** @hide */ @SuppressWarnings({"unchecked", "RedundantCast"}) @DataClass.Generated.Member - /* package-private */ WidgetInfo(@NonNull android.os.Parcel in) { + /* package-private */ WidgetInfo(@NonNull Parcel in) { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } long widgetToken = in.readLong(); + Rect contentRect = (Rect) in.readTypedObject(Rect.CREATOR); + SurfaceControlViewHost.SurfacePackage surfacePackage = (SurfaceControlViewHost.SurfacePackage) in.readTypedObject(SurfaceControlViewHost.SurfacePackage.CREATOR); this.mWidgetToken = widgetToken; + this.mContentRect = contentRect; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mContentRect); + this.mSurfacePackage = surfacePackage; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mSurfacePackage); // onConstructed(); // You can define this method to get a callback } @@ -148,16 +208,16 @@ public final class WidgetInfo implements Parcelable { } @Override - public WidgetInfo createFromParcel(@NonNull android.os.Parcel in) { + public WidgetInfo createFromParcel(@NonNull Parcel in) { return new WidgetInfo(in); } }; @DataClass.Generated( - time = 1639488254020L, + time = 1643281495056L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/WidgetInfo.java", - inputSignatures = "private final long mWidgetToken\nclass WidgetInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)") + inputSignatures = "private final long mWidgetToken\nprivate final @android.annotation.NonNull android.graphics.Rect mContentRect\nprivate final @android.annotation.NonNull android.view.SurfaceControlViewHost.SurfacePackage mSurfacePackage\nclass WidgetInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)") @Deprecated private void __metadata() {} |
