[CD Taskbar] Staging - Add/Remove Taskbars
Tablet to Monitor connection renders Extended Mode.
Test: Manual
Bug: 390426030
Flag: com.android.window.flags.enable_taskbar_connected_displays
Change-Id: I16e2e4911446c42d5351d7086154d6c720bca284
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index b9d1275..11cc22d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -47,7 +47,6 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import static com.android.window.flags.Flags.enableStartLaunchTransitionFromTaskbarBugfix;
-import static com.android.window.flags.Flags.enableTaskbarConnectedDisplays;
import static com.android.wm.shell.Flags.enableTinyTaskbar;
import static java.lang.invoke.MethodHandles.Lookup.PROTECTED;
@@ -77,6 +76,7 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.Toast;
+import android.window.DesktopExperienceFlags;
import android.window.DesktopModeFlags;
import android.window.RemoteTransition;
@@ -434,8 +434,9 @@
.setIsTransientTaskbar(true)
.build();
}
- mNavMode = (enableTaskbarConnectedDisplays() && !mIsPrimaryDisplay)
- ? NavigationMode.THREE_BUTTONS : DisplayController.getNavigationMode(this);
+ mNavMode = (DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()
+ && !mIsPrimaryDisplay) ? NavigationMode.THREE_BUTTONS
+ : DisplayController.getNavigationMode(this);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 96bcffd..46802c3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -32,7 +32,6 @@
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR;
import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_TASKBAR;
-import static com.android.window.flags.Flags.enableTaskbarConnectedDisplays;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
@@ -53,6 +52,7 @@
import android.view.MotionEvent;
import android.view.WindowManager;
import android.widget.FrameLayout;
+import android.window.DesktopExperienceFlags;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -118,11 +118,12 @@
Settings.Secure.NAV_BAR_KIDS_MODE);
private final Context mBaseContext;
+ private TaskbarNavButtonCallbacks mNavCallbacks;
// TODO: Remove this during the connected displays lifecycle refactor.
private final Context mPrimaryWindowContext;
private WindowManager mPrimaryWindowManager;
- private final TaskbarNavButtonController mDefaultNavButtonController;
- private final ComponentCallbacks mDefaultComponentCallbacks;
+ private TaskbarNavButtonController mPrimaryNavButtonController;
+ private ComponentCallbacks mPrimaryComponentCallbacks;
private final SimpleBroadcastReceiver mShutdownReceiver;
@@ -140,6 +141,11 @@
private final SparseArray<FrameLayout> mRootLayouts = new SparseArray<>();
/** DisplayId - {@link Boolean} map indicating if RootLayout was added to window. */
private final SparseBooleanArray mAddedRootLayouts = new SparseBooleanArray();
+ /** DisplayId - {@link TaskbarNavButtonController} map for Connected Display. */
+ private final SparseArray<TaskbarNavButtonController> mNavButtonControllers =
+ new SparseArray<>();
+ /** DisplayId - {@link ComponentCallbacks} map for Connected Display. */
+ private final SparseArray<ComponentCallbacks> mComponentCallbacks = new SparseArray<>();
private StatefulActivity mActivity;
private RecentsViewContainer mRecentsViewContainer;
@@ -158,27 +164,35 @@
private class RecreationListener implements DisplayController.DisplayInfoChangeListener {
@Override
public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
-
if ((flags & CHANGE_DENSITY) != 0) {
- Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "Display density changed");
+ debugTaskbarManager("onDisplayInfoChanged - Display density changed",
+ context.getDisplayId());
}
if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
- Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "Navigation mode changed");
+ debugTaskbarManager("onDisplayInfoChanged - Navigation mode changed",
+ context.getDisplayId());
}
if ((flags & CHANGE_DESKTOP_MODE) != 0) {
- Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "Desktop mode changed");
+ debugTaskbarManager("onDisplayInfoChanged - Desktop mode changed",
+ context.getDisplayId());
}
if ((flags & CHANGE_TASKBAR_PINNING) != 0) {
- Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "Taskbar pinning changed");
+ debugTaskbarManager("onDisplayInfoChanged - Taskbar pinning changed",
+ context.getDisplayId());
}
if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE | CHANGE_DESKTOP_MODE
| CHANGE_TASKBAR_PINNING)) != 0) {
+ debugTaskbarManager("onDisplayInfoChanged - Recreating Taskbar!",
+ context.getDisplayId());
recreateTaskbar();
}
}
}
- private final SettingsCache.OnChangeListener mOnSettingsChangeListener = c -> recreateTaskbar();
+ private final SettingsCache.OnChangeListener mOnSettingsChangeListener = c -> {
+ debugTaskbarManager("Settings changed! Recreating Taskbar!");
+ recreateTaskbar();
+ };
private boolean mUserUnlocked = false;
@@ -191,6 +205,7 @@
@Override
public void run() {
int displayId = getDefaultDisplayId();
+ debugTaskbarManager("mActivityOnDestroyCallback running!", displayId);
if (mActivity != null) {
displayId = mActivity.getDisplayId();
mActivity.removeOnDeviceProfileChangeListener(
@@ -204,7 +219,6 @@
mRecentsViewContainer = null;
}
mActivity = null;
- debugWhyTaskbarNotDestroyed("clearActivity");
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
if (taskbar != null) {
taskbar.setUIController(TaskbarUIController.DEFAULT);
@@ -217,28 +231,27 @@
new UnfoldTransitionProgressProvider.TransitionProgressListener() {
@Override
public void onTransitionStarted() {
- Log.d(TASKBAR_NOT_DESTROYED_TAG,
- "fold/unfold transition started getting called.");
+ debugTaskbarManager("fold/unfold transition started getting called.");
}
@Override
public void onTransitionProgress(float progress) {
- Log.d(TASKBAR_NOT_DESTROYED_TAG,
- "fold/unfold transition progress : " + progress);
+ debugTaskbarManager(
+ "fold/unfold transition progress getting called. | progress="
+ + progress);
}
@Override
public void onTransitionFinishing() {
- Log.d(TASKBAR_NOT_DESTROYED_TAG,
+ debugTaskbarManager(
"fold/unfold transition finishing getting called.");
}
@Override
public void onTransitionFinished() {
- Log.d(TASKBAR_NOT_DESTROYED_TAG,
+ debugTaskbarManager(
"fold/unfold transition finished getting called.");
-
}
};
@@ -250,20 +263,22 @@
RecentsDisplayModel recentsDisplayModel) {
mBaseContext = context;
mAllAppsActionManager = allAppsActionManager;
+ mNavCallbacks = navCallbacks;
mRecentsDisplayModel = recentsDisplayModel;
- mPrimaryWindowContext = createWindowContext(getDefaultDisplayId());
- if (enableTaskbarNoRecreate()) {
- mPrimaryWindowManager = mPrimaryWindowContext.getSystemService(WindowManager.class);
- createTaskbarRootLayout(getDefaultDisplayId());
- }
- mDefaultNavButtonController = createDefaultNavButtonController(context, navCallbacks);
- mDefaultComponentCallbacks = createDefaultComponentCallbacks();
+
+ // Set up primary display.
+ int primaryDisplayId = getDefaultDisplayId();
+ debugTaskbarManager("TaskbarManager constructor", primaryDisplayId);
+ mPrimaryWindowContext = createWindowContext(primaryDisplayId);
+ mPrimaryWindowManager = mPrimaryWindowContext.getSystemService(WindowManager.class);
+ createTaskbarRootLayout(primaryDisplayId);
+ createNavButtonController(primaryDisplayId);
+ createAndRegisterComponentCallbacks(primaryDisplayId);
+
SettingsCache.INSTANCE.get(mPrimaryWindowContext)
.register(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
SettingsCache.INSTANCE.get(mPrimaryWindowContext)
.register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
- Log.d(TASKBAR_NOT_DESTROYED_TAG, "registering component callbacks from constructor.");
- mPrimaryWindowContext.registerComponentCallbacks(mDefaultComponentCallbacks);
mShutdownReceiver =
new SimpleBroadcastReceiver(
mPrimaryWindowContext, UI_HELPER_EXECUTOR, i -> destroyAllTaskbars());
@@ -281,82 +296,10 @@
mTaskbarBroadcastReceiver.register(RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR);
});
- debugWhyTaskbarNotDestroyed("TaskbarManager created");
+ debugTaskbarManager("TaskbarManager created");
recreateTaskbar();
}
- @NonNull
- private TaskbarNavButtonController createDefaultNavButtonController(Context context,
- TaskbarNavButtonCallbacks navCallbacks) {
- return new TaskbarNavButtonController(
- context,
- navCallbacks,
- SystemUiProxy.INSTANCE.get(mPrimaryWindowContext),
- new Handler(),
- new ContextualSearchInvoker(mPrimaryWindowContext));
- }
-
- private ComponentCallbacks createDefaultComponentCallbacks() {
- return new ComponentCallbacks() {
- private Configuration mOldConfig =
- mPrimaryWindowContext.getResources().getConfiguration();
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- Trace.instantForTrack(Trace.TRACE_TAG_APP, "TaskbarManager",
- "onConfigurationChanged: " + newConfig);
- debugWhyTaskbarNotDestroyed(
- "TaskbarManager#mComponentCallbacks.onConfigurationChanged: " + newConfig);
- // TODO: adapt this logic to be specific to different displays.
- DeviceProfile dp = mUserUnlocked
- ? LauncherAppState.getIDP(mPrimaryWindowContext).getDeviceProfile(
- mPrimaryWindowContext)
- : null;
- int configDiff = mOldConfig.diff(newConfig) & ~SKIP_RECREATE_CONFIG_CHANGES;
-
- if ((configDiff & ActivityInfo.CONFIG_UI_MODE) != 0) {
- Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "onConfigurationChanged: theme changed");
- // Only recreate for theme changes, not other UI mode changes such as docking.
- int oldUiNightMode = (mOldConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
- int newUiNightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
- if (oldUiNightMode == newUiNightMode) {
- configDiff &= ~ActivityInfo.CONFIG_UI_MODE;
- }
- }
-
- debugWhyTaskbarNotDestroyed("ComponentCallbacks#onConfigurationChanged() "
- + "configDiff=" + Configuration.configurationDiffToString(configDiff));
- if (configDiff != 0 || getCurrentActivityContext() == null) {
- recreateTaskbar();
- } else {
- // Config change might be handled without re-creating the taskbar
- if (dp != null && !isTaskbarEnabled(dp)) {
- destroyDefaultTaskbar();
- } else {
- if (dp != null && isTaskbarEnabled(dp)) {
- if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
- // Re-initialize for screen size change? Should this be done
- // by looking at screen-size change flag in configDiff in the
- // block above?
- recreateTaskbar();
- } else {
- getCurrentActivityContext().updateDeviceProfile(dp);
- }
- }
- getCurrentActivityContext().onConfigurationChanged(configDiff);
- }
- }
- mOldConfig = new Configuration(newConfig);
- // reset taskbar was pinned value, so we don't automatically unstash taskbar upon
- // user unfolding the device.
- mSharedState.setTaskbarWasPinned(false);
- }
-
- @Override
- public void onLowMemory() { }
- };
- }
-
private void destroyAllTaskbars() {
for (int i = 0; i < mTaskbars.size(); i++) {
int displayId = mTaskbars.keyAt(i);
@@ -365,23 +308,18 @@
}
}
- private void destroyDefaultTaskbar() {
- destroyTaskbarForDisplay(getDefaultDisplayId());
- }
-
private void destroyTaskbarForDisplay(int displayId) {
Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "destroyTaskbarForDisplay: " + displayId);
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
- debugWhyTaskbarNotDestroyed("destroyTaskbarForDisplay: " + taskbar, displayId);
+ debugTaskbarManager("destroyTaskbarForDisplay: " + taskbar, displayId);
if (taskbar != null) {
taskbar.onDestroy();
// remove all defaults that we store
removeTaskbarFromMap(displayId);
}
- // make this display-specific
- DeviceProfile dp = mUserUnlocked ?
- LauncherAppState.getIDP(getWindowContext(displayId)).getDeviceProfile(
- getWindowContext(displayId)) : null;
+ // TODO (b/381113004): make this display-specific via getWindowContext()
+ DeviceProfile dp = mUserUnlocked ? LauncherAppState.getIDP(
+ mPrimaryWindowContext).getDeviceProfile(mPrimaryWindowContext) : null;
if (dp == null || !isTaskbarEnabled(dp)) {
removeTaskbarRootViewFromWindow(displayId);
}
@@ -431,7 +369,10 @@
DisplayController.INSTANCE.get(mPrimaryWindowContext).addChangeListener(
mRecreationListener);
recreateTaskbar();
- addTaskbarRootViewToWindow(getDefaultDisplayId());
+ for (int i = 0; i < mTaskbars.size(); i++) {
+ int displayId = mTaskbars.keyAt(i);
+ addTaskbarRootViewToWindow(displayId);
+ }
}
/**
@@ -443,7 +384,7 @@
}
removeActivityCallbacksAndListeners();
mActivity = activity;
- debugWhyTaskbarNotDestroyed("Set mActivity=" + mActivity);
+ debugTaskbarManager("Set mActivity=" + mActivity);
mActivity.addOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
Log.d(TASKBAR_NOT_DESTROYED_TAG,
"registering activity lifecycle callbacks from setActivity().");
@@ -492,7 +433,7 @@
return ql.getUnfoldTransitionProgressProvider();
}
} else {
- return SystemUiProxy.INSTANCE.get(mPrimaryWindowContext).getUnfoldTransitionProvider();
+ return SystemUiProxy.INSTANCE.get(mBaseContext).getUnfoldTransitionProvider();
}
return null;
}
@@ -530,13 +471,21 @@
/**
* This method is called multiple times (ex. initial init, then when user unlocks) in which case
- * we fully want to destroy the existing default display's taskbar and create a new one.
+ * we fully want to destroy existing taskbars and create all desired new ones.
* In other case (folding/unfolding) we don't need to remove and add window.
*/
@VisibleForTesting
public synchronized void recreateTaskbar() {
- // TODO: make this recreate all taskbars in map.
- recreateTaskbarForDisplay(getDefaultDisplayId());
+ // Handles initial creation case.
+ if (mTaskbars.size() == 0) {
+ recreateTaskbarForDisplay(getDefaultDisplayId());
+ return;
+ }
+
+ for (int i = 0; i < mTaskbars.size(); i++) {
+ int displayId = mTaskbars.keyAt(i);
+ recreateTaskbarForDisplay(displayId);
+ }
}
/**
@@ -545,13 +494,12 @@
* In other case (folding/unfolding) we don't need to remove and add window.
*/
private void recreateTaskbarForDisplay(int displayId) {
- Trace.beginSection("recreateTaskbar");
+ Trace.beginSection("recreateTaskbarForDisplay");
try {
Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "recreateTaskbarForDisplay: " + displayId);
- // TODO: make this code display specific
- DeviceProfile dp = mUserUnlocked ?
- LauncherAppState.getIDP(getWindowContext(displayId)).getDeviceProfile(
- getWindowContext(displayId)) : null;
+ // TODO (b/381113004): make this display-specific via getWindowContext()
+ DeviceProfile dp = mUserUnlocked ? LauncherAppState.getIDP(
+ mPrimaryWindowContext).getDeviceProfile(mPrimaryWindowContext) : null;
// All Apps action is unrelated to navbar unification, so we only need to check DP.
final boolean isLargeScreenTaskbar = dp != null && dp.isTaskbarPresent;
@@ -559,15 +507,17 @@
destroyTaskbarForDisplay(displayId);
+ boolean displayExists = getDisplay(displayId) != null;
boolean isTaskbarEnabled = dp != null && isTaskbarEnabled(dp);
- debugWhyTaskbarNotDestroyed("recreateTaskbar: isTaskbarEnabled=" + isTaskbarEnabled
+ debugTaskbarManager("recreateTaskbarForDisplay: isTaskbarEnabled=" + isTaskbarEnabled
+ " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
+ " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
- + " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent));
- if (!isTaskbarEnabled || !isLargeScreenTaskbar) {
- SystemUiProxy.INSTANCE.get(mPrimaryWindowContext)
+ + " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent)
+ + " displayExists=" + displayExists);
+ if (!isTaskbarEnabled || !isLargeScreenTaskbar || !displayExists) {
+ SystemUiProxy.INSTANCE.get(mBaseContext)
.notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
- if (!isTaskbarEnabled) {
+ if (!isTaskbarEnabled || !displayExists) {
return;
}
}
@@ -575,6 +525,11 @@
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
if (enableTaskbarNoRecreate() || taskbar == null) {
taskbar = createTaskbarActivityContext(dp, displayId);
+ if (taskbar == null) {
+ debugTaskbarManager(
+ "recreateTaskbarForDisplay: new taskbar instance is null!", displayId);
+ return;
+ }
} else {
taskbar.updateDeviceProfile(dp);
}
@@ -585,7 +540,8 @@
// Non default displays should not use LauncherTaskbarUIController as they shouldn't
// have access to the Launcher activity.
- if (enableTaskbarConnectedDisplays() && !isDefaultDisplay(displayId)) {
+ if (!isDefaultDisplay(displayId)
+ && DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()) {
taskbar.setUIController(createTaskbarUIControllerForNonDefaultDisplay(displayId));
} else if (mRecentsViewContainer != null) {
taskbar.setUIController(
@@ -622,8 +578,8 @@
}
public void onLongPressHomeEnabled(boolean assistantLongPressEnabled) {
- if (mDefaultNavButtonController != null) {
- mDefaultNavButtonController.setAssistantLongPressEnabled(assistantLongPressEnabled);
+ if (mPrimaryNavButtonController != null) {
+ mPrimaryNavButtonController.setAssistantLongPressEnabled(assistantLongPressEnabled);
}
}
@@ -746,13 +702,26 @@
* primary device or a previously mirroring display is switched to extended mode.
*/
public void onDisplayAddSystemDecorations(int displayId) {
- if (isDefaultDisplay(displayId) || !enableTaskbarConnectedDisplays()) {
+ Display display = getDisplay(displayId);
+ if (!DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue() || isDefaultDisplay(
+ displayId) || display == null) {
+ debugTaskbarManager("onDisplayAddSystemDecorations: not adding display");
+ return;
+ }
+
+ // TODO (b/391965805): remove once onDisplayAddSystemDecorations is working.
+ WindowManager wm = getWindowManager(displayId);
+ if (wm == null || !wm.shouldShowSystemDecors(displayId)) {
return;
}
Context newWindowContext = createWindowContext(displayId);
if (newWindowContext != null) {
addWindowContextToMap(displayId, newWindowContext);
+ createTaskbarRootLayout(displayId);
+ createNavButtonController(displayId);
+ createAndRegisterComponentCallbacks(displayId);
+ recreateTaskbarForDisplay(displayId);
}
}
@@ -761,12 +730,16 @@
* removed from the primary device.
*/
public void onDisplayRemoved(int displayId) {
- if (isDefaultDisplay(displayId) || !enableTaskbarConnectedDisplays()) {
+ if (!DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue() || isDefaultDisplay(
+ displayId)) {
return;
}
Context windowContext = getWindowContext(displayId);
if (windowContext != null) {
+ removeNavButtonController(displayId);
+ removeAndUnregisterComponentCallbacks(displayId);
+ destroyTaskbarForDisplay(displayId);
removeWindowContextFromMap(displayId);
}
}
@@ -796,7 +769,7 @@
*/
public void destroy() {
mRecentsViewContainer = null;
- debugWhyTaskbarNotDestroyed("TaskbarManager#destroy()");
+ debugTaskbarManager("TaskbarManager#destroy()");
removeActivityCallbacksAndListeners();
mTaskbarBroadcastReceiver.unregisterReceiverSafely();
@@ -809,7 +782,7 @@
SettingsCache.INSTANCE.get(mPrimaryWindowContext)
.unregister(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
- mPrimaryWindowContext.unregisterComponentCallbacks(mDefaultComponentCallbacks);
+ removeAndUnregisterComponentCallbacks(getDefaultDisplayId());
mShutdownReceiver.unregisterReceiverSafely();
destroyAllTaskbars();
}
@@ -836,15 +809,20 @@
private void addTaskbarRootViewToWindow(int displayId) {
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
if (!enableTaskbarNoRecreate() || taskbar == null) {
- Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG,
- "addTaskbarRootViewToWindow - taskbar null | displayId=" + displayId);
+ debugTaskbarManager("addTaskbarRootViewToWindow - taskbar null", displayId);
+ return;
+ }
+
+ if (getDisplay(displayId) == null) {
+ debugTaskbarManager("addTaskbarRootViewToWindow - display null", displayId);
return;
}
if (!isTaskbarRootLayoutAddedForDisplay(displayId)) {
FrameLayout rootLayout = getTaskbarRootLayoutForDisplay(displayId);
- if (rootLayout != null) {
- getWindowManager(displayId).addView(rootLayout, taskbar.getWindowLayoutParams());
+ WindowManager windowManager = getWindowManager(displayId);
+ if (rootLayout != null && windowManager != null) {
+ windowManager.addView(rootLayout, taskbar.getWindowLayoutParams());
mAddedRootLayouts.put(displayId, true);
} else {
Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW,
@@ -864,10 +842,14 @@
return;
}
- if (isTaskbarRootLayoutAddedForDisplay(displayId)) {
- getWindowManager(displayId).removeViewImmediate(rootLayout);
+ WindowManager windowManager = getWindowManager(displayId);
+ if (isTaskbarRootLayoutAddedForDisplay(displayId) && windowManager != null) {
+ windowManager.removeViewImmediate(rootLayout);
mAddedRootLayouts.put(displayId, false);
removeTaskbarRootLayoutFromMap(displayId);
+ } else {
+ debugTaskbarManager("removeTaskbarRootViewFromWindow - WindowManager is null",
+ displayId);
}
}
@@ -913,24 +895,164 @@
/**
* Creates a {@link TaskbarActivityContext} for the given display and adds it to the map.
+ * @param dp The {@link DeviceProfile} for the display.
+ * @param displayId The ID of the display.
*/
- private TaskbarActivityContext createTaskbarActivityContext(DeviceProfile dp, int displayId) {
- Display display = mBaseContext.getSystemService(DisplayManager.class).getDisplay(
- displayId);
- Context navigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
- ? mBaseContext.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
- : null;
+ private @Nullable TaskbarActivityContext createTaskbarActivityContext(DeviceProfile dp,
+ int displayId) {
+ Display display = getDisplay(displayId);
+ if (display == null) {
+ debugTaskbarManager("createTaskbarActivityContext: display null", displayId);
+ return null;
+ }
+
+ Context navigationBarPanelContext = null;
+ if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
+ navigationBarPanelContext = mBaseContext.createWindowContext(display,
+ TYPE_NAVIGATION_BAR_PANEL, null);
+ }
+
+ boolean isPrimaryDisplay = isDefaultDisplay(displayId)
+ || !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue();
TaskbarActivityContext newTaskbar = new TaskbarActivityContext(getWindowContext(displayId),
- navigationBarPanelContext, dp, mDefaultNavButtonController,
- mUnfoldProgressProvider, isDefaultDisplay(displayId),
- SystemUiProxy.INSTANCE.get(mPrimaryWindowContext));
+ navigationBarPanelContext, dp, getNavButtonController(displayId),
+ mUnfoldProgressProvider, isPrimaryDisplay,
+ SystemUiProxy.INSTANCE.get(mBaseContext));
addTaskbarToMap(displayId, newTaskbar);
return newTaskbar;
}
/**
+ * Create {@link ComponentCallbacks} for the given display and register it to the relevant
+ * WindowContext. For external displays, populate maps.
+ * @param displayId The ID of the display.
+ */
+ private void createAndRegisterComponentCallbacks(int displayId) {
+ ComponentCallbacks callbacks = new ComponentCallbacks() {
+ private Configuration mOldConfig =
+ getWindowContext(displayId).getResources().getConfiguration();
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, "TaskbarManager",
+ "onConfigurationChanged: " + newConfig);
+ debugTaskbarManager(
+ "TaskbarManager#mComponentCallbacks.onConfigurationChanged: " + newConfig);
+ // TODO (b/381113004): make this display-specific via getWindowContext()
+ DeviceProfile dp = mUserUnlocked ? LauncherAppState.getIDP(
+ mPrimaryWindowContext).getDeviceProfile(mPrimaryWindowContext) : null;
+ int configDiff = mOldConfig.diff(newConfig) & ~SKIP_RECREATE_CONFIG_CHANGES;
+
+ if ((configDiff & ActivityInfo.CONFIG_UI_MODE) != 0) {
+ Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "onConfigurationChanged: theme changed");
+ // Only recreate for theme changes, not other UI mode changes such as docking.
+ int oldUiNightMode = (mOldConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+ int newUiNightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+ if (oldUiNightMode == newUiNightMode) {
+ configDiff &= ~ActivityInfo.CONFIG_UI_MODE;
+ }
+ }
+
+ debugTaskbarManager("ComponentCallbacks#onConfigurationChanged() "
+ + "configDiff=" + Configuration.configurationDiffToString(configDiff));
+ if (configDiff != 0 || getCurrentActivityContext() == null) {
+ recreateTaskbar();
+ } else {
+ // Config change might be handled without re-creating the taskbar
+ if (dp != null && !isTaskbarEnabled(dp)) {
+ destroyTaskbarForDisplay(getDefaultDisplayId());
+ } else {
+ if (dp != null && isTaskbarEnabled(dp)) {
+ if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
+ // Re-initialize for screen size change? Should this be done
+ // by looking at screen-size change flag in configDiff in the
+ // block above?
+ recreateTaskbar();
+ } else {
+ getCurrentActivityContext().updateDeviceProfile(dp);
+ }
+ }
+ getCurrentActivityContext().onConfigurationChanged(configDiff);
+ }
+ }
+ mOldConfig = new Configuration(newConfig);
+ // reset taskbar was pinned value, so we don't automatically unstash taskbar upon
+ // user unfolding the device.
+ mSharedState.setTaskbarWasPinned(false);
+ }
+
+ @Override
+ public void onLowMemory() { }
+ };
+ if (isDefaultDisplay(displayId)
+ || !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()) {
+ mPrimaryComponentCallbacks = callbacks;
+ mPrimaryWindowContext.registerComponentCallbacks(callbacks);
+ } else {
+ mComponentCallbacks.put(displayId, callbacks);
+ getWindowContext(displayId).registerComponentCallbacks(callbacks);
+ }
+ }
+
+ /**
+ * Unregister {@link ComponentCallbacks} for the given display from its WindowContext. For
+ * external displays, remove from the map.
+ * @param displayId The ID of the display.
+ */
+ private void removeAndUnregisterComponentCallbacks(int displayId) {
+ if (isDefaultDisplay(displayId)
+ || !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()) {
+ mPrimaryWindowContext.unregisterComponentCallbacks(mPrimaryComponentCallbacks);
+ } else {
+ ComponentCallbacks callbacks = mComponentCallbacks.get(displayId);
+ getWindowContext(displayId).unregisterComponentCallbacks(callbacks);
+ mComponentCallbacks.delete(displayId);
+ }
+ }
+
+ /**
+ * Creates a {@link TaskbarNavButtonController} for the given display and adds it to the map
+ * if it doesn't already exist.
+ * @param displayId The ID of the display
+ */
+ private void createNavButtonController(int displayId) {
+ if (isDefaultDisplay(displayId)
+ || !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()) {
+ mPrimaryNavButtonController = new TaskbarNavButtonController(
+ mPrimaryWindowContext,
+ mNavCallbacks,
+ SystemUiProxy.INSTANCE.get(mBaseContext),
+ new Handler(),
+ new ContextualSearchInvoker(mBaseContext));
+ } else {
+ TaskbarNavButtonController navButtonController = new TaskbarNavButtonController(
+ getWindowContext(displayId),
+ mNavCallbacks,
+ SystemUiProxy.INSTANCE.get(mBaseContext),
+ new Handler(),
+ new ContextualSearchInvoker(mBaseContext));
+ mNavButtonControllers.put(displayId, navButtonController);
+ }
+ }
+
+ private TaskbarNavButtonController getNavButtonController(int displayId) {
+ return (isDefaultDisplay(displayId)
+ || !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue())
+ ? mPrimaryNavButtonController : mNavButtonControllers.get(displayId);
+ }
+
+ private void removeNavButtonController(int displayId) {
+ if (isDefaultDisplay(displayId)
+ || !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()) {
+ mPrimaryNavButtonController = null;
+ } else {
+ mNavButtonControllers.delete(displayId);
+ }
+ }
+
+ /**
* Adds the {@link TaskbarActivityContext} associated with the given display ID to taskbar
* map if there is not already a taskbar mapped to that displayId.
*
@@ -958,12 +1080,16 @@
*/
private void createTaskbarRootLayout(int displayId) {
Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "createTaskbarRootLayout: " + displayId);
+ if (!enableTaskbarNoRecreate()) {
+ return;
+ }
+
FrameLayout newTaskbarRootLayout = new FrameLayout(getWindowContext(displayId)) {
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// The motion events can be outside the view bounds of task bar, and hence
// manually dispatching them to the drag layer here.
- TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
if (taskbar != null && taskbar.getDragLayer().isAttachedToWindow()) {
return taskbar.getDragLayer().dispatchTouchEvent(ev);
}
@@ -1029,13 +1155,10 @@
* @param displayId The ID of the display for which to create the window context.
*/
private @Nullable Context createWindowContext(int displayId) {
- DisplayManager displayManager = mBaseContext.getSystemService(DisplayManager.class);
- if (displayManager == null) {
- return null;
- }
-
- Display display = displayManager.getDisplay(displayId);
+ debugTaskbarManager("createWindowContext: " + displayId);
+ Display display = getDisplay(displayId);
if (display == null) {
+ debugTaskbarManager("createWindowContext: display null", displayId);
return null;
}
@@ -1043,10 +1166,29 @@
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION && isDefaultDisplay(displayId)) {
windowType = TYPE_NAVIGATION_BAR;
}
+ debugTaskbarManager(
+ "createWindowContext: windowType=" + ((windowType == TYPE_NAVIGATION_BAR)
+ ? "TYPE_NAVIGATION_BAR" : "TYPE_NAVIGATION_BAR_PANEL"), displayId);
return mBaseContext.createWindowContext(display, windowType, null);
}
+ private @Nullable Display getDisplay(int displayId) {
+ DisplayManager displayManager = mBaseContext.getSystemService(DisplayManager.class);
+ if (displayManager == null) {
+ debugTaskbarManager("cannot get DisplayManager", displayId);
+ return null;
+ }
+
+ Display display = displayManager.getDisplay(displayId);
+ if (display == null) {
+ debugTaskbarManager("Cannot get display!", displayId);
+ return null;
+ }
+
+ return displayManager.getDisplay(displayId);
+ }
+
/**
* Retrieves the window context of the taskbar for the specified display.
*
@@ -1054,7 +1196,8 @@
* @return The Window Context {@link Context} for a given display or {@code null}.
*/
private Context getWindowContext(int displayId) {
- return (isDefaultDisplay(displayId) || !enableTaskbarConnectedDisplays())
+ return (isDefaultDisplay(displayId)
+ || !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue())
? mPrimaryWindowContext : mWindowContexts.get(displayId);
}
@@ -1070,12 +1213,15 @@
* @return The window manager {@link WindowManager} for a given display or {@code null}.
*/
private @Nullable WindowManager getWindowManager(int displayId) {
- if (isDefaultDisplay(displayId) || !enableTaskbarConnectedDisplays()) {
+ if (isDefaultDisplay(displayId)
+ || !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()) {
+ debugTaskbarManager("cannot get mPrimaryWindowManager", displayId);
return mPrimaryWindowManager;
}
Context externalDisplayContext = getWindowContext(displayId);
if (externalDisplayContext == null) {
+ debugTaskbarManager("cannot get externalDisplayContext", displayId);
return null;
}
@@ -1110,18 +1256,20 @@
}
/** Temp logs for b/254119092. */
- public void debugWhyTaskbarNotDestroyed(String debugReason) {
- debugWhyTaskbarNotDestroyed(debugReason, getDefaultDisplayId());
+ public void debugTaskbarManager(String debugReason) {
+ debugTaskbarManager(debugReason, getDefaultDisplayId());
}
/** Temp logs for b/254119092. */
- public void debugWhyTaskbarNotDestroyed(String debugReason, int displayId) {
+ public void debugTaskbarManager(String debugReason, int displayId) {
StringJoiner log = new StringJoiner("\n");
- log.add(debugReason + " displayId=" + displayId);
+ log.add(debugReason + " displayId=" + displayId + " isDefaultDisplay=" + isDefaultDisplay(
+ displayId));
boolean activityTaskbarPresent = mActivity != null
&& mActivity.getDeviceProfile().isTaskbarPresent;
- Context windowContext = getWindowContext(displayId);
+ // TODO (b/381113004): make this display-specific via getWindowContext()
+ Context windowContext = mPrimaryWindowContext;
if (windowContext == null) {
log.add("window context for displayId" + displayId);
return;
@@ -1160,6 +1308,6 @@
}
private final DeviceProfile.OnDeviceProfileChangeListener mDebugActivityDeviceProfileChanged =
- dp -> debugWhyTaskbarNotDestroyed("mActivity onDeviceProfileChanged");
+ dp -> debugTaskbarManager("mActivity onDeviceProfileChanged");
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index bb57d6e..019e746 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1380,7 +1380,7 @@
SystemUiProxy.INSTANCE.get(this).setLauncherAppIconSize(mDeviceProfile.iconSizePx);
TaskbarManager taskbarManager = mTISBindHelper.getTaskbarManager();
if (taskbarManager != null) {
- taskbarManager.debugWhyTaskbarNotDestroyed("QuickstepLauncher#onDeviceProfileChanged");
+ taskbarManager.debugTaskbarManager("QuickstepLauncher#onDeviceProfileChanged");
}
}