diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index b360c82374d05..3574f8d05055c 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -5790,6 +5790,7 @@ public class Activity extends ContextThemeWrapper * * @return True if this is the root activity, else false. */ + @Override public boolean isTaskRoot() { try { return ActivityManager.getService().getTaskForActivity(mToken, true) >= 0; @@ -7207,6 +7208,9 @@ public class Activity extends ContextThemeWrapper "dispatchPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode + " " + newConfig); mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode, newConfig); + if (mWindow != null) { + mWindow.onPictureInPictureModeChanged(isInPictureInPictureMode); + } onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig); } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 6dd8ecfa12e3d..0d5c0754dca77 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -624,6 +624,9 @@ public abstract class Window { /** Returns the current stack Id for the window. */ int getWindowStackId() throws RemoteException; + + /** Returns whether the window belongs to the task root. */ + boolean isTaskRoot(); } /** @@ -2270,6 +2273,12 @@ public abstract class Window { */ public abstract void onMultiWindowModeChanged(); + /** + * Called when the activity changes to/from picture-in-picture mode. + * @hide + */ + public abstract void onPictureInPictureModeChanged(boolean isInPictureInPictureMode); + /** * Called when the activity just relaunched. * @hide diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index ba3aa36067d52..60fbbe9778e7e 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -16,6 +16,8 @@ package com.android.internal.policy; +import android.graphics.Outline; +import android.view.ViewOutlineProvider; import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.R; import com.android.internal.policy.PhoneWindow.PanelFeatureState; @@ -135,6 +137,16 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind com.android.internal.R.id.navigationBarBackground, 0 /* hideWindowFlag */); + // This is used to workaround an issue where the PiP shadow can be transparent if the window + // background is transparent + private static final ViewOutlineProvider PIP_OUTLINE_PROVIDER = new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRect(0, 0, view.getWidth(), view.getHeight()); + outline.setAlpha(1f); + } + }; + // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer // size calculation takes the shadow size into account. We set the elevation currently // to max until the first layout command has been executed. @@ -142,6 +154,12 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private boolean mElevationAdjustedForStack = false; + // Keeps track of the picture-in-picture mode for the view shadow + private boolean mIsInPictureInPictureMode; + + // Stores the previous outline provider prior to applying PIP_OUTLINE_PROVIDER + private ViewOutlineProvider mLastOutlineProvider; + int mDefaultOpacity = PixelFormat.OPAQUE; /** The feature ID of the panel, or -1 if this is the application's DecorView */ @@ -1404,6 +1422,41 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } } + /** + * Overrides the view outline when the activity enters picture-in-picture to ensure that it has + * an opaque shadow even if the window background is completely transparent. This only applies + * to activities that are currently the task root. + */ + public void updatePictureInPictureOutlineProvider(boolean isInPictureInPictureMode) { + if (mIsInPictureInPictureMode == isInPictureInPictureMode) { + return; + } + + if (isInPictureInPictureMode) { + final Window.WindowControllerCallback callback = + mWindow.getWindowControllerCallback(); + if (callback != null && callback.isTaskRoot()) { + // Call super implementation directly as we don't want to save the PIP outline + // provider to be restored + super.setOutlineProvider(PIP_OUTLINE_PROVIDER); + } + } else { + // Restore the previous outline provider + if (getOutlineProvider() != mLastOutlineProvider) { + setOutlineProvider(mLastOutlineProvider); + } + } + mIsInPictureInPictureMode = isInPictureInPictureMode; + } + + @Override + public void setOutlineProvider(ViewOutlineProvider provider) { + super.setOutlineProvider(provider); + + // Save the outline provider set to ensure that we can restore when the activity leaves PiP + mLastOutlineProvider = provider; + } + private void drawableChanged() { if (mChanging) { return; diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 243916b4ade20..8fe9100d2011b 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -728,6 +728,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + @Override + public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) { + if (mDecor != null) { + mDecor.updatePictureInPictureOutlineProvider(isInPictureInPictureMode); + } + } + @Override public void reportActivityRelaunched() { if (mDecor != null && mDecor.getViewRootImpl() != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 236e008d42968..f58a91b8b369b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -721,6 +721,10 @@ public class StatusBarWindowView extends FrameLayout { public void onMultiWindowModeChanged() { } + @Override + public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) { + } + @Override public void reportActivityRelaunched() { }