5d8e6bcdee
Create a new New NavigationBarPanelContext per instance of taskbar object for each new instance of taskbar. Test: m Bug: 394421505 Flag: EXEMPT not adding new behavior Change-Id: I6c82140fac9e6a00f0462ea1a593c13f49c3deee
1092 lines
47 KiB
Java
1092 lines
47 KiB
Java
/*
|
|
* Copyright (C) 2021 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.launcher3.taskbar;
|
|
|
|
import static android.content.Context.RECEIVER_NOT_EXPORTED;
|
|
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
|
|
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
|
|
|
|
import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
|
|
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
|
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
|
|
import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
|
|
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
|
|
import static com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE;
|
|
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
|
|
import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
|
|
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
|
|
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
|
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 android.annotation.SuppressLint;
|
|
import android.app.PendingIntent;
|
|
import android.content.ComponentCallbacks;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.pm.ActivityInfo;
|
|
import android.content.res.Configuration;
|
|
import android.hardware.display.DisplayManager;
|
|
import android.net.Uri;
|
|
import android.os.Handler;
|
|
import android.os.Trace;
|
|
import android.provider.Settings;
|
|
import android.util.Log;
|
|
import android.util.SparseArray;
|
|
import android.util.SparseBooleanArray;
|
|
import android.view.Display;
|
|
import android.view.MotionEvent;
|
|
import android.view.WindowManager;
|
|
import android.widget.FrameLayout;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.VisibleForTesting;
|
|
|
|
import com.android.launcher3.DeviceProfile;
|
|
import com.android.launcher3.Launcher;
|
|
import com.android.launcher3.LauncherAppState;
|
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
|
import com.android.launcher3.statemanager.StatefulActivity;
|
|
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
|
|
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
|
|
import com.android.launcher3.uioverrides.QuickstepLauncher;
|
|
import com.android.launcher3.util.DisplayController;
|
|
import com.android.launcher3.util.SettingsCache;
|
|
import com.android.launcher3.util.SimpleBroadcastReceiver;
|
|
import com.android.quickstep.AllAppsActionManager;
|
|
import com.android.quickstep.RecentsActivity;
|
|
import com.android.quickstep.SystemUiProxy;
|
|
import com.android.quickstep.fallback.window.RecentsWindowManager;
|
|
import com.android.quickstep.util.ContextualSearchInvoker;
|
|
import com.android.quickstep.views.RecentsViewContainer;
|
|
import com.android.systemui.shared.statusbar.phone.BarTransitions;
|
|
import com.android.systemui.shared.system.QuickStepContract;
|
|
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
|
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
|
|
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
|
|
|
|
import java.io.PrintWriter;
|
|
import java.util.StringJoiner;
|
|
|
|
/**
|
|
* Class to manage taskbar lifecycle
|
|
*/
|
|
public class TaskbarManager {
|
|
private static final String TAG = "TaskbarManager";
|
|
private static final boolean DEBUG = false;
|
|
// TODO(b/382378283) remove all logs with this tag
|
|
public static final String NULL_TASKBAR_ROOT_LAYOUT_TAG = "b/382378283";
|
|
public static final String ILLEGAL_ARGUMENT_WM_ADD_VIEW = "b/391653300";
|
|
|
|
/**
|
|
* All the configurations which do not initiate taskbar recreation.
|
|
* This includes all the configurations defined in Launcher's manifest entry and
|
|
* ActivityController#filterConfigChanges
|
|
*/
|
|
private static final int SKIP_RECREATE_CONFIG_CHANGES = ActivityInfo.CONFIG_WINDOW_CONFIGURATION
|
|
| ActivityInfo.CONFIG_KEYBOARD
|
|
| ActivityInfo.CONFIG_KEYBOARD_HIDDEN
|
|
| ActivityInfo.CONFIG_MCC
|
|
| ActivityInfo.CONFIG_MNC
|
|
| ActivityInfo.CONFIG_NAVIGATION
|
|
| ActivityInfo.CONFIG_ORIENTATION
|
|
| ActivityInfo.CONFIG_SCREEN_SIZE
|
|
| ActivityInfo.CONFIG_SCREEN_LAYOUT
|
|
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
|
|
|
|
private static final Uri USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(
|
|
Settings.Secure.USER_SETUP_COMPLETE);
|
|
|
|
private static final Uri NAV_BAR_KIDS_MODE = Settings.Secure.getUriFor(
|
|
Settings.Secure.NAV_BAR_KIDS_MODE);
|
|
|
|
private final Context mParentContext;
|
|
private final TaskbarNavButtonController mDefaultNavButtonController;
|
|
private final ComponentCallbacks mDefaultComponentCallbacks;
|
|
|
|
private final SimpleBroadcastReceiver mShutdownReceiver =
|
|
new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> destroyAllTaskbars());
|
|
|
|
// The source for this provider is set when Launcher is available
|
|
// We use 'non-destroyable' version here so the original provider won't be destroyed
|
|
// as it is tied to the activity lifecycle, not the taskbar lifecycle.
|
|
// It's destruction/creation will be managed by the activity.
|
|
private final ScopedUnfoldTransitionProgressProvider mUnfoldProgressProvider =
|
|
new NonDestroyableScopedUnfoldTransitionProgressProvider();
|
|
/** DisplayId - {@link TaskbarActivityContext} map for Connected Display. */
|
|
private final SparseArray<TaskbarActivityContext> mTaskbars = new SparseArray<>();
|
|
/** DisplayId - {@link Context} map for Connected Display. */
|
|
private final SparseArray<Context> mWindowContexts = new SparseArray<>();
|
|
/** DisplayId - {@link FrameLayout} map for Connected Display. */
|
|
private final SparseArray<FrameLayout> mRootLayouts = new SparseArray<>();
|
|
/** DisplayId - {@link Boolean} map indicating if RootLayout was added to window. */
|
|
private final SparseBooleanArray mAddedRootLayouts = new SparseBooleanArray();
|
|
private StatefulActivity mActivity;
|
|
private RecentsViewContainer mRecentsViewContainer;
|
|
|
|
/**
|
|
* Cache a copy here so we can initialize state whenever taskbar is recreated, since
|
|
* this class does not get re-initialized w/ new taskbars.
|
|
*/
|
|
private final TaskbarSharedState mSharedState = new TaskbarSharedState();
|
|
|
|
/**
|
|
* We use WindowManager's ComponentCallbacks() for internal UI changes (similar to an Activity)
|
|
* which comes via a different channel
|
|
*/
|
|
private final RecreationListener mRecreationListener = new RecreationListener();
|
|
|
|
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");
|
|
}
|
|
if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
|
|
Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "Navigation mode changed");
|
|
}
|
|
if ((flags & CHANGE_DESKTOP_MODE) != 0) {
|
|
Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "Desktop mode changed");
|
|
}
|
|
if ((flags & CHANGE_TASKBAR_PINNING) != 0) {
|
|
Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "Taskbar pinning changed");
|
|
}
|
|
|
|
if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE | CHANGE_DESKTOP_MODE
|
|
| CHANGE_TASKBAR_PINNING)) != 0) {
|
|
recreateTaskbar();
|
|
}
|
|
}
|
|
}
|
|
private final SettingsCache.OnChangeListener mOnSettingsChangeListener = c -> recreateTaskbar();
|
|
|
|
private boolean mUserUnlocked = false;
|
|
|
|
private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver =
|
|
new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, this::showTaskbarFromBroadcast);
|
|
|
|
private final AllAppsActionManager mAllAppsActionManager;
|
|
|
|
private final Runnable mActivityOnDestroyCallback = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
int displayId = getDefaultDisplayId();
|
|
if (mActivity != null) {
|
|
displayId = mActivity.getDisplayId();
|
|
mActivity.removeOnDeviceProfileChangeListener(
|
|
mDebugActivityDeviceProfileChanged);
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG,
|
|
"unregistering activity lifecycle callbacks from "
|
|
+ "onActivityDestroyed.");
|
|
mActivity.removeEventCallback(EVENT_DESTROYED, this);
|
|
}
|
|
if (mActivity == mRecentsViewContainer) {
|
|
mRecentsViewContainer = null;
|
|
}
|
|
mActivity = null;
|
|
debugWhyTaskbarNotDestroyed("clearActivity");
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (taskbar != null) {
|
|
taskbar.setUIController(TaskbarUIController.DEFAULT);
|
|
}
|
|
mUnfoldProgressProvider.setSourceProvider(null);
|
|
}
|
|
};
|
|
|
|
UnfoldTransitionProgressProvider.TransitionProgressListener mUnfoldTransitionProgressListener =
|
|
new UnfoldTransitionProgressProvider.TransitionProgressListener() {
|
|
@Override
|
|
public void onTransitionStarted() {
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG,
|
|
"fold/unfold transition started getting called.");
|
|
}
|
|
|
|
@Override
|
|
public void onTransitionProgress(float progress) {
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG,
|
|
"fold/unfold transition progress : " + progress);
|
|
}
|
|
|
|
@Override
|
|
public void onTransitionFinishing() {
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG,
|
|
"fold/unfold transition finishing getting called.");
|
|
|
|
}
|
|
|
|
@Override
|
|
public void onTransitionFinished() {
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG,
|
|
"fold/unfold transition finished getting called.");
|
|
|
|
}
|
|
};
|
|
|
|
@SuppressLint("WrongConstant")
|
|
public TaskbarManager(
|
|
Context context,
|
|
AllAppsActionManager allAppsActionManager,
|
|
TaskbarNavButtonCallbacks navCallbacks) {
|
|
mParentContext = context;
|
|
createWindowContext(context.getDisplayId());
|
|
mAllAppsActionManager = allAppsActionManager;
|
|
if (enableTaskbarNoRecreate()) {
|
|
createTaskbarRootLayout(getDefaultDisplayId());
|
|
}
|
|
mDefaultNavButtonController = createDefaultNavButtonController(context, navCallbacks);
|
|
mDefaultComponentCallbacks = createDefaultComponentCallbacks();
|
|
SettingsCache.INSTANCE.get(getPrimaryWindowContext())
|
|
.register(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
|
|
SettingsCache.INSTANCE.get(getPrimaryWindowContext())
|
|
.register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG, "registering component callbacks from constructor.");
|
|
getPrimaryWindowContext().registerComponentCallbacks(mDefaultComponentCallbacks);
|
|
mShutdownReceiver.register(getPrimaryWindowContext(), Intent.ACTION_SHUTDOWN);
|
|
UI_HELPER_EXECUTOR.execute(() -> {
|
|
mSharedState.taskbarSystemActionPendingIntent = PendingIntent.getBroadcast(
|
|
getPrimaryWindowContext(),
|
|
SYSTEM_ACTION_ID_TASKBAR,
|
|
new Intent(ACTION_SHOW_TASKBAR).setPackage(
|
|
getPrimaryWindowContext().getPackageName()),
|
|
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
|
mTaskbarBroadcastReceiver.register(
|
|
getPrimaryWindowContext(), RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR);
|
|
});
|
|
|
|
debugWhyTaskbarNotDestroyed("TaskbarManager created");
|
|
recreateTaskbar();
|
|
}
|
|
|
|
@NonNull
|
|
private TaskbarNavButtonController createDefaultNavButtonController(Context context,
|
|
TaskbarNavButtonCallbacks navCallbacks) {
|
|
return new TaskbarNavButtonController(
|
|
context,
|
|
navCallbacks,
|
|
SystemUiProxy.INSTANCE.get(getPrimaryWindowContext()),
|
|
new Handler(),
|
|
new ContextualSearchInvoker(getPrimaryWindowContext()));
|
|
}
|
|
|
|
private ComponentCallbacks createDefaultComponentCallbacks() {
|
|
return new ComponentCallbacks() {
|
|
private Configuration mOldConfig =
|
|
getPrimaryWindowContext().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(getPrimaryWindowContext()).getDeviceProfile(
|
|
getPrimaryWindowContext())
|
|
: 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);
|
|
destroyTaskbarForDisplay(displayId);
|
|
removeTaskbarRootViewFromWindow(displayId);
|
|
removeWindowContextFromMap(displayId);
|
|
}
|
|
}
|
|
|
|
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);
|
|
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;
|
|
if (dp == null || !isTaskbarEnabled(dp)) {
|
|
removeTaskbarRootViewFromWindow(displayId);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show Taskbar upon receiving broadcast
|
|
*/
|
|
private void showTaskbarFromBroadcast(Intent intent) {
|
|
// TODO: make this code displayId specific
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
|
if (ACTION_SHOW_TASKBAR.equals(intent.getAction()) && taskbar != null) {
|
|
taskbar.showTaskbarFromBroadcast();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Toggles All Apps for Taskbar or Launcher depending on the current state.
|
|
*/
|
|
public void toggleAllApps() {
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
|
if (taskbar == null || taskbar.canToggleHomeAllApps()) {
|
|
// Home All Apps should be toggled from this class, because the controllers are not
|
|
// initialized when Taskbar is disabled (i.e. TaskbarActivityContext is null).
|
|
if (mActivity instanceof Launcher l) l.toggleAllAppsSearch();
|
|
} else {
|
|
taskbar.toggleAllAppsSearch();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Displays a frame of the first Launcher reveal animation.
|
|
*
|
|
* This should be used to run a first Launcher reveal animation whose progress matches a swipe
|
|
* progress.
|
|
*/
|
|
public AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) {
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
|
return taskbar == null ? null : taskbar.createLauncherStartFromSuwAnim(duration);
|
|
}
|
|
|
|
/**
|
|
* Called when the user is unlocked
|
|
*/
|
|
public void onUserUnlocked() {
|
|
mUserUnlocked = true;
|
|
DisplayController.INSTANCE.get(getPrimaryWindowContext()).addChangeListener(
|
|
mRecreationListener);
|
|
recreateTaskbar();
|
|
addTaskbarRootViewToWindow(getDefaultDisplayId());
|
|
}
|
|
|
|
/**
|
|
* Sets a {@link StatefulActivity} to act as taskbar callback
|
|
*/
|
|
public void setActivity(@NonNull StatefulActivity activity) {
|
|
if (mActivity == activity) {
|
|
return;
|
|
}
|
|
removeActivityCallbacksAndListeners();
|
|
mActivity = activity;
|
|
debugWhyTaskbarNotDestroyed("Set mActivity=" + mActivity);
|
|
mActivity.addOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG,
|
|
"registering activity lifecycle callbacks from setActivity().");
|
|
mActivity.addEventCallback(EVENT_DESTROYED, mActivityOnDestroyCallback);
|
|
UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
|
|
getUnfoldTransitionProgressProviderForActivity(activity);
|
|
if (unfoldTransitionProgressProvider != null) {
|
|
unfoldTransitionProgressProvider.addCallback(mUnfoldTransitionProgressListener);
|
|
}
|
|
mUnfoldProgressProvider.setSourceProvider(unfoldTransitionProgressProvider);
|
|
|
|
if (activity instanceof RecentsViewContainer recentsViewContainer) {
|
|
setRecentsViewContainer(recentsViewContainer);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the current RecentsViewContainer, from which we create a TaskbarUIController.
|
|
*/
|
|
public void setRecentsViewContainer(@NonNull RecentsViewContainer recentsViewContainer) {
|
|
if (mRecentsViewContainer == recentsViewContainer) {
|
|
return;
|
|
}
|
|
if (mRecentsViewContainer == mActivity) {
|
|
// When switching to RecentsWindowManager (not an Activity), the old mActivity is not
|
|
// destroyed, nor is there a new Activity to replace it. Thus if we don't clear it here,
|
|
// it will not get re-set properly if we return to the Activity (e.g. NexusLauncher).
|
|
mActivityOnDestroyCallback.run();
|
|
}
|
|
mRecentsViewContainer = recentsViewContainer;
|
|
TaskbarActivityContext taskbar = getCurrentActivityContext();
|
|
if (taskbar != null) {
|
|
taskbar.setUIController(
|
|
createTaskbarUIControllerForRecentsViewContainer(mRecentsViewContainer));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns an {@link UnfoldTransitionProgressProvider} to use while the given StatefulActivity
|
|
* is active.
|
|
*/
|
|
private UnfoldTransitionProgressProvider getUnfoldTransitionProgressProviderForActivity(
|
|
StatefulActivity activity) {
|
|
if (!enableUnfoldStateAnimation()) {
|
|
if (activity instanceof QuickstepLauncher ql) {
|
|
return ql.getUnfoldTransitionProgressProvider();
|
|
}
|
|
} else {
|
|
return SystemUiProxy.INSTANCE.get(
|
|
getPrimaryWindowContext()).getUnfoldTransitionProvider();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Creates a {@link TaskbarUIController} to use while the given StatefulActivity is active.
|
|
*/
|
|
private TaskbarUIController createTaskbarUIControllerForRecentsViewContainer(
|
|
RecentsViewContainer container) {
|
|
if (container instanceof QuickstepLauncher quickstepLauncher) {
|
|
return new LauncherTaskbarUIController(quickstepLauncher);
|
|
}
|
|
// If a 3P Launcher is default, always use FallbackTaskbarUIController regardless of
|
|
// whether the recents container is RecentsActivity or RecentsWindowManager.
|
|
if (container instanceof RecentsActivity recentsActivity) {
|
|
return new FallbackTaskbarUIController<>(recentsActivity);
|
|
}
|
|
if (container instanceof RecentsWindowManager recentsWindowManager) {
|
|
return new FallbackTaskbarUIController<>(recentsWindowManager);
|
|
}
|
|
return TaskbarUIController.DEFAULT;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
* 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());
|
|
}
|
|
|
|
/**
|
|
* This method is called multiple times (ex. initial init, then when user unlocks) in which case
|
|
* we fully want to destroy an existing taskbar for a specified display and create a new one.
|
|
* In other case (folding/unfolding) we don't need to remove and add window.
|
|
*/
|
|
private void recreateTaskbarForDisplay(int displayId) {
|
|
Trace.beginSection("recreateTaskbar");
|
|
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;
|
|
|
|
// All Apps action is unrelated to navbar unification, so we only need to check DP.
|
|
final boolean isLargeScreenTaskbar = dp != null && dp.isTaskbarPresent;
|
|
mAllAppsActionManager.setTaskbarPresent(isLargeScreenTaskbar);
|
|
|
|
destroyTaskbarForDisplay(displayId);
|
|
|
|
boolean isTaskbarEnabled = dp != null && isTaskbarEnabled(dp);
|
|
debugWhyTaskbarNotDestroyed("recreateTaskbar: 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(getPrimaryWindowContext())
|
|
.notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
|
|
if (!isTaskbarEnabled) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (enableTaskbarNoRecreate() || taskbar == null) {
|
|
taskbar = createTaskbarActivityContext(dp, displayId);
|
|
} else {
|
|
taskbar.updateDeviceProfile(dp);
|
|
}
|
|
mSharedState.startTaskbarVariantIsTransient =
|
|
DisplayController.isTransientTaskbar(taskbar);
|
|
mSharedState.allAppsVisible = mSharedState.allAppsVisible && isLargeScreenTaskbar;
|
|
taskbar.init(mSharedState);
|
|
|
|
if (mRecentsViewContainer != null) {
|
|
taskbar.setUIController(
|
|
createTaskbarUIControllerForRecentsViewContainer(mRecentsViewContainer));
|
|
}
|
|
|
|
if (enableTaskbarNoRecreate()) {
|
|
addTaskbarRootViewToWindow(displayId);
|
|
FrameLayout taskbarRootLayout = getTaskbarRootLayoutForDisplay(displayId);
|
|
if (taskbarRootLayout != null) {
|
|
taskbarRootLayout.removeAllViews();
|
|
taskbarRootLayout.addView(taskbar.getDragLayer());
|
|
taskbar.notifyUpdateLayoutParams();
|
|
} else {
|
|
Log.e(NULL_TASKBAR_ROOT_LAYOUT_TAG,
|
|
"taskbarRootLayout is null for displayId=" + displayId);
|
|
}
|
|
}
|
|
} finally {
|
|
Trace.endSection();
|
|
}
|
|
}
|
|
|
|
public void onSystemUiFlagsChanged(@SystemUiStateFlags long systemUiStateFlags) {
|
|
if (DEBUG) {
|
|
Log.d(TAG, "SysUI flags changed: " + formatFlagChange(systemUiStateFlags,
|
|
mSharedState.sysuiStateFlags, QuickStepContract::getSystemUiStateString));
|
|
}
|
|
mSharedState.sysuiStateFlags = systemUiStateFlags;
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
|
if (taskbar != null) {
|
|
taskbar.updateSysuiStateFlags(systemUiStateFlags, false /* fromInit */);
|
|
}
|
|
}
|
|
|
|
public void onLongPressHomeEnabled(boolean assistantLongPressEnabled) {
|
|
if (mDefaultNavButtonController != null) {
|
|
mDefaultNavButtonController.setAssistantLongPressEnabled(assistantLongPressEnabled);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the flag indicating setup UI is visible
|
|
*/
|
|
public void setSetupUIVisible(boolean isVisible) {
|
|
mSharedState.setupUIVisible = isVisible;
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
|
if (taskbar != null) {
|
|
taskbar.setSetupUIVisible(isVisible);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets wallpaper visibility for specific display.
|
|
*/
|
|
public void setWallpaperVisible(int displayId, boolean isVisible) {
|
|
mSharedState.wallpaperVisible = isVisible;
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (taskbar != null) {
|
|
taskbar.setWallpaperVisible(isVisible);
|
|
}
|
|
}
|
|
|
|
public void checkNavBarModes(int displayId) {
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (taskbar != null) {
|
|
taskbar.checkNavBarModes();
|
|
}
|
|
}
|
|
|
|
public void finishBarAnimations(int displayId) {
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (taskbar != null) {
|
|
taskbar.finishBarAnimations();
|
|
}
|
|
}
|
|
|
|
public void touchAutoDim(int displayId, boolean reset) {
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (taskbar != null) {
|
|
taskbar.touchAutoDim(reset);
|
|
}
|
|
}
|
|
|
|
public void transitionTo(int displayId, @BarTransitions.TransitionMode int barMode,
|
|
boolean animate) {
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (taskbar != null) {
|
|
taskbar.transitionTo(barMode, animate);
|
|
}
|
|
}
|
|
|
|
public void appTransitionPending(boolean pending) {
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
|
if (taskbar != null) {
|
|
taskbar.appTransitionPending(pending);
|
|
}
|
|
}
|
|
|
|
private boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
|
|
return ENABLE_TASKBAR_NAVBAR_UNIFICATION || deviceProfile.isTaskbarPresent;
|
|
}
|
|
|
|
public void onRotationProposal(int rotation, boolean isValid) {
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
|
if (taskbar != null) {
|
|
taskbar.onRotationProposal(rotation, isValid);
|
|
}
|
|
}
|
|
|
|
public void disableNavBarElements(int displayId, int state1, int state2, boolean animate) {
|
|
mSharedState.disableNavBarDisplayId = displayId;
|
|
mSharedState.disableNavBarState1 = state1;
|
|
mSharedState.disableNavBarState2 = state2;
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (taskbar != null) {
|
|
taskbar.disableNavBarElements(displayId, state1, state2, animate);
|
|
}
|
|
}
|
|
|
|
public void onSystemBarAttributesChanged(int displayId, int behavior) {
|
|
mSharedState.systemBarAttrsDisplayId = displayId;
|
|
mSharedState.systemBarAttrsBehavior = behavior;
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (taskbar != null) {
|
|
taskbar.onSystemBarAttributesChanged(displayId, behavior);
|
|
}
|
|
}
|
|
|
|
public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
|
|
mSharedState.barMode = barMode;
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
|
if (taskbar != null) {
|
|
taskbar.onTransitionModeUpdated(barMode, checkBarModes);
|
|
}
|
|
}
|
|
|
|
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
|
|
mSharedState.navButtonsDarkIntensity = darkIntensity;
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
|
|
if (taskbar != null) {
|
|
taskbar.onNavButtonsDarkIntensityChanged(darkIntensity);
|
|
}
|
|
}
|
|
|
|
public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
|
|
mSharedState.mLumaSamplingDisplayId = displayId;
|
|
mSharedState.mIsLumaSamplingEnabled = enable;
|
|
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
|
|
if (taskbar != null) {
|
|
taskbar.onNavigationBarLumaSamplingEnabled(displayId, enable);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Signal from SysUI indicating that a non-mirroring display was just connected to the
|
|
* primary device or a previously mirroring display is switched to extended mode.
|
|
*/
|
|
public void onDisplayAddSystemDecorations(int displayId) {
|
|
}
|
|
|
|
/**
|
|
* Signal from SysUI indicating that a previously connected non-mirroring display was just
|
|
* removed from the primary device.
|
|
*/
|
|
public void onDisplayRemoved(int displayId) {
|
|
}
|
|
|
|
/**
|
|
* Signal from SysUI indicating that system decorations should be removed from the display.
|
|
*/
|
|
public void onDisplayRemoveSystemDecorations(int displayId) {}
|
|
|
|
private void removeActivityCallbacksAndListeners() {
|
|
if (mActivity != null) {
|
|
mActivity.removeOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG,
|
|
"unregistering activity lifecycle callbacks from "
|
|
+ "removeActivityCallbackAndListeners().");
|
|
mActivity.removeEventCallback(EVENT_DESTROYED, mActivityOnDestroyCallback);
|
|
UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
|
|
getUnfoldTransitionProgressProviderForActivity(mActivity);
|
|
if (unfoldTransitionProgressProvider != null) {
|
|
unfoldTransitionProgressProvider.removeCallback(mUnfoldTransitionProgressListener);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called when the manager is no longer needed
|
|
*/
|
|
public void destroy() {
|
|
mRecentsViewContainer = null;
|
|
debugWhyTaskbarNotDestroyed("TaskbarManager#destroy()");
|
|
removeActivityCallbacksAndListeners();
|
|
mTaskbarBroadcastReceiver.unregisterReceiverSafely(getPrimaryWindowContext());
|
|
|
|
if (mUserUnlocked) {
|
|
DisplayController.INSTANCE.get(getPrimaryWindowContext()).removeChangeListener(
|
|
mRecreationListener);
|
|
}
|
|
SettingsCache.INSTANCE.get(getPrimaryWindowContext())
|
|
.unregister(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
|
|
SettingsCache.INSTANCE.get(getPrimaryWindowContext())
|
|
.unregister(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
|
|
getPrimaryWindowContext().unregisterComponentCallbacks(mDefaultComponentCallbacks);
|
|
mShutdownReceiver.unregisterReceiverSafely(getPrimaryWindowContext());
|
|
destroyAllTaskbars();
|
|
}
|
|
|
|
public @Nullable TaskbarActivityContext getCurrentActivityContext() {
|
|
return getTaskbarForDisplay(getDefaultDisplayId());
|
|
}
|
|
|
|
public void dumpLogs(String prefix, PrintWriter pw) {
|
|
pw.println(prefix + "TaskbarManager:");
|
|
// iterate through taskbars and do the dump for each
|
|
for (int i = 0; i < mTaskbars.size(); i++) {
|
|
int displayId = mTaskbars.keyAt(i);
|
|
TaskbarActivityContext taskbar = mTaskbars.get(i);
|
|
pw.println(prefix + "\tTaskbar at display " + displayId + ":");
|
|
if (taskbar == null) {
|
|
pw.println(prefix + "\t\tTaskbarActivityContext: null");
|
|
} else {
|
|
taskbar.dumpLogs(prefix + "\t\t", pw);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
return;
|
|
}
|
|
|
|
if (!isTaskbarRootLayoutAddedForDisplay(displayId)) {
|
|
FrameLayout rootLayout = getTaskbarRootLayoutForDisplay(displayId);
|
|
if (rootLayout != null) {
|
|
getWindowManager(displayId).addView(rootLayout, taskbar.getWindowLayoutParams());
|
|
mAddedRootLayouts.put(displayId, true);
|
|
} else {
|
|
Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW,
|
|
"addTaskbarRootViewToWindow - root layout null | displayId=" + displayId);
|
|
}
|
|
} else {
|
|
Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG,
|
|
"addTaskbarRootViewToWindow - root layout already added | displayId="
|
|
+ displayId);
|
|
}
|
|
}
|
|
|
|
private void removeTaskbarRootViewFromWindow(int displayId) {
|
|
Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "removeTaskbarRootViewFromWindow: " + displayId);
|
|
FrameLayout rootLayout = getTaskbarRootLayoutForDisplay(displayId);
|
|
if (!enableTaskbarNoRecreate() || rootLayout == null) {
|
|
return;
|
|
}
|
|
|
|
if (isTaskbarRootLayoutAddedForDisplay(displayId)) {
|
|
getWindowManager(displayId).removeViewImmediate(rootLayout);
|
|
mAddedRootLayouts.put(displayId, false);
|
|
removeTaskbarRootLayoutFromMap(displayId);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves whether RootLayout was added to window for specific display, or false if no
|
|
* such mapping has been made.
|
|
*
|
|
* @param displayId The ID of the display for which to retrieve the taskbar root layout.
|
|
* @return if RootLayout was added to window {@link Boolean} for a display or {@code false}.
|
|
*/
|
|
private boolean isTaskbarRootLayoutAddedForDisplay(int displayId) {
|
|
return mAddedRootLayouts.get(displayId);
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link TaskbarActivityContext} associated with the given display ID.
|
|
*
|
|
* @param displayId The ID of the display to retrieve the taskbar for.
|
|
* @return The {@link TaskbarActivityContext} for the specified display, or
|
|
* {@code null} if no taskbar is associated with that display.
|
|
*/
|
|
private TaskbarActivityContext getTaskbarForDisplay(int displayId) {
|
|
return mTaskbars.get(displayId);
|
|
}
|
|
|
|
|
|
/**
|
|
* Creates a {@link TaskbarActivityContext} for the given display and adds it to the map.
|
|
*/
|
|
private TaskbarActivityContext createTaskbarActivityContext(DeviceProfile dp, int displayId) {
|
|
Display display = mParentContext.getSystemService(DisplayManager.class).getDisplay(
|
|
displayId);
|
|
Context navigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
|
|
? mParentContext.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
|
|
: null;
|
|
|
|
TaskbarActivityContext newTaskbar = new TaskbarActivityContext(getWindowContext(displayId),
|
|
navigationBarPanelContext, dp, mDefaultNavButtonController,
|
|
mUnfoldProgressProvider, isDefaultDisplay(displayId),
|
|
SystemUiProxy.INSTANCE.get(getPrimaryWindowContext()));
|
|
|
|
addTaskbarToMap(displayId, newTaskbar);
|
|
return newTaskbar;
|
|
}
|
|
|
|
/**
|
|
* Adds the {@link TaskbarActivityContext} associated with the given display ID to taskbar
|
|
* map if there is not already a taskbar mapped to that displayId.
|
|
*
|
|
* @param displayId The ID of the display to retrieve the taskbar for.
|
|
* @param newTaskbar The new {@link TaskbarActivityContext} to add to the map.
|
|
*/
|
|
private void addTaskbarToMap(int displayId, TaskbarActivityContext newTaskbar) {
|
|
if (!mTaskbars.contains(displayId)) {
|
|
mTaskbars.put(displayId, newTaskbar);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes the taskbar associated with the given display ID from the taskbar map.
|
|
*
|
|
* @param displayId The ID of the display for which to remove the taskbar.
|
|
*/
|
|
private void removeTaskbarFromMap(int displayId) {
|
|
mTaskbars.delete(displayId);
|
|
}
|
|
|
|
/**
|
|
* Creates {@link FrameLayout} for the taskbar on the specified display and adds it to map.
|
|
* @param displayId The ID of the display for which to create the taskbar root layout.
|
|
*/
|
|
private void createTaskbarRootLayout(int displayId) {
|
|
Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "createTaskbarRootLayout: " + displayId);
|
|
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());
|
|
if (taskbar != null && taskbar.getDragLayer().isAttachedToWindow()) {
|
|
return taskbar.getDragLayer().dispatchTouchEvent(ev);
|
|
}
|
|
return super.dispatchTouchEvent(ev);
|
|
}
|
|
};
|
|
addTaskbarRootLayoutToMap(displayId, newTaskbarRootLayout);
|
|
Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "created new root layout - displayId=" + displayId);
|
|
}
|
|
|
|
private boolean isDefaultDisplay(int displayId) {
|
|
return displayId == getDefaultDisplayId();
|
|
}
|
|
|
|
/**
|
|
* Retrieves the root layout of the taskbar for the specified display.
|
|
*
|
|
* @param displayId The ID of the display for which to retrieve the taskbar root layout.
|
|
* @return The taskbar root layout {@link FrameLayout} for a given display or {@code null}.
|
|
*/
|
|
private FrameLayout getTaskbarRootLayoutForDisplay(int displayId) {
|
|
Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "getTaskbarRootLayoutForDisplay: " + displayId);
|
|
FrameLayout frameLayout = mRootLayouts.get(displayId);
|
|
if (frameLayout != null) {
|
|
return frameLayout;
|
|
} else {
|
|
Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG,
|
|
"getTaskbarRootLayoutForDisplay == null | displayId=" + displayId);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds the taskbar root layout {@link FrameLayout} to taskbar map, mapped to display ID.
|
|
*
|
|
* @param displayId The ID of the display to associate with the taskbar root layout.
|
|
* @param rootLayout The taskbar root layout {@link FrameLayout} to add to the map.
|
|
*/
|
|
private void addTaskbarRootLayoutToMap(int displayId, FrameLayout rootLayout) {
|
|
if (!mRootLayouts.contains(displayId) && rootLayout != null) {
|
|
mRootLayouts.put(displayId, rootLayout);
|
|
}
|
|
|
|
Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "mRootLayouts.size()=" + mRootLayouts.size());
|
|
}
|
|
|
|
/**
|
|
* Removes taskbar root layout {@link FrameLayout} for given display ID from the taskbar map.
|
|
*
|
|
* @param displayId The ID of the display for which to remove the taskbar root layout.
|
|
*/
|
|
private void removeTaskbarRootLayoutFromMap(int displayId) {
|
|
if (mRootLayouts.contains(displayId)) {
|
|
mAddedRootLayouts.delete(displayId);
|
|
mRootLayouts.delete(displayId);
|
|
}
|
|
|
|
Log.d(NULL_TASKBAR_ROOT_LAYOUT_TAG, "mRootLayouts.size()=" + mRootLayouts.size());
|
|
}
|
|
|
|
/**
|
|
* Creates {@link Context} for the taskbar on the specified display and›› adds it to map.
|
|
* @param displayId The ID of the display for which to create the window context.
|
|
*/
|
|
private void createWindowContext(int displayId) {
|
|
DisplayManager displayManager = mParentContext.getSystemService(DisplayManager.class);
|
|
if (displayManager == null) {
|
|
return;
|
|
}
|
|
|
|
Display display = displayManager.getDisplay(displayId);
|
|
if (display != null) {
|
|
int windowType = (ENABLE_TASKBAR_NAVBAR_UNIFICATION && isDefaultDisplay(displayId))
|
|
? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
|
|
Context newContext = mParentContext.createWindowContext(display, windowType, null);
|
|
addWindowContextToMap(displayId, newContext);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves the window context of the taskbar for the specified display.
|
|
*
|
|
* @param displayId The ID of the display for which to retrieve the window context.
|
|
* @return The Window Context {@link Context} for a given display or {@code null}.
|
|
*/
|
|
private Context getWindowContext(int displayId) {
|
|
return mWindowContexts.get(displayId);
|
|
}
|
|
|
|
@VisibleForTesting
|
|
public Context getPrimaryWindowContext() {
|
|
return getWindowContext(getDefaultDisplayId());
|
|
}
|
|
|
|
/**
|
|
* Retrieves the window manager {@link WindowManager} of the taskbar for the specified display.
|
|
*
|
|
* @param displayId The ID of the display for which to retrieve the window manager.
|
|
* @return The window manager {@link WindowManager} for a given display or {@code null}.
|
|
*/
|
|
private WindowManager getWindowManager(int displayId) {
|
|
return getWindowContext(displayId).getSystemService(WindowManager.class);
|
|
}
|
|
|
|
/**
|
|
* Adds the window context {@link Context} to taskbar map, mapped to display ID.
|
|
*
|
|
* @param displayId The ID of the display to associate with the taskbar root layout.
|
|
* @param windowContext The window context {@link Context} to add to the map.
|
|
*/
|
|
private void addWindowContextToMap(int displayId, @NonNull Context windowContext) {
|
|
if (!mWindowContexts.contains(displayId)) {
|
|
mWindowContexts.put(displayId, windowContext);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes the window context {@link Context} for given display ID from the taskbar map.
|
|
*
|
|
* @param displayId The ID of the display for which to remove the taskbar root layout.
|
|
*/
|
|
private void removeWindowContextFromMap(int displayId) {
|
|
if (mWindowContexts.contains(displayId)) {
|
|
mWindowContexts.delete(displayId);
|
|
}
|
|
}
|
|
|
|
private int getDefaultDisplayId() {
|
|
return mParentContext.getDisplayId();
|
|
}
|
|
|
|
/** Temp logs for b/254119092. */
|
|
public void debugWhyTaskbarNotDestroyed(String debugReason) {
|
|
debugWhyTaskbarNotDestroyed(debugReason, getDefaultDisplayId());
|
|
}
|
|
|
|
/** Temp logs for b/254119092. */
|
|
public void debugWhyTaskbarNotDestroyed(String debugReason, int displayId) {
|
|
StringJoiner log = new StringJoiner("\n");
|
|
log.add(debugReason + " displayId=" + displayId);
|
|
|
|
boolean activityTaskbarPresent = mActivity != null
|
|
&& mActivity.getDeviceProfile().isTaskbarPresent;
|
|
Context windowContext = getWindowContext(displayId);
|
|
if (windowContext == null) {
|
|
log.add("window context for displayId" + displayId);
|
|
return;
|
|
}
|
|
|
|
boolean contextTaskbarPresent = mUserUnlocked && LauncherAppState.getIDP(windowContext)
|
|
.getDeviceProfile(windowContext).isTaskbarPresent;
|
|
if (activityTaskbarPresent == contextTaskbarPresent) {
|
|
log.add("mActivity and mWindowContext agree taskbarIsPresent=" + contextTaskbarPresent);
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG, log.toString());
|
|
return;
|
|
}
|
|
|
|
log.add("mActivity & mWindowContext device profiles have different values, add more logs.");
|
|
|
|
log.add("\tmActivity logs:");
|
|
log.add("\t\tmActivity=" + mActivity);
|
|
if (mActivity != null) {
|
|
log.add("\t\tmActivity.getResources().getConfiguration()="
|
|
+ mActivity.getResources().getConfiguration());
|
|
log.add("\t\tmActivity.getDeviceProfile().isTaskbarPresent="
|
|
+ activityTaskbarPresent);
|
|
}
|
|
log.add("\tWindowContext logs:");
|
|
log.add("\t\tWindowContext=" + windowContext);
|
|
log.add("\t\tWindowContext.getResources().getConfiguration()="
|
|
+ windowContext.getResources().getConfiguration());
|
|
if (mUserUnlocked) {
|
|
log.add("\t\tLauncherAppState.getIDP().getDeviceProfile(getPrimaryWindowContext())"
|
|
+ ".isTaskbarPresent=" + contextTaskbarPresent);
|
|
} else {
|
|
log.add("\t\tCouldn't get DeviceProfile because !mUserUnlocked");
|
|
}
|
|
|
|
Log.d(TASKBAR_NOT_DESTROYED_TAG, log.toString());
|
|
}
|
|
|
|
private final DeviceProfile.OnDeviceProfileChangeListener mDebugActivityDeviceProfileChanged =
|
|
dp -> debugWhyTaskbarNotDestroyed("mActivity onDeviceProfileChanged");
|
|
|
|
}
|