Merge "Integrate PipUI PipManager to PipController (7/N)"

This commit is contained in:
TreeHugger Robot
2020-09-01 00:50:44 +00:00
committed by Android (Google) Code Review
27 changed files with 644 additions and 424 deletions

View File

@@ -123,7 +123,6 @@
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
<item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>com.android.systemui.LatencyTester</item>
<item>com.android.systemui.globalactions.GlobalActionsComponent</item>

View File

@@ -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})

View File

@@ -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

View File

@@ -516,7 +516,7 @@
android:excludeFromRecents="true"
android:visibleToInstantApps="true"/>
<!-- started from PipUI -->
<!-- started from PipController -->
<activity
android:name=".pip.tv.PipMenuActivity"
android:permission="com.android.systemui.permission.SELF"

View File

@@ -115,10 +115,6 @@ Shows UI for keyboard shortcuts (triggered by keyboard shortcut).
Shows the overlay controls when One handed is triggered.
### [com.android.systemui.pip.PipUI](/packages/SystemUI/src/com/android/systemui/pip/PipUI.java)
Shows the overlay controls when Pip is showing.
### [com.android.systemui.shortcut.ShortcutKeyDispatcher](/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java)
Dispatches shortcut to System UI components.

View File

@@ -33,7 +33,6 @@
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
<item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>@string/config_systemUIVendorServiceComponent</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>

View File

@@ -306,7 +306,6 @@
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
<item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>@string/config_systemUIVendorServiceComponent</item>
<item>com.android.systemui.util.leak.GarbageMonitor$Service</item>

View File

@@ -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})

View File

@@ -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

View File

@@ -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) {}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}
}

View File

@@ -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<SplitScreen> 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);

View File

@@ -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);
}

View File

@@ -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<SplitScreen> 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. */

View File

@@ -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<Pip> 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<Pip> 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<MediaController> 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 {

View File

@@ -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<Pip> 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<Pip> 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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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<Pip> mPipOptional;
private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
private final Optional<SplitScreen> 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<NavigationBarController> navBarControllerLazy, NavigationModeController navModeController,
Lazy<NavigationBarController> navBarControllerLazy,
NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
PipUI pipUI, Optional<SplitScreen> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<Lazy<StatusBar>> 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
*/

View File

@@ -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);

View File

@@ -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 = {
})

View File

@@ -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<SplitScreen> splitScreenOptional, DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
return new PipTaskOrganizer(context, pipBoundsHandler,
pipSurfaceTransactionHelper, splitScreenOptional, displayController,
pipUiEventLogger, shellTaskOrganizer);
}
}

View File

@@ -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<SystemUiTraceProto> {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTraceProto>,
CommandQueue.Callbacks {
private final CommandQueue mCommandQueue;
private final DisplayImeController mDisplayImeController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final Optional<Pip> mPipOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private final ProtoTracer mProtoTracer;
@Inject
WMShell(Context context, KeyguardUpdateMonitor keyguardUpdateMonitor,
public WMShell(Context context, CommandQueue commandQueue,
KeyguardUpdateMonitor keyguardUpdateMonitor,
DisplayImeController displayImeController,
Optional<Pip> pipOptional,
Optional<SplitScreen> 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<SystemUiTr
// This is to prevent circular init problem by separating registration step out of its
// constructor. And make sure the initialization of DisplayImeController won't depend on
// specific feature anymore.
mCommandQueue.addCallback(this);
mDisplayImeController.startMonitorDisplays();
mPipOptional.ifPresent(this::initPip);
mSplitScreenOptional.ifPresent(this::initSplitScreen);
}
private void initPip(Pip pip) {
mCommandQueue.addCallback(new CommandQueue.Callbacks() {
@Override
public void showPictureInPictureMenu() {
pip.showPictureInPictureMenu();
}
});
}
private void initSplitScreen(SplitScreen splitScreen) {
mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
@Override

View File

@@ -23,8 +23,11 @@ import android.view.IWindowManager;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipUiEventLogger;
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;
@@ -74,6 +77,13 @@ public abstract class WMShellBaseModule {
return new PipUiEventLogger(uiEventLogger);
}
@SysUISingleton
@Provides
static PipSurfaceTransactionHelper providesPipSurfaceTransactionHelper(Context context,
ConfigurationController configController) {
return new PipSurfaceTransactionHelper(context, configController);
}
@SysUISingleton
@Provides
static SystemWindows provideSystemWindows(DisplayController displayController,
@@ -89,6 +99,9 @@ public abstract class WMShellBaseModule {
return organizer;
}
@BindsOptionalOf
abstract Pip optionalPip();
@BindsOptionalOf
abstract SplitScreen optionalSplitScreen();
}

View File

@@ -20,16 +20,29 @@ 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.model.SysUiState;
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.phone.PipController;
import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.stackdivider.SplitScreenController;
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.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;
@@ -48,6 +61,26 @@ public class WMShellModule {
return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
}
@SysUISingleton
@Provides
static Pip providePipController(Context context,
BroadcastDispatcher broadcastDispatcher,
ConfigurationController configController,
DeviceConfigProxy deviceConfig,
DisplayController displayController,
FloatingContentCoordinator floatingContentCoordinator,
SysUiState sysUiState,
PipBoundsHandler pipBoundsHandler,
PipSurfaceTransactionHelper surfaceTransactionHelper,
PipTaskOrganizer pipTaskOrganizer,
PipUiEventLogger pipUiEventLogger) {
return new PipController(context, broadcastDispatcher, configController, deviceConfig,
displayController, floatingContentCoordinator, sysUiState, pipBoundsHandler,
surfaceTransactionHelper,
pipTaskOrganizer,
pipUiEventLogger);
}
@SysUISingleton
@Provides
static SplitScreen provideSplitScreen(Context context,
@@ -57,4 +90,23 @@ public class WMShellModule {
return new SplitScreenController(context, displayController, systemWindows,
displayImeController, handler, transactionPool, shellTaskOrganizer);
}
@SysUISingleton
@Provides
static PipBoundsHandler providesPipBoundsHandler(Context context) {
return new PipBoundsHandler(context);
}
@SysUISingleton
@Provides
static PipTaskOrganizer providesPipTaskOrganizer(Context context,
PipBoundsHandler pipBoundsHandler,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
return new PipTaskOrganizer(context, pipBoundsHandler,
pipSurfaceTransactionHelper, splitScreenOptional, displayController,
pipUiEventLogger, shellTaskOrganizer);
}
}

View File

@@ -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<Pip> mPipOptional;
@Mock Optional<SplitScreen> 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);
}
}