diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml index d3277ded6c5ba..1fe2760e5b102 100644 --- a/packages/CarSystemUI/res/values/config.xml +++ b/packages/CarSystemUI/res/values/config.xml @@ -123,7 +123,6 @@ com.android.systemui.volume.VolumeUI com.android.systemui.statusbar.phone.StatusBar com.android.systemui.keyboard.KeyboardUI - com.android.systemui.pip.PipUI com.android.systemui.shortcut.ShortcutKeyDispatcher com.android.systemui.LatencyTester com.android.systemui.globalactions.GlobalActionsComponent diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java index 1a6fdfa9c996f..51855dc648e91 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java @@ -20,7 +20,6 @@ import com.android.systemui.dagger.DependencyProvider; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SystemUIModule; -import com.android.systemui.pip.phone.dagger.PipModule; import dagger.Subcomponent; @@ -31,7 +30,6 @@ import dagger.Subcomponent; @Subcomponent(modules = { CarComponentBinder.class, DependencyProvider.class, - PipModule.class, SystemUIModule.class, CarSystemUIModule.class, CarSystemUIBinder.class}) diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java index 3971e18bb968b..616e56288392e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java @@ -29,7 +29,6 @@ import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.onehanded.OneHandedUI; -import com.android.systemui.pip.PipUI; import com.android.systemui.power.PowerUI; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsModule; @@ -101,12 +100,6 @@ public abstract class CarSystemUIBinder { @ClassKey(OneHandedUI.class) public abstract SystemUI bindOneHandedUI(OneHandedUI sysui); - /** Inject into PipUI. */ - @Binds - @IntoMap - @ClassKey(PipUI.class) - public abstract SystemUI bindPipUI(PipUI sysui); - /** Inject into PowerUI. */ @Binds @IntoMap diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 7f4f580abf94e..6db3d0b8dff2e 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -516,7 +516,7 @@ android:excludeFromRecents="true" android:visibleToInstantApps="true"/> - + com.android.systemui.power.PowerUI com.android.systemui.media.RingtonePlayer com.android.systemui.keyboard.KeyboardUI - com.android.systemui.pip.PipUI com.android.systemui.shortcut.ShortcutKeyDispatcher @string/config_systemUIVendorServiceComponent com.android.systemui.SliceBroadcastRelayHandler diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 130bb4fc90b9e..7faa2a44bb6cc 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -306,7 +306,6 @@ com.android.systemui.power.PowerUI com.android.systemui.media.RingtonePlayer com.android.systemui.keyboard.KeyboardUI - com.android.systemui.pip.PipUI com.android.systemui.shortcut.ShortcutKeyDispatcher @string/config_systemUIVendorServiceComponent com.android.systemui.util.leak.GarbageMonitor$Service diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 2622593880ba4..4bea0674e8bf1 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -22,7 +22,6 @@ import com.android.systemui.InitController; import com.android.systemui.SystemUIAppComponentFactory; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardSliceProvider; -import com.android.systemui.pip.phone.dagger.PipModule; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.InjectionInflationController; @@ -36,7 +35,6 @@ import dagger.Subcomponent; @Subcomponent(modules = { DefaultComponentBinder.class, DependencyProvider.class, - PipModule.class, SystemUIBinder.class, SystemUIModule.class, SystemUIDefaultModule.class}) diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index 9dfd9f8fd9bfd..c331bd377eecc 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -29,7 +29,6 @@ import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.onehanded.OneHandedUI; -import com.android.systemui.pip.PipUI; import com.android.systemui.power.PowerUI; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsModule; @@ -97,12 +96,6 @@ public abstract class SystemUIBinder { @ClassKey(OneHandedUI.class) public abstract SystemUI bindOneHandedUI(OneHandedUI sysui); - /** Inject into PipUI. */ - @Binds - @IntoMap - @ClassKey(PipUI.class) - public abstract SystemUI bindPipUI(PipUI sysui); - /** Inject into PowerUI. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java deleted file mode 100644 index 38744fe1b670e..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2017 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 com.android.systemui.pip; - -import android.content.res.Configuration; - -import com.android.systemui.shared.recents.IPinnedStackAnimationListener; - -import java.io.PrintWriter; - - -public interface BasePipManager { - void showPictureInPictureMenu(); - default void expandPip() {} - default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {} - void onConfigurationChanged(Configuration newConfig); - default void setShelfHeight(boolean visible, int height) {} - default void setPinnedStackAnimationType(int animationType) {} - default void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {} - default void dump(PrintWriter pw) {} -} diff --git a/packages/SystemUI/src/com/android/systemui/pip/Pip.java b/packages/SystemUI/src/com/android/systemui/pip/Pip.java new file mode 100644 index 0000000000000..b068370da9e3a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/Pip.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2017 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 com.android.systemui.pip; + +import android.content.res.Configuration; +import android.media.session.MediaController; + +import com.android.systemui.pip.tv.PipController; +import com.android.systemui.shared.recents.IPinnedStackAnimationListener; + +import java.io.PrintWriter; + +/** + * Interface to engage picture in picture feature. + */ +public interface Pip { + /** + * Called when showing Pip menu. + */ + void showPictureInPictureMenu(); + + /** + * Registers {@link com.android.systemui.pip.tv.PipController.Listener} that gets called. + * whenever receiving notification on changes in PIP. + */ + default void addListener(PipController.Listener listener) { + } + + /** + * Registers a {@link com.android.systemui.pip.tv.PipController.MediaListener} to PipController. + */ + default void addMediaListener(PipController.MediaListener listener) { + } + + /** + * Closes PIP (PIPed activity and PIP system UI). + */ + default void closePip() { + } + + /** + * Expand PIP, it's possible that specific request to activate the window via Alt-tab. + */ + default void expandPip() { + } + + /** + * Get current play back state. (e.g: Used in TV) + * + * @return The state of defined in PipController. + */ + default int getPlaybackState() { + return 0; + } + + /** + * Get MediaController. + * + * @return The MediaController instance. + */ + default MediaController getMediaController() { + return null; + } + + /** + * Hides the PIP menu. + */ + void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback); + + /** + * Returns {@code true} if PIP is shown. + */ + default boolean isPipShown() { + return false; + } + + /** + * Moves the PIPed activity to the fullscreen and closes PIP system UI. + */ + default void movePipToFullscreen() { + } + + /** + * Called when configuration change invoked. + */ + void onConfigurationChanged(Configuration newConfig); + + /** + * Removes a {@link PipController.Listener} from PipController. + */ + default void removeListener(PipController.Listener listener) { + } + + /** + * Removes a {@link com.android.systemui.pip.tv.PipController.MediaListener} from PipController. + */ + default void removeMediaListener(PipController.MediaListener listener) { + } + + /** + * Resize the Pip to the appropriate size for the input state. + * + * @param state In Pip state also used to determine the new size for the Pip. + */ + default void resizePinnedStack(int state) { + } + + /** + * Resumes resizing operation on the Pip that was previously suspended. + * + * @param reason The reason resizing operations on the Pip was suspended. + */ + default void resumePipResizing(int reason) { + } + + /** + * Sets both shelf visibility and its height. + * + * @param visible visibility of shelf. + * @param height to specify the height for shelf. + */ + default void setShelfHeight(boolean visible, int height) { + } + + /** + * Set the pinned stack with {@link PipAnimationController.AnimationType} + * + * @param animationType The pre-defined {@link PipAnimationController.AnimationType} + */ + default void setPinnedStackAnimationType(int animationType) { + } + + /** + * Registers the pinned stack animation listener. + * + * @param listener The listener of pinned stack animation. + */ + default void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) { + } + + /** + * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called. + * + * @param reason The reason for suspending resizing operations on the Pip. + */ + default void suspendPipResizing(int reason) { + } + + /** + * Dump the current state and information if need. + * + * @param pw The stream to dump information to. + */ + default void dump(PrintWriter pw) { + } +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java deleted file mode 100644 index 2cd1e202125df..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2016 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 com.android.systemui.pip; - -import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.os.UserHandle; -import android.os.UserManager; - -import com.android.systemui.SystemUI; -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.shared.recents.IPinnedStackAnimationListener; -import com.android.systemui.statusbar.CommandQueue; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -import javax.inject.Inject; - -/** - * Controls the picture-in-picture window. - */ -@SysUISingleton -public class PipUI extends SystemUI implements CommandQueue.Callbacks { - - private final CommandQueue mCommandQueue; - private BasePipManager mPipManager; - - @Inject - public PipUI(Context context, CommandQueue commandQueue, - BasePipManager pipManager) { - super(context); - mCommandQueue = commandQueue; - mPipManager = pipManager; - } - - @Override - public void start() { - PackageManager pm = mContext.getPackageManager(); - boolean supportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE); - if (!supportsPip) { - return; - } - - // Ensure that we are the primary user's SystemUI. - final int processUser = UserManager.get(mContext).getUserHandle(); - if (processUser != UserHandle.USER_SYSTEM) { - throw new IllegalStateException("Non-primary Pip component not currently supported."); - } - - mCommandQueue.addCallback(this); - } - - @Override - public void showPictureInPictureMenu() { - mPipManager.showPictureInPictureMenu(); - } - - public void expandPip() { - mPipManager.expandPip(); - } - - public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) { - mPipManager.hidePipMenu(onStartCallback, onEndCallback); - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - if (mPipManager == null) { - return; - } - - mPipManager.onConfigurationChanged(newConfig); - } - - public void setShelfHeight(boolean visible, int height) { - if (mPipManager == null) { - return; - } - - mPipManager.setShelfHeight(visible, height); - } - - public void setPinnedStackAnimationType(int animationType) { - if (mPipManager != null) { - mPipManager.setPinnedStackAnimationType(animationType); - } - } - - public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) { - if (mPipManager != null) { - mPipManager.setPinnedStackAnimationListener(listener); - } - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mPipManager == null) { - return; - } - - mPipManager.dump(pw); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java similarity index 89% rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java rename to packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java index 5ef5b902327e9..1a805daef77ec 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java @@ -18,6 +18,7 @@ package com.android.systemui.pip.phone; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static com.android.systemui.pip.PipAnimationController.isOutPipDirection; @@ -28,11 +29,14 @@ import android.app.IActivityManager; import android.app.RemoteAction; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; import android.util.Log; import android.util.Pair; import android.view.DisplayInfo; @@ -44,7 +48,7 @@ import com.android.systemui.UiOffloadThread; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.model.SysUiState; -import com.android.systemui.pip.BasePipManager; +import com.android.systemui.pip.Pip; import com.android.systemui.pip.PipBoundsHandler; import com.android.systemui.pip.PipSurfaceTransactionHelper; import com.android.systemui.pip.PipTaskOrganizer; @@ -55,25 +59,20 @@ import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; -import com.android.systemui.stackdivider.SplitScreen; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.FloatingContentCoordinator; -import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; import java.io.PrintWriter; -import java.util.Optional; - -import javax.inject.Inject; /** * Manages the picture-in-picture (PIP) UI and states for Phones. */ @SysUISingleton -public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitionCallback { - private static final String TAG = "PipManager"; +public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback { + private static final String TAG = "PipController"; private Context mContext; private IActivityManager mActivityManager; @@ -87,15 +86,15 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private DisplayController mDisplayController; private InputConsumerController mInputConsumerController; private PipAppOpsListener mAppOpsListener; + private PipBoundsHandler mPipBoundsHandler; private PipMediaController mMediaController; private PipTouchHandler mTouchHandler; - private PipTaskOrganizer mPipTaskOrganizer; private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper; private IPinnedStackAnimationListener mPinnedStackAnimationRecentsListener; private boolean mIsInFixedRotation; - protected PipBoundsHandler mPipBoundsHandler; protected PipMenuActivityController mMenuController; + protected PipTaskOrganizer mPipTaskOrganizer; /** * Handler for display rotation changes. @@ -127,7 +126,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio // not during the fixed rotation. In fixed rotation case, app is about to enter PiP // and we need the offsets preserved to calculate the destination bounds. if (!mIsInFixedRotation) { - mPipBoundsHandler.setShelfHeight(false , 0); + mPipBoundsHandler.setShelfHeight(false, 0); mPipBoundsHandler.onImeVisibilityChanged(false, 0); mTouchHandler.onShelfVisibilityChanged(false, 0); mTouchHandler.onImeVisibilityChanged(false, 0); @@ -201,7 +200,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio /** * Handler for messages from the PIP controller. */ - private class PipManagerPinnedStackListener extends PinnedStackListener { + private class PipControllerPinnedStackListener extends PinnedStackListener { @Override public void onListenerRegistered(IPinnedStackController controller) { mHandler.post(() -> mTouchHandler.setPinnedStackController(controller)); @@ -253,44 +252,55 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio public ConfigurationController.ConfigurationListener mOverlayChangedListener = new ConfigurationController.ConfigurationListener() { - @Override - public void onOverlayChanged() { - mHandler.post(() -> { - mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay()); - updateMovementBounds(null /* toBounds */, - false /* fromRotation */, false /* fromImeAdjustment */, - false /* fromShelfAdjustment */, null /* windowContainerTransaction */); - }); - } - }; + @Override + public void onOverlayChanged() { + mHandler.post(() -> { + mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay()); + updateMovementBounds(null /* toBounds */, + false /* fromRotation */, false /* fromImeAdjustment */, + false /* fromShelfAdjustment */, + null /* windowContainerTransaction */); + }); + } + }; - @Inject - public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, + public PipController(Context context, BroadcastDispatcher broadcastDispatcher, ConfigurationController configController, DeviceConfigProxy deviceConfig, DisplayController displayController, - Optional splitScreenOptional, FloatingContentCoordinator floatingContentCoordinator, SysUiState sysUiState, - PipUiEventLogger pipUiEventLogger, - ShellTaskOrganizer shellTaskOrganizer) { + PipBoundsHandler pipBoundsHandler, + PipSurfaceTransactionHelper pipSurfaceTransactionHelper, + PipTaskOrganizer pipTaskOrganizer, + PipUiEventLogger pipUiEventLogger) { mContext = context; mActivityManager = ActivityManager.getService(); + PackageManager pm = context.getPackageManager(); + boolean supportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE); + if (!supportsPip) { + return; + } + + // Ensure that we are the primary user's SystemUI. + final int processUser = UserManager.get(context).getUserHandle(); + if (processUser != UserHandle.USER_SYSTEM) { + throw new IllegalStateException("Non-primary Pip component not currently supported."); + } + try { WindowManagerWrapper.getInstance().addPinnedStackListener( - new PipManagerPinnedStackListener()); + new PipControllerPinnedStackListener()); } catch (RemoteException e) { Log.e(TAG, "Failed to register pinned stack listener", e); } ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); mDisplayController = displayController; - mPipBoundsHandler = new PipBoundsHandler(mContext); - mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController); - mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler, - mPipSurfaceTransactionHelper, splitScreenOptional, mDisplayController, - pipUiEventLogger, shellTaskOrganizer); + mPipBoundsHandler = pipBoundsHandler; + mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper; + mPipTaskOrganizer = pipTaskOrganizer; mPipTaskOrganizer.registerPipTransitionCallback(this); mInputConsumerController = InputConsumerController.getPipInputConsumer(); mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher); @@ -450,6 +460,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mTmpDisplayInfo.rotation); } + @Override public void dump(PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java deleted file mode 100644 index c8b6982a2eba5..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.systemui.pip.phone.dagger; - -import com.android.systemui.pip.BasePipManager; -import com.android.systemui.pip.phone.PipManager; - -import dagger.Binds; -import dagger.Module; - -/** - * Dagger Module for Phone PIP. - */ -@Module -public abstract class PipModule { - - /** Binds PipManager as the default BasePipManager. */ - @Binds - public abstract BasePipManager providePipManager(PipManager pipManager); -} diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java similarity index 91% rename from packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java rename to packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java index a388fa324a2e2..3b3235f1e63c0 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java @@ -20,7 +20,6 @@ import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import android.annotation.NonNull; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; import android.app.ActivityTaskManager; @@ -51,34 +50,31 @@ import com.android.systemui.R; import com.android.systemui.UiOffloadThread; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.pip.BasePipManager; +import com.android.systemui.pip.Pip; import com.android.systemui.pip.PipBoundsHandler; import com.android.systemui.pip.PipSurfaceTransactionHelper; import com.android.systemui.pip.PipTaskOrganizer; -import com.android.systemui.pip.PipUiEventLogger; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; -import com.android.systemui.stackdivider.SplitScreen; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.common.DisplayController; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import javax.inject.Inject; - /** * Manages the picture-in-picture (PIP) UI and states. */ @SysUISingleton -public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitionCallback { - private static final String TAG = "PipManager"; +public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback { + private static final String TAG = "PipController"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + /** + * Unknown or invalid state + */ + public static final int STATE_UNKNOWN = -1; /** * State when there's no PIP. */ @@ -147,7 +143,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private boolean mImeVisible; private int mImeHeightAdjustment; - private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener(); + private final PinnedStackListener mPinnedStackListener = new PipControllerPinnedStackListener(); private final Runnable mResizePinnedStackRunnable = new Runnable() { @Override @@ -189,7 +185,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio /** * Handler for messages from the PIP controller. */ - private class PipManagerPinnedStackListener extends PinnedStackListener { + private class PipControllerPinnedStackListener extends PinnedStackListener { @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { mHandler.post(() -> { @@ -231,20 +227,19 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } } - @Inject - public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, - ConfigurationController configController, - DisplayController displayController, - Optional splitScreenOptional, - @NonNull PipUiEventLogger pipUiEventLogger, - ShellTaskOrganizer shellTaskOrganizer) { + public PipController(Context context, BroadcastDispatcher broadcastDispatcher, + PipBoundsHandler pipBoundsHandler, + PipSurfaceTransactionHelper pipSurfaceTransactionHelper, + PipTaskOrganizer pipTaskOrganizer) { if (mInitialized) { return; } mInitialized = true; mContext = context; - mPipBoundsHandler = new PipBoundsHandler(mContext); + mPipNotification = new PipNotification(context, broadcastDispatcher, + Optional.of(this).get()); + mPipBoundsHandler = pipBoundsHandler; // Ensure that we have the display info in case we get calls to update the bounds before the // listener calls back final DisplayInfo displayInfo = new DisplayInfo(); @@ -253,10 +248,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mResizeAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); - mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController); - mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler, - mPipSurfaceTransactionHelper, splitScreenOptional, displayController, - pipUiEventLogger, shellTaskOrganizer); + mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper; + mPipTaskOrganizer = pipTaskOrganizer; mPipTaskOrganizer.registerPipTransitionCallback(this); mActivityTaskManager = ActivityTaskManager.getService(); ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); @@ -278,8 +271,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } catch (RemoteException | UnsupportedOperationException e) { Log.e(TAG, "Failed to register pinned stack listener", e); } - - mPipNotification = new PipNotification(context, broadcastDispatcher, this); } private void loadConfigurationsAndApply(Configuration newConfig) { @@ -359,7 +350,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio /** * Moves the PIPed activity to the fullscreen and closes PIP system UI. */ - void movePipToFullscreen() { + public void movePipToFullscreen() { if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription()); mPipTaskId = TASK_ID_NO_PIP; @@ -372,34 +363,41 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio /** * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called + * * @param reason The reason for suspending resizing operations on the Pip. */ public void suspendPipResizing(int reason) { - if (DEBUG) Log.d(TAG, - "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2)); + if (DEBUG) { + Log.d(TAG, + "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2)); + } mSuspendPipResizingReason |= reason; } /** * Resumes resizing operation on the Pip that was previously suspended. + * * @param reason The reason resizing operations on the Pip was suspended. */ public void resumePipResizing(int reason) { if ((mSuspendPipResizingReason & reason) == 0) { return; } - if (DEBUG) Log.d(TAG, - "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2)); + if (DEBUG) { + Log.d(TAG, + "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2)); + } mSuspendPipResizingReason &= ~reason; mHandler.post(mResizePinnedStackRunnable); } /** * Resize the Pip to the appropriate size for the input state. + * * @param state In Pip state also used to determine the new size for the Pip. */ - void resizePinnedStack(int state) { + public void resizePinnedStack(int state) { if (DEBUG) { Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state=" + getStateDescription(), new Exception()); @@ -411,10 +409,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } if (mSuspendPipResizingReason != 0) { mResumeResizePinnedStackRunnableState = state; - if (DEBUG) Log.d(TAG, "resizePinnedStack() deferring" - + " mSuspendPipResizingReason=" + mSuspendPipResizingReason - + " mResumeResizePinnedStackRunnableState=" - + stateToName(mResumeResizePinnedStackRunnableState)); + if (DEBUG) { + Log.d(TAG, "resizePinnedStack() deferring" + + " mSuspendPipResizingReason=" + mSuspendPipResizingReason + + " mResumeResizePinnedStackRunnableState=" + + stateToName(mResumeResizePinnedStackRunnableState)); + } return; } mState = state; @@ -471,28 +471,28 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } /** - * Adds a {@link Listener} to PipManager. + * Adds a {@link Listener} to PipController. */ public void addListener(Listener listener) { mListeners.add(listener); } /** - * Removes a {@link Listener} from PipManager. + * Removes a {@link Listener} from PipController. */ public void removeListener(Listener listener) { mListeners.remove(listener); } /** - * Adds a {@link MediaListener} to PipManager. + * Adds a {@link MediaListener} to PipController. */ public void addMediaListener(MediaListener listener) { mMediaListeners.add(listener); } /** - * Removes a {@link MediaListener} from PipManager. + * Removes a {@link MediaListener} from PipController. */ public void removeMediaListener(MediaListener listener) { mMediaListeners.remove(listener); @@ -568,16 +568,21 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio /** * Gets the {@link android.media.session.MediaController} for the PIPed activity. */ - MediaController getMediaController() { + public MediaController getMediaController() { return mPipMediaController; } + @Override + public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) { + + } + /** * Returns the PIPed activity's playback state. * This returns one of {@link #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED}, * or {@link #PLAYBACK_STATE_UNAVAILABLE}. */ - int getPlaybackState() { + public int getPlaybackState() { if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) { return PLAYBACK_STATE_UNAVAILABLE; } @@ -673,7 +678,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio }; @Override - public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { } + public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { + } @Override public void onPipTransitionFinished(ComponentName activity, int direction) { @@ -701,7 +707,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio * Invoked when an activity is pinned and PIP manager is set corresponding information. * Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned} * because there's no guarantee for the PIP manager be return relavent information - * correctly. (e.g. {@link isPipShown}). + * correctly. (e.g. {@link Pip.isPipShown}). */ void onPipEntered(String packageName); /** Invoked when a PIPed activity is closed. */ diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java index 05bb882ea52e7..4ecd52f8adf5c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java @@ -27,12 +27,14 @@ import android.view.LayoutInflater; import android.view.View; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.pip.Pip; import com.android.wm.shell.R; import java.util.ArrayList; import java.util.List; - -import javax.inject.Inject; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; /** * Controller for {@link PipControlsView}. @@ -43,9 +45,9 @@ public class PipControlsViewController { private static final float DISABLED_ACTION_ALPHA = 0.54f; private final PipControlsView mView; - private final PipManager mPipManager; private final LayoutInflater mLayoutInflater; private final Handler mHandler; + private final Optional mPipOptional; private final PipControlButtonView mPlayPauseButtonView; private MediaController mMediaController; private PipControlButtonView mFocusedChild; @@ -73,12 +75,14 @@ public class PipControlsViewController { @Override public void onViewAttachedToWindow(View v) { updateMediaController(); - mPipManager.addMediaListener(mPipMediaListener); + mPipOptional.ifPresent( + pip -> pip.addMediaListener(mPipMediaListener)); } @Override public void onViewDetachedFromWindow(View v) { - mPipManager.removeMediaListener(mPipMediaListener); + mPipOptional.ifPresent( + pip -> pip.removeMediaListener(mPipMediaListener)); } }; @@ -89,7 +93,7 @@ public class PipControlsViewController { } }; - private final PipManager.MediaListener mPipMediaListener = this::updateMediaController; + private final PipController.MediaListener mPipMediaListener = this::updateMediaController; private final View.OnFocusChangeListener mFocusChangeListener = @@ -105,12 +109,11 @@ public class PipControlsViewController { }; - @Inject - public PipControlsViewController(PipControlsView view, PipManager pipManager, + public PipControlsViewController(PipControlsView view, Optional pipOptional, LayoutInflater layoutInflater, @Main Handler handler) { super(); mView = view; - mPipManager = pipManager; + mPipOptional = pipOptional; mLayoutInflater = layoutInflater; mHandler = handler; @@ -121,12 +124,14 @@ public class PipControlsViewController { View fullButtonView = mView.getFullButtonView(); fullButtonView.setOnFocusChangeListener(mFocusChangeListener); - fullButtonView.setOnClickListener(v -> mPipManager.movePipToFullscreen()); + fullButtonView.setOnClickListener( + v -> mPipOptional.ifPresent(pip -> pip.movePipToFullscreen()) + ); View closeButtonView = mView.getCloseButtonView(); closeButtonView.setOnFocusChangeListener(mFocusChangeListener); closeButtonView.setOnClickListener(v -> { - mPipManager.closePip(); + mPipOptional.ifPresent(pip -> pip.closePip()); if (mListener != null) { mListener.onClosed(); } @@ -139,24 +144,29 @@ public class PipControlsViewController { if (mMediaController == null || mMediaController.getPlaybackState() == null) { return; } - if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PAUSED) { - mMediaController.getTransportControls().play(); - } else if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PLAYING) { - mMediaController.getTransportControls().pause(); - } + mPipOptional.ifPresent(pip -> { + if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PAUSED) { + mMediaController.getTransportControls().play(); + } else if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PLAYING) { + mMediaController.getTransportControls().pause(); + } + }); + // View will be updated later in {@link mMediaControllerCallback} }); } private void updateMediaController() { - MediaController newController = mPipManager.getMediaController(); - if (mMediaController == newController) { + AtomicReference newController = new AtomicReference<>(); + mPipOptional.ifPresent(pip -> newController.set(pip.getMediaController())); + + if (newController.get() == null || mMediaController == newController.get()) { return; } if (mMediaController != null) { mMediaController.unregisterCallback(mMediaControllerCallback); } - mMediaController = newController; + mMediaController = newController.get(); if (mMediaController != null) { mMediaController.registerCallback(mMediaControllerCallback); } @@ -210,12 +220,14 @@ public class PipControlsViewController { // Hide the media session buttons mPlayPauseButtonView.setVisibility(View.GONE); } else { - int state = mPipManager.getPlaybackState(); - if (state == PipManager.PLAYBACK_STATE_UNAVAILABLE) { + AtomicInteger state = new AtomicInteger(PipController.STATE_UNKNOWN); + mPipOptional.ifPresent(pip -> state.set(pip.getPlaybackState())); + if (state.get() == PipController.STATE_UNKNOWN + || state.get() == PipController.PLAYBACK_STATE_UNAVAILABLE) { mPlayPauseButtonView.setVisibility(View.GONE); } else { mPlayPauseButtonView.setVisibility(View.VISIBLE); - if (state == PipManager.PLAYBACK_STATE_PLAYING) { + if (state.get() == PipController.PLAYBACK_STATE_PLAYING) { mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_pause_white); mPlayPauseButtonView.setText(R.string.pip_pause); } else { diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java index 70374036ef146..7e812d9ca8a19 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java @@ -25,17 +25,20 @@ import android.content.pm.ParceledListSlice; import android.os.Bundle; import android.util.Log; +import com.android.systemui.pip.Pip; import com.android.systemui.pip.tv.dagger.TvPipComponent; import com.android.wm.shell.R; import java.util.Collections; +import java.util.Optional; import javax.inject.Inject; /** * Activity to show the PIP menu to control PIP. */ -public class PipMenuActivity extends Activity implements PipManager.Listener { + +public class PipMenuActivity extends Activity implements PipController.Listener { private static final String TAG = "PipMenuActivity"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -43,7 +46,7 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { private final TvPipComponent.Builder mPipComponentBuilder; private TvPipComponent mTvPipComponent; - private final PipManager mPipManager; + private final Optional mPipOptional; private Animator mFadeInAnimation; private Animator mFadeOutAnimation; @@ -51,10 +54,11 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { private PipControlsViewController mPipControlsViewController; @Inject - public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder, PipManager pipManager) { + public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder, + Optional pipOptional) { super(); mPipComponentBuilder = pipComponentBuilder; - mPipManager = pipManager; + mPipOptional = pipOptional; } @Override @@ -62,15 +66,17 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { if (DEBUG) Log.d(TAG, "onCreate()"); super.onCreate(bundle); - if (!mPipManager.isPipShown()) { - finish(); - } + mPipOptional.ifPresent(pip -> { + if (!pip.isPipShown()) { + finish(); + } + }); setContentView(R.layout.tv_pip_menu); mTvPipComponent = mPipComponentBuilder.pipControlsView( findViewById(R.id.pip_controls)).build(); mPipControlsViewController = mTvPipComponent.getPipControlsViewController(); - mPipManager.addListener(this); + mPipOptional.ifPresent(pip -> pip.addListener(this)); mRestorePipSizeWhenClose = true; mFadeInAnimation = AnimatorInflater.loadAnimator( @@ -98,7 +104,7 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { if (DEBUG) Log.d(TAG, " > restoring to the default position"); // When PIP menu activity is closed, restore to the default position. - mPipManager.resizePinnedStack(PipManager.STATE_PIP); + mPipOptional.ifPresent(pip -> pip.resizePinnedStack(PipController.STATE_PIP)); } finish(); } @@ -125,9 +131,9 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { if (DEBUG) Log.d(TAG, "onDestroy()"); super.onDestroy(); - mPipManager.removeListener(this); - mPipManager.resumePipResizing( - PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH); + mPipOptional.ifPresent(pip -> pip.removeListener(this)); + mPipOptional.ifPresent(pip -> pip.resumePipResizing( + PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH)); } @Override @@ -178,8 +184,8 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()"); finish(); - mPipManager.suspendPipResizing( - PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH); + mPipOptional.ifPresent(pip -> pip.suspendPipResizing( + PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH)); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java index 5e5de58da2f61..78569edf009d2 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java @@ -48,14 +48,14 @@ import com.android.wm.shell.R; public class PipNotification { private static final String TAG = "PipNotification"; private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName(); - private static final boolean DEBUG = PipManager.DEBUG; + private static final boolean DEBUG = PipController.DEBUG; private static final String ACTION_MENU = "PipNotification.menu"; private static final String ACTION_CLOSE = "PipNotification.close"; private final PackageManager mPackageManager; - private final PipManager mPipManager; + private final PipController mPipController; private final NotificationManager mNotificationManager; private final Notification.Builder mNotificationBuilder; @@ -70,7 +70,7 @@ public class PipNotification { private String mMediaTitle; private Bitmap mArt; - private PipManager.Listener mPipListener = new PipManager.Listener() { + private PipController.Listener mPipListener = new PipController.Listener() { @Override public void onPipEntered(String packageName) { mPackageName = packageName; @@ -124,26 +124,27 @@ public class PipNotification { } }; - private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() { - @Override - public void onMediaControllerChanged() { - MediaController newController = mPipManager.getMediaController(); - if (mMediaController == newController) { - return; - } - if (mMediaController != null) { - mMediaController.unregisterCallback(mMediaControllerCallback); - } - mMediaController = newController; - if (mMediaController != null) { - mMediaController.registerCallback(mMediaControllerCallback); - } - if (updateMediaControllerMetadata() && mNotified) { - // update notification - notifyPipNotification(); - } - } - }; + private final PipController.MediaListener mPipMediaListener = + new PipController.MediaListener() { + @Override + public void onMediaControllerChanged() { + MediaController newController = mPipController.getMediaController(); + if (newController == null || mMediaController == newController) { + return; + } + if (mMediaController != null) { + mMediaController.unregisterCallback(mMediaControllerCallback); + } + mMediaController = newController; + if (mMediaController != null) { + mMediaController.registerCallback(mMediaControllerCallback); + } + if (updateMediaControllerMetadata() && mNotified) { + // update notification + notifyPipNotification(); + } + } + }; private final BroadcastReceiver mEventReceiver = new BroadcastReceiver() { @Override @@ -153,17 +154,17 @@ public class PipNotification { } switch (intent.getAction()) { case ACTION_MENU: - mPipManager.showPictureInPictureMenu(); + mPipController.showPictureInPictureMenu(); break; case ACTION_CLOSE: - mPipManager.closePip(); + mPipController.closePip(); break; } } }; public PipNotification(Context context, BroadcastDispatcher broadcastDispatcher, - PipManager pipManager) { + PipController pipController) { mPackageManager = context.getPackageManager(); mNotificationManager = (NotificationManager) context.getSystemService( @@ -177,9 +178,9 @@ public class PipNotification { .setContentIntent(createPendingIntent(context, ACTION_MENU)) .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE))); - mPipManager = pipManager; - mPipManager.addListener(mPipListener); - mPipManager.addMediaListener(mPipMediaListener); + mPipController = pipController; + pipController.addListener(mPipListener); + pipController.addMediaListener(mPipMediaListener); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ACTION_MENU); @@ -190,7 +191,7 @@ public class PipNotification { } /** - * Called by {@link PipManager} when the configuration is changed. + * Called by {@link PipController} when the configuration is changed. */ void onConfigurationChanged(Context context) { Resources res = context.getResources(); @@ -227,8 +228,8 @@ public class PipNotification { private boolean updateMediaControllerMetadata() { String title = null; Bitmap art = null; - if (mPipManager.getMediaController() != null) { - MediaMetadata metadata = mPipManager.getMediaController().getMetadata(); + if (mPipController.getMediaController() != null) { + MediaMetadata metadata = mPipController.getMediaController().getMetadata(); if (metadata != null) { title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE); if (TextUtils.isEmpty(title)) { @@ -248,6 +249,7 @@ public class PipNotification { return false; } + private String getNotificationTitle() { if (!TextUtils.isEmpty(mMediaTitle)) { return mMediaTitle; diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java deleted file mode 100644 index 52b38a91a58f9..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.systemui.pip.tv.dagger; - -import android.app.Activity; - -import com.android.systemui.pip.BasePipManager; -import com.android.systemui.pip.tv.PipManager; -import com.android.systemui.pip.tv.PipMenuActivity; - -import dagger.Binds; -import dagger.Module; -import dagger.multibindings.ClassKey; -import dagger.multibindings.IntoMap; - -/** - * Dagger module for TV Pip. - */ -@Module(subcomponents = {TvPipComponent.class}) -public abstract class PipModule { - - /** Binds PipManager as the default BasePipManager. */ - @Binds - public abstract BasePipManager providePipManager(PipManager pipManager); - - - /** Inject into PipMenuActivity. */ - @Binds - @IntoMap - @ClassKey(PipMenuActivity.class) - public abstract Activity providePipMenuActivity(PipMenuActivity activity); -} diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 263bbdbf7c351..62b35f9f5e2d0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -75,8 +75,8 @@ import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.onehanded.OneHandedUI; +import com.android.systemui.pip.Pip; import com.android.systemui.pip.PipAnimationController; -import com.android.systemui.pip.PipUI; import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.shared.recents.IOverviewProxy; @@ -122,7 +122,7 @@ public class OverviewProxyService extends CurrentUserTracker implements private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000; private final Context mContext; - private final PipUI mPipUI; + private final Optional mPipOptional; private final Optional> mStatusBarOptionalLazy; private final Optional mSplitScreenOptional; private SysUiState mSysUiState; @@ -388,7 +388,8 @@ public class OverviewProxyService extends CurrentUserTracker implements } long token = Binder.clearCallingIdentity(); try { - mPipUI.setShelfHeight(visible, shelfHeight); + mPipOptional.ifPresent( + pip -> pip.setShelfHeight(visible, shelfHeight)); } finally { Binder.restoreCallingIdentity(token); } @@ -413,7 +414,9 @@ public class OverviewProxyService extends CurrentUserTracker implements } long token = Binder.clearCallingIdentity(); try { - mPipUI.setPinnedStackAnimationType(PipAnimationController.ANIM_TYPE_ALPHA); + mPipOptional.ifPresent( + pip -> pip.setPinnedStackAnimationType( + PipAnimationController.ANIM_TYPE_ALPHA)); } finally { Binder.restoreCallingIdentity(token); } @@ -426,7 +429,8 @@ public class OverviewProxyService extends CurrentUserTracker implements } long token = Binder.clearCallingIdentity(); try { - mPipUI.setPinnedStackAnimationListener(listener); + mPipOptional.ifPresent( + pip -> pip.setPinnedStackAnimationListener(listener)); } finally { Binder.restoreCallingIdentity(token); } @@ -603,14 +607,16 @@ public class OverviewProxyService extends CurrentUserTracker implements @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Inject public OverviewProxyService(Context context, CommandQueue commandQueue, - Lazy navBarControllerLazy, NavigationModeController navModeController, + Lazy navBarControllerLazy, + NavigationModeController navModeController, NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, - PipUI pipUI, Optional splitScreenOptional, + Optional pipOptional, + Optional splitScreenOptional, Optional> statusBarOptionalLazy, OneHandedUI oneHandedUI, BroadcastDispatcher broadcastDispatcher) { super(broadcastDispatcher); mContext = context; - mPipUI = pipUI; + mPipOptional = pipOptional; mStatusBarOptionalLazy = statusBarOptionalLazy; mHandler = new Handler(); mNavBarControllerLazy = navBarControllerLazy; @@ -916,6 +922,7 @@ public class OverviewProxyService extends CurrentUserTracker implements /** * Notifies the Launcher of split screen size changes + * * @param secondaryWindowBounds Bounds of the secondary window including the insets * @param secondaryWindowInsets stable insets received by the secondary window */ diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java index 9a44bf12a3ef4..22fa0106795ad 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java @@ -17,12 +17,11 @@ package com.android.systemui.tv; import com.android.systemui.dagger.GlobalRootComponent; -import com.android.systemui.pip.tv.dagger.PipModule; import dagger.Binds; import dagger.Module; -@Module(includes = {PipModule.class}) +@Module() interface TvSystemUIBinder { @Binds GlobalRootComponent bindGlobalRootComponent(TvGlobalRootComponent globalRootComponent); diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java index d727bfbdf48a2..c5bb9c1b6f48f 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java @@ -62,7 +62,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.wmshell.WMShellModule; +import com.android.systemui.wmshell.TvWMShellModule; import javax.inject.Named; @@ -76,7 +76,7 @@ import dagger.Provides; */ @Module(includes = { QSModule.class, - WMShellModule.class + TvWMShellModule.class, }, subcomponents = { }) diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java new file mode 100644 index 0000000000000..d8cb280bc7e04 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 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 com.android.systemui.wmshell; + +import android.content.Context; +import android.os.Handler; +import android.view.IWindowManager; + +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.pip.Pip; +import com.android.systemui.pip.PipBoundsHandler; +import com.android.systemui.pip.PipSurfaceTransactionHelper; +import com.android.systemui.pip.PipTaskOrganizer; +import com.android.systemui.pip.PipUiEventLogger; +import com.android.systemui.pip.tv.PipController; +import com.android.systemui.pip.tv.PipNotification; +import com.android.systemui.pip.tv.dagger.TvPipComponent; +import com.android.systemui.stackdivider.SplitScreen; +import com.android.systemui.stackdivider.SplitScreenController; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.SystemWindows; +import com.android.wm.shell.common.TransactionPool; + +import java.util.Optional; + +import dagger.Module; +import dagger.Provides; + +/** + * Provides dependencies from {@link com.android.wm.shell} which could be customized among different + * branches of SystemUI. + */ +// TODO(b/162923491): Move most of these dependencies into WMSingleton scope. +@Module(includes = WMShellBaseModule.class, subcomponents = {TvPipComponent.class}) +public class TvWMShellModule { + @SysUISingleton + @Provides + static DisplayImeController provideDisplayImeController(IWindowManager wmService, + DisplayController displayController, @Main Handler mainHandler, + TransactionPool transactionPool) { + return new DisplayImeController(wmService, displayController, mainHandler, transactionPool); + } + + @SysUISingleton + @Provides + static Pip providePipController(Context context, + BroadcastDispatcher broadcastDispatcher, + PipBoundsHandler pipBoundsHandler, + PipSurfaceTransactionHelper pipSurfaceTransactionHelper, + PipTaskOrganizer pipTaskOrganizer) { + return new PipController(context, broadcastDispatcher, pipBoundsHandler, + pipSurfaceTransactionHelper, pipTaskOrganizer); + } + + @SysUISingleton + @Provides + static SplitScreen provideSplitScreen(Context context, + DisplayController displayController, SystemWindows systemWindows, + DisplayImeController displayImeController, @Main Handler handler, + TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer) { + return new SplitScreenController(context, displayController, systemWindows, + displayImeController, handler, transactionPool, shellTaskOrganizer); + } + + @SysUISingleton + @Provides + static PipNotification providePipNotification(Context context, + BroadcastDispatcher broadcastDispatcher, + PipController pipController) { + return new PipNotification(context, broadcastDispatcher, pipController); + } + + @SysUISingleton + @Provides + static PipBoundsHandler providesPipBoundsHandler(Context context) { + return new PipBoundsHandler(context); + } + + @SysUISingleton + @Provides + static PipTaskOrganizer providesPipTaskOrganizer(Context context, + PipBoundsHandler pipBoundsHandler, + PipSurfaceTransactionHelper pipSurfaceTransactionHelper, + Optional splitScreenOptional, DisplayController displayController, + PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) { + return new PipTaskOrganizer(context, pipBoundsHandler, + pipSurfaceTransactionHelper, splitScreenOptional, displayController, + pipUiEventLogger, shellTaskOrganizer); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index ee404ca980b20..e1e18a22af51b 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -25,10 +25,12 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.SystemUI; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.pip.Pip; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.tracing.ProtoTraceable; import com.android.systemui.stackdivider.SplitScreen; +import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.tracing.ProtoTracer; import com.android.systemui.tracing.nano.SystemUiTraceProto; import com.android.wm.shell.common.DisplayImeController; @@ -46,20 +48,27 @@ import javax.inject.Inject; * Proxy in SysUiScope to delegate events to controllers in WM Shell library. */ @SysUISingleton -public final class WMShell extends SystemUI implements ProtoTraceable { - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; +public final class WMShell extends SystemUI implements ProtoTraceable, + CommandQueue.Callbacks { + private final CommandQueue mCommandQueue; private final DisplayImeController mDisplayImeController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final Optional mPipOptional; private final Optional mSplitScreenOptional; private final ProtoTracer mProtoTracer; @Inject - WMShell(Context context, KeyguardUpdateMonitor keyguardUpdateMonitor, + public WMShell(Context context, CommandQueue commandQueue, + KeyguardUpdateMonitor keyguardUpdateMonitor, DisplayImeController displayImeController, + Optional pipOptional, Optional splitScreenOptional, ProtoTracer protoTracer) { super(context); + mCommandQueue = commandQueue; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mDisplayImeController = displayImeController; + mPipOptional = pipOptional; mSplitScreenOptional = splitScreenOptional; mProtoTracer = protoTracer; mProtoTracer.add(this); @@ -70,11 +79,22 @@ public final class WMShell extends SystemUI implements ProtoTraceable splitScreenOptional, DisplayController displayController, + PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) { + return new PipTaskOrganizer(context, pipBoundsHandler, + pipSurfaceTransactionHelper, splitScreenOptional, displayController, + pipUiEventLogger, shellTaskOrganizer); + } + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java new file mode 100644 index 0000000000000..2f3c86dfc8ae5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 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 com.android.systemui.wmshell; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Instrumentation; +import android.content.Context; +import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.pip.Pip; +import com.android.systemui.pip.tv.PipController; +import com.android.systemui.stackdivider.SplitScreen; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.tracing.ProtoTracer; +import com.android.wm.shell.common.DisplayImeController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Optional; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class WMShellTest extends SysuiTestCase { + + Instrumentation mInstrumentation; + WMShell mWMShell; + @Mock Context mContext; + @Mock CommandQueue mCommandQueue; + @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock DisplayImeController mDisplayImeController; + @Mock Optional mPipOptional; + @Mock Optional mSplitScreenOptional; + @Mock PipController mPipController; + @Mock ProtoTracer mProtoTracer; + + @Before + public void setUp() throws Exception { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + MockitoAnnotations.initMocks(this); + mWMShell = new WMShell(mContext, mCommandQueue, mKeyguardUpdateMonitor, + mDisplayImeController, mPipOptional, mSplitScreenOptional, mProtoTracer); + mWMShell.start(); + when(mPipOptional.get()).thenReturn(mPipController); + } + + @Test + public void testWMShellRegisterCommandQueue() { + verify(mCommandQueue, times(1)).addCallback(mWMShell); + } +}