diff options
9 files changed, 108 insertions, 16 deletions
diff --git a/libs/WindowManager/Shell/res/drawable/pip_custom_close_bg.xml b/libs/WindowManager/Shell/res/drawable/pip_custom_close_bg.xml new file mode 100644 index 000000000000..39c3fe6f6106 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/pip_custom_close_bg.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <solid + android:color="@color/pip_custom_close_bg" /> + <size + android:width="@dimen/pip_custom_close_bg_size" + android:height="@dimen/pip_custom_close_bg_size" /> +</shape> diff --git a/libs/WindowManager/Shell/res/layout/pip_menu_action.xml b/libs/WindowManager/Shell/res/layout/pip_menu_action.xml index a733b31d9fb0..b51dd6a00815 100644 --- a/libs/WindowManager/Shell/res/layout/pip_menu_action.xml +++ b/libs/WindowManager/Shell/res/layout/pip_menu_action.xml @@ -22,6 +22,14 @@ android:forceHasOverlappingRendering="false"> <ImageView + android:id="@+id/custom_close_bg" + android:layout_width="@dimen/pip_custom_close_bg_size" + android:layout_height="@dimen/pip_custom_close_bg_size" + android:layout_gravity="center" + android:src="@drawable/pip_custom_close_bg" + android:visibility="gone"/> + + <ImageView android:id="@+id/image" android:layout_width="@dimen/pip_action_inner_size" android:layout_height="@dimen/pip_action_inner_size" diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index 4606d24d1716..6e750a3d5e34 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -30,6 +30,9 @@ <color name="bubbles_dark">@color/GM2_grey_800</color> <color name="bubbles_icon_tint">@color/GM2_grey_700</color> + <!-- PiP --> + <color name="pip_custom_close_bg">#D93025</color> + <!-- Compat controls UI --> <color name="compat_controls_background">@android:color/system_neutral1_800</color> <color name="compat_controls_text">@android:color/system_neutral1_50</color> @@ -47,4 +50,4 @@ <color name="splash_screen_bg_light">#FFFFFF</color> <color name="splash_screen_bg_dark">#000000</color> <color name="splash_window_background_default">@color/splash_screen_bg_light</color> -</resources>
\ No newline at end of file +</resources> diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index d416c060c86c..8ba41ab60c87 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -46,6 +46,10 @@ <!-- Show PiP enter split icon, which allows apps to directly enter splitscreen from PiP. --> <bool name="config_pipEnableEnterSplitButton">false</bool> + <!-- Time (duration in milliseconds) that the shell waits for an app to close the PiP by itself + if a custom action is present before closing it. --> + <integer name="config_pipForceCloseDelay">1000</integer> + <!-- Animation duration when using long press on recents to dock --> <integer name="long_press_dock_anim_duration">250</integer> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index a2f9e884b37d..c21381d1486a 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -78,6 +78,9 @@ WindowConfiguration#PINNED_WINDOWING_MODE_ELEVATION_IN_DIP --> <dimen name="pip_shadow_radius">5dp</dimen> + <!-- The width and height of the background for custom action in PiP menu. --> + <dimen name="pip_custom_close_bg_size">32dp</dimen> + <dimen name="dismiss_target_x_size">24dp</dimen> <dimen name="floating_dismiss_bottom_margin">50dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java index 9c23a32a7d2b..513ebba59258 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java @@ -110,7 +110,10 @@ public class PipUiEventLogger { PICTURE_IN_PICTURE_STASH_RIGHT(711), @UiEvent(doc = "User taps on the settings button in PiP menu") - PICTURE_IN_PICTURE_SHOW_SETTINGS(933); + PICTURE_IN_PICTURE_SHOW_SETTINGS(933), + + @UiEvent(doc = "Closes PiP with app-provided close action") + PICTURE_IN_PICTURE_CUSTOM_CLOSE(1058); private final int mId; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java index f73b81e9d3f3..8ce8f7382ff3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java @@ -121,6 +121,7 @@ public class PhonePipMenuController implements PipMenuController { private final Optional<SplitScreenController> mSplitScreenController; private final PipUiEventLogger mPipUiEventLogger; private ParceledListSlice<RemoteAction> mAppActions; + private RemoteAction mCloseAction; private ParceledListSlice<RemoteAction> mMediaActions; private SyncRtSurfaceTransactionApplier mApplier; private int mMenuState; @@ -459,6 +460,7 @@ public class PhonePipMenuController implements PipMenuController { public void setAppActions(ParceledListSlice<RemoteAction> appActions, RemoteAction closeAction) { mAppActions = appActions; + mCloseAction = closeAction; updateMenuActions(); } @@ -490,9 +492,8 @@ public class PhonePipMenuController implements PipMenuController { private void updateMenuActions() { if (mPipMenuView != null) { final ParceledListSlice<RemoteAction> menuActions = resolveMenuActions(); - if (menuActions != null) { - mPipMenuView.setActions(mPipBoundsState.getBounds(), menuActions.getList()); - } + mPipMenuView.setActions(mPipBoundsState.getBounds(), + menuActions == null ? null : menuActions.getList(), mCloseAction); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActionView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActionView.java index f11ae422e837..7f84500e8406 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActionView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActionView.java @@ -19,6 +19,7 @@ package com.android.wm.shell.pip.phone; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; @@ -30,6 +31,7 @@ import com.android.wm.shell.R; */ public class PipMenuActionView extends FrameLayout { private ImageView mImageView; + private View mCustomCloseBackground; public PipMenuActionView(Context context, AttributeSet attrs) { super(context, attrs); @@ -39,10 +41,16 @@ public class PipMenuActionView extends FrameLayout { protected void onFinishInflate() { super.onFinishInflate(); mImageView = findViewById(R.id.image); + mCustomCloseBackground = findViewById(R.id.custom_close_bg); } /** pass through to internal {@link #mImageView} */ public void setImageDrawable(Drawable drawable) { mImageView.setImageDrawable(drawable); } + + /** pass through to internal {@link #mCustomCloseBackground} */ + public void setCustomCloseBackgroundVisibility(@View.Visibility int visibility) { + mCustomCloseBackground.setVisibility(visibility); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java index c0fa8c0a8898..6390c8984dac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java @@ -33,8 +33,10 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.PendingIntent.CanceledException; +import android.app.PendingIntent; import android.app.RemoteAction; import android.app.WindowConfiguration; import android.content.ComponentName; @@ -72,6 +74,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; /** @@ -113,6 +116,7 @@ public class PipMenuView extends FrameLayout { private boolean mFocusedTaskAllowSplitScreen; private final List<RemoteAction> mActions = new ArrayList<>(); + private RemoteAction mCloseAction; private AccessibilityManager mAccessibilityManager; private Drawable mBackgroundDrawable; @@ -151,6 +155,9 @@ public class PipMenuView extends FrameLayout { protected View mTopEndContainer; protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm; + // How long the shell will wait for the app to close the PiP if a custom action is set. + private final int mPipForceCloseDelay; + public PipMenuView(Context context, PhonePipMenuController controller, ShellExecutor mainExecutor, Handler mainHandler, Optional<SplitScreenController> splitScreenController, @@ -166,6 +173,9 @@ public class PipMenuView extends FrameLayout { mAccessibilityManager = context.getSystemService(AccessibilityManager.class); inflate(context, R.layout.pip_menu, this); + mPipForceCloseDelay = context.getResources().getInteger( + R.integer.config_pipForceCloseDelay); + mBackgroundDrawable = mContext.getDrawable(R.drawable.pip_menu_background); mBackgroundDrawable.setAlpha(0); mViewRoot = findViewById(R.id.background); @@ -437,9 +447,13 @@ public class PipMenuView extends FrameLayout { return new Size(width, height); } - void setActions(Rect stackBounds, List<RemoteAction> actions) { + void setActions(Rect stackBounds, @Nullable List<RemoteAction> actions, + @Nullable RemoteAction closeAction) { mActions.clear(); - mActions.addAll(actions); + if (actions != null && !actions.isEmpty()) { + mActions.addAll(actions); + } + mCloseAction = closeAction; if (mMenuState == MENU_STATE_FULL) { updateActionViews(mMenuState, stackBounds); } @@ -492,6 +506,8 @@ public class PipMenuView extends FrameLayout { final RemoteAction action = mActions.get(i); final PipMenuActionView actionView = (PipMenuActionView) mActionsGroup.getChildAt(i); + final boolean isCloseAction = mCloseAction != null && Objects.equals( + mCloseAction.getActionIntent(), action.getActionIntent()); // TODO: Check if the action drawable has changed before we reload it action.getIcon().loadDrawableAsync(mContext, d -> { @@ -500,16 +516,12 @@ public class PipMenuView extends FrameLayout { actionView.setImageDrawable(d); } }, mMainHandler); + actionView.setCustomCloseBackgroundVisibility( + isCloseAction ? View.VISIBLE : View.GONE); actionView.setContentDescription(action.getContentDescription()); if (action.isEnabled()) { - actionView.setOnClickListener(v -> { - try { - action.getActionIntent().send(); - } catch (CanceledException e) { - ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: Failed to send action, %s", TAG, e); - } - }); + actionView.setOnClickListener( + v -> onActionViewClicked(action.getActionIntent(), isCloseAction)); } actionView.setEnabled(action.isEnabled()); actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA); @@ -559,6 +571,32 @@ public class PipMenuView extends FrameLayout { } } + /** + * Execute the {@link PendingIntent} attached to the {@link PipMenuActionView}. + * If the given {@link PendingIntent} matches {@link #mCloseAction}, we need to make sure + * the PiP is removed after a certain timeout in case the app does not respond in a + * timely manner. + */ + private void onActionViewClicked(@NonNull PendingIntent intent, boolean isCloseAction) { + try { + intent.send(); + } catch (PendingIntent.CanceledException e) { + ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: Failed to send action, %s", TAG, e); + } + if (isCloseAction) { + mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_CUSTOM_CLOSE); + mAllowTouches = false; + mMainExecutor.executeDelayed(() -> { + hideMenu(); + // TODO: it's unsafe to call onPipDismiss with a delay here since + // we may have a different PiP by the time this runnable is executed. + mController.onPipDismiss(); + mAllowTouches = true; + }, mPipForceCloseDelay); + } + } + private void enterSplit() { // Do not notify menu visibility when hiding the menu, the controller will do this when it // handles the message |