Merge "Convert IconShape to Kotlin" into main
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
deleted file mode 100644
index 488cea5..0000000
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Copyright (C) 2022 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.statehandlers;
-
-import static android.view.View.VISIBLE;
-import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-
-import android.content.Context;
-import android.os.Debug;
-import android.util.Log;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.statemanager.BaseState;
-import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.views.ActivityContext;
-import com.android.quickstep.GestureState;
-import com.android.quickstep.SystemUiProxy;
-import com.android.quickstep.fallback.RecentsState;
-import com.android.wm.shell.desktopmode.IDesktopTaskListener;
-import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
-
-import java.io.PrintWriter;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Controls the visibility of the workspace and the resumed / paused state when desktop mode
- * is enabled.
- */
-public class DesktopVisibilityController {
-
- private static final String TAG = "DesktopVisController";
- private static final boolean DEBUG = false;
- private final Set<DesktopVisibilityListener> mDesktopVisibilityListeners = new HashSet<>();
- private final Set<TaskbarDesktopModeListener> mTaskbarDesktopModeListeners = new HashSet<>();
-
- private int mVisibleDesktopTasksCount;
- private boolean mInOverviewState;
- private boolean mBackgroundStateEnabled;
- private boolean mGestureInProgress;
-
- @Nullable
- private DesktopTaskListenerImpl mDesktopTaskListener;
-
- @Nullable
- private Context mContext;
-
- public DesktopVisibilityController(@NonNull Context context) {
- setContext(context);
- }
-
- /** Sets the context and re-registers the System Ui listener */
- private void setContext(@Nullable Context context) {
- unregisterSystemUiListener();
- mContext = context;
- registerSystemUiListener();
- }
-
- /** Register a listener with System UI to receive updates about desktop tasks state */
- private void registerSystemUiListener() {
- if (mContext == null) {
- return;
- }
- if (mDesktopTaskListener != null) {
- return;
- }
- mDesktopTaskListener = new DesktopTaskListenerImpl(this, mContext.getDisplayId());
- SystemUiProxy.INSTANCE.get(mContext).setDesktopTaskListener(mDesktopTaskListener);
- }
-
- /**
- * Clear listener from System UI that was set with {@link #registerSystemUiListener()}
- */
- private void unregisterSystemUiListener() {
- if (mContext == null) {
- return;
- }
- if (mDesktopTaskListener == null) {
- return;
- }
- SystemUiProxy.INSTANCE.get(mContext).setDesktopTaskListener(null);
- mDesktopTaskListener.release();
- mDesktopTaskListener = null;
- }
-
- /**
- * Whether desktop tasks are visible in desktop mode.
- */
- public boolean areDesktopTasksVisible() {
- boolean desktopTasksVisible = mVisibleDesktopTasksCount > 0;
- if (DEBUG) {
- Log.d(TAG, "areDesktopTasksVisible: desktopVisible=" + desktopTasksVisible);
- }
- return desktopTasksVisible;
- }
-
- /**
- * Whether desktop tasks are visible in desktop mode.
- */
- public boolean areDesktopTasksVisibleAndNotInOverview() {
- boolean desktopTasksVisible = mVisibleDesktopTasksCount > 0;
- if (DEBUG) {
- Log.d(TAG, "areDesktopTasksVisible: desktopVisible=" + desktopTasksVisible
- + " overview=" + mInOverviewState);
- }
- return desktopTasksVisible && !mInOverviewState;
- }
-
- /**
- * Number of visible desktop windows in desktop mode.
- */
- public int getVisibleDesktopTasksCount() {
- return mVisibleDesktopTasksCount;
- }
-
- /** Registers a listener for Desktop Mode visibility updates. */
- public void registerDesktopVisibilityListener(DesktopVisibilityListener listener) {
- mDesktopVisibilityListeners.add(listener);
- }
-
- /** Removes a previously registered Desktop Mode visibility listener. */
- public void unregisterDesktopVisibilityListener(DesktopVisibilityListener listener) {
- mDesktopVisibilityListeners.remove(listener);
- }
-
- /** Registers a listener for Taskbar changes in Desktop Mode. */
- public void registerTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) {
- mTaskbarDesktopModeListeners.add(listener);
- }
-
- /** Removes a previously registered listener for Taskbar changes in Desktop Mode. */
- public void unregisterTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) {
- mTaskbarDesktopModeListeners.remove(listener);
- }
-
- /**
- * Sets the number of desktop windows that are visible and updates launcher visibility based on
- * it.
- */
- public void setVisibleDesktopTasksCount(int visibleTasksCount) {
- if (mContext == null) {
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "setVisibleDesktopTasksCount: visibleTasksCount=" + visibleTasksCount
- + " currentValue=" + mVisibleDesktopTasksCount);
- }
-
- if (visibleTasksCount != mVisibleDesktopTasksCount) {
- final boolean wasVisible = mVisibleDesktopTasksCount > 0;
- final boolean isVisible = visibleTasksCount > 0;
- final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisibleAndNotInOverview();
- mVisibleDesktopTasksCount = visibleTasksCount;
- final boolean areDesktopTasksVisibleNow = areDesktopTasksVisibleAndNotInOverview();
- if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
- notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
- }
-
- if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
- && wasVisible != isVisible) {
- // TODO: b/333533253 - Remove after flag rollout
- if (mVisibleDesktopTasksCount > 0) {
- setLauncherViewsVisibility(View.INVISIBLE);
- if (!mInOverviewState) {
- // When desktop tasks are visible & we're not in overview, we want launcher
- // to appear paused, this ensures that taskbar displays.
- markLauncherPaused();
- }
- } else {
- setLauncherViewsVisibility(View.VISIBLE);
- // If desktop tasks aren't visible, ensure that launcher appears resumed to
- // behave normally.
- markLauncherResumed();
- }
- }
- }
- }
-
- public void onLauncherStateChanged(LauncherState state) {
- onLauncherStateChanged(
- state, state == LauncherState.BACKGROUND_APP, state.isRecentsViewVisible);
- }
-
- public void onLauncherStateChanged(RecentsState state) {
- onLauncherStateChanged(
- state, state == RecentsState.BACKGROUND_APP, state.isRecentsViewVisible());
- }
-
- /**
- * Process launcher state change and update launcher view visibility based on desktop state
- */
- public void onLauncherStateChanged(
- BaseState<?> state, boolean isBackgroundAppState, boolean isRecentsViewVisible) {
- if (DEBUG) {
- Log.d(TAG, "onLauncherStateChanged: newState=" + state);
- }
- setBackgroundStateEnabled(isBackgroundAppState);
- // Desktop visibility tracks overview and background state separately
- setOverviewStateEnabled(!isBackgroundAppState && isRecentsViewVisible);
- }
-
- private void setOverviewStateEnabled(boolean overviewStateEnabled) {
- if (mContext == null) {
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "setOverviewStateEnabled: enabled=" + overviewStateEnabled
- + " currentValue=" + mInOverviewState);
- }
- if (overviewStateEnabled != mInOverviewState) {
- final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisibleAndNotInOverview();
- mInOverviewState = overviewStateEnabled;
- final boolean areDesktopTasksVisibleNow = areDesktopTasksVisibleAndNotInOverview();
- if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
- notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
- }
- if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
- return;
- }
- // TODO: b/333533253 - Clean up after flag rollout
-
- if (mInOverviewState) {
- setLauncherViewsVisibility(View.VISIBLE);
- markLauncherResumed();
- } else if (areDesktopTasksVisibleNow && !mGestureInProgress) {
- // Switching out of overview state and gesture finished.
- // If desktop tasks are still visible, hide launcher again.
- setLauncherViewsVisibility(View.INVISIBLE);
- markLauncherPaused();
- }
- }
- }
-
- private void notifyDesktopVisibilityListeners(boolean areDesktopTasksVisible) {
- if (mContext == null) {
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "notifyDesktopVisibilityListeners: visible=" + areDesktopTasksVisible);
- }
- for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) {
- listener.onDesktopVisibilityChanged(areDesktopTasksVisible);
- }
- DisplayController.INSTANCE.get(mContext).notifyConfigChange();
- }
-
- private void notifyTaskbarDesktopModeListeners(boolean doesAnyTaskRequireTaskbarRounding) {
- if (DEBUG) {
- Log.d(TAG, "notifyTaskbarDesktopModeListeners: doesAnyTaskRequireTaskbarRounding="
- + doesAnyTaskRequireTaskbarRounding);
- }
- for (TaskbarDesktopModeListener listener : mTaskbarDesktopModeListeners) {
- listener.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding);
- }
- }
-
- /**
- * TODO: b/333533253 - Remove after flag rollout
- */
- private void setBackgroundStateEnabled(boolean backgroundStateEnabled) {
- if (DEBUG) {
- Log.d(TAG, "setBackgroundStateEnabled: enabled=" + backgroundStateEnabled
- + " currentValue=" + mBackgroundStateEnabled);
- }
- if (backgroundStateEnabled != mBackgroundStateEnabled) {
- mBackgroundStateEnabled = backgroundStateEnabled;
- if (mBackgroundStateEnabled) {
- setLauncherViewsVisibility(View.VISIBLE);
- markLauncherResumed();
- } else if (areDesktopTasksVisibleAndNotInOverview() && !mGestureInProgress) {
- // Switching out of background state. If desktop tasks are visible, pause launcher.
- setLauncherViewsVisibility(View.INVISIBLE);
- markLauncherPaused();
- }
- }
- }
-
- /**
- * Whether recents gesture is currently in progress.
- *
- * TODO: b/333533253 - Remove after flag rollout
- */
- public boolean isRecentsGestureInProgress() {
- return mGestureInProgress;
- }
-
- /**
- * Notify controller that recents gesture has started.
- *
- * TODO: b/333533253 - Remove after flag rollout
- */
- public void setRecentsGestureStart() {
- if (DEBUG) {
- Log.d(TAG, "setRecentsGestureStart");
- }
- setRecentsGestureInProgress(true);
- }
-
- /**
- * Notify controller that recents gesture finished with the given
- * {@link com.android.quickstep.GestureState.GestureEndTarget}
- *
- * TODO: b/333533253 - Remove after flag rollout
- */
- public void setRecentsGestureEnd(@Nullable GestureState.GestureEndTarget endTarget) {
- if (DEBUG) {
- Log.d(TAG, "setRecentsGestureEnd: endTarget=" + endTarget);
- }
- setRecentsGestureInProgress(false);
-
- if (endTarget == null) {
- // Gesture did not result in a new end target. Ensure launchers gets paused again.
- markLauncherPaused();
- }
- }
-
- /**
- * TODO: b/333533253 - Remove after flag rollout
- */
- private void setRecentsGestureInProgress(boolean gestureInProgress) {
- if (gestureInProgress != mGestureInProgress) {
- mGestureInProgress = gestureInProgress;
- }
- }
-
- /**
- * TODO: b/333533253 - Remove after flag rollout
- */
- private void setLauncherViewsVisibility(int visibility) {
- if (mContext == null) {
- return;
- }
- if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "setLauncherViewsVisibility: visibility=" + visibility + " "
- + Debug.getCaller());
- }
- if (!(mContext instanceof ActivityContext activity)) {
- return;
- }
- View dragLayer = activity.getDragLayer();
- if (dragLayer != null) {
- dragLayer.setVisibility(visibility);
- }
- if (!(activity instanceof Launcher launcher)) {
- return;
- }
- View workspaceView = launcher.getWorkspace();
- if (workspaceView != null) {
- workspaceView.setVisibility(visibility);
- }
- if (launcher instanceof QuickstepLauncher ql
- && ql.getTaskbarUIController() != null
- && mVisibleDesktopTasksCount != 0) {
- ql.getTaskbarUIController().onLauncherVisibilityChanged(visibility == VISIBLE);
- }
- }
-
- /**
- * TODO: b/333533253 - Remove after flag rollout
- */
- private void markLauncherPaused() {
- if (mContext == null) {
- return;
- }
- if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "markLauncherPaused " + Debug.getCaller());
- }
- StatefulActivity<LauncherState> activity =
- QuickstepLauncher.ACTIVITY_TRACKER.getCreatedContext();
- if (activity != null) {
- activity.setPaused();
- }
- }
-
- /**
- * TODO: b/333533253 - Remove after flag rollout
- */
- private void markLauncherResumed() {
- if (mContext == null) {
- return;
- }
- if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "markLauncherResumed " + Debug.getCaller());
- }
- StatefulActivity<LauncherState> activity =
- QuickstepLauncher.ACTIVITY_TRACKER.getCreatedContext();
- // Check activity state before calling setResumed(). Launcher may have been actually
- // paused (eg fullscreen task moved to front).
- // In this case we should not mark the activity as resumed.
- if (activity != null && activity.isResumed()) {
- activity.setResumed();
- }
- }
-
- public void onDestroy() {
- setContext(null);
- }
-
- public void dumpLogs(String prefix, PrintWriter pw) {
- pw.println(prefix + "DesktopVisibilityController:");
-
- pw.println(prefix + "\tmDesktopVisibilityListeners=" + mDesktopVisibilityListeners);
- pw.println(prefix + "\tmVisibleDesktopTasksCount=" + mVisibleDesktopTasksCount);
- pw.println(prefix + "\tmInOverviewState=" + mInOverviewState);
- pw.println(prefix + "\tmBackgroundStateEnabled=" + mBackgroundStateEnabled);
- pw.println(prefix + "\tmGestureInProgress=" + mGestureInProgress);
- pw.println(prefix + "\tmDesktopTaskListener=" + mDesktopTaskListener);
- pw.println(prefix + "\tmContext=" + mContext);
- }
-
- /** A listener for when the user enters/exits Desktop Mode. */
- public interface DesktopVisibilityListener {
- /**
- * Callback for when the user enters or exits Desktop Mode
- *
- * @param visible whether Desktop Mode is now visible
- */
- void onDesktopVisibilityChanged(boolean visible);
- }
-
- /**
- * Wrapper for the IDesktopTaskListener stub to prevent lingering references to the launcher
- * activity via the controller.
- */
- private static class DesktopTaskListenerImpl extends IDesktopTaskListener.Stub {
-
- private DesktopVisibilityController mController;
- private final int mDisplayId;
-
- DesktopTaskListenerImpl(@NonNull DesktopVisibilityController controller, int displayId) {
- mController = controller;
- mDisplayId = displayId;
- }
-
- /**
- * Clears any references to the controller.
- */
- void release() {
- mController = null;
- }
-
- @Override
- public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) {
- MAIN_EXECUTOR.execute(() -> {
- if (mController != null && displayId == mDisplayId) {
- if (DEBUG) {
- Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount);
- }
- mController.setVisibleDesktopTasksCount(visibleTasksCount);
- }
- });
- }
-
- @Override
- public void onStashedChanged(int displayId, boolean stashed) {
- Log.w(TAG, "DesktopTaskListenerImpl: onStashedChanged is deprecated");
- }
-
- @Override
- public void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding) {
- MAIN_EXECUTOR.execute(() -> {
- if (mController != null && DesktopModeStatus.useRoundedCorners()) {
- Log.d(TAG, "DesktopTaskListenerImpl: doesAnyTaskRequireTaskbarRounding= "
- + doesAnyTaskRequireTaskbarRounding);
- mController.notifyTaskbarDesktopModeListeners(
- doesAnyTaskRequireTaskbarRounding);
- }
- });
- }
-
- public void onEnterDesktopModeTransitionStarted(int transitionDuration) {
-
- }
-
- @Override
- public void onExitDesktopModeTransitionStarted(int transitionDuration) {
-
- }
- }
-
- /** A listener for Taskbar in Desktop Mode. */
- public interface TaskbarDesktopModeListener {
- /**
- * Callback for when task is resized in desktop mode.
- *
- * @param doesAnyTaskRequireTaskbarRounding whether task requires taskbar corner roundness.
- */
- void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
new file mode 100644
index 0000000..5a8302c
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2022 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.statehandlers
+
+import android.content.Context
+import android.os.Debug
+import android.util.Log
+import android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
+import com.android.launcher3.LauncherState
+import com.android.launcher3.dagger.ApplicationContext
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppSingleton
+import com.android.launcher3.statemanager.BaseState
+import com.android.launcher3.statemanager.StatefulActivity
+import com.android.launcher3.uioverrides.QuickstepLauncher
+import com.android.launcher3.util.DaggerSingletonObject
+import com.android.launcher3.util.DaggerSingletonTracker
+import com.android.launcher3.util.Executors
+import com.android.launcher3.util.window.WindowManagerProxy.DesktopVisibilityListener
+import com.android.quickstep.GestureState.GestureEndTarget
+import com.android.quickstep.SystemUiProxy
+import com.android.quickstep.fallback.RecentsState
+import com.android.wm.shell.desktopmode.IDesktopTaskListener.Stub
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import java.io.PrintWriter
+import java.lang.ref.WeakReference
+import javax.inject.Inject
+
+/**
+ * Controls the visibility of the workspace and the resumed / paused state when desktop mode is
+ * enabled.
+ */
+@LauncherAppSingleton
+class DesktopVisibilityController
+@Inject
+constructor(
+ @ApplicationContext private val context: Context,
+ systemUiProxy: SystemUiProxy,
+ lifecycleTracker: DaggerSingletonTracker,
+) {
+ private val desktopVisibilityListeners: MutableSet<DesktopVisibilityListener> = HashSet()
+ private val taskbarDesktopModeListeners: MutableSet<TaskbarDesktopModeListener> = HashSet()
+
+ /** Number of visible desktop windows in desktop mode. */
+ var visibleDesktopTasksCount: Int = 0
+ /**
+ * Sets the number of desktop windows that are visible and updates launcher visibility based
+ * on it.
+ */
+ set(visibleTasksCount) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ ("setVisibleDesktopTasksCount: visibleTasksCount=" +
+ visibleTasksCount +
+ " currentValue=" +
+ field),
+ )
+ }
+
+ if (visibleTasksCount != field) {
+ val wasVisible = field > 0
+ val isVisible = visibleTasksCount > 0
+ val wereDesktopTasksVisibleBefore = areDesktopTasksVisible()
+ field = visibleTasksCount
+ val areDesktopTasksVisibleNow = areDesktopTasksVisible()
+ if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+ notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow)
+ }
+
+ if (
+ !ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue && wasVisible != isVisible
+ ) {
+ // TODO: b/333533253 - Remove after flag rollout
+ if (field > 0) {
+ if (!inOverviewState) {
+ // When desktop tasks are visible & we're not in overview, we want
+ // launcher
+ // to appear paused, this ensures that taskbar displays.
+ markLauncherPaused()
+ }
+ } else {
+ // If desktop tasks aren't visible, ensure that launcher appears resumed to
+ // behave normally.
+ markLauncherResumed()
+ }
+ }
+ }
+ }
+
+ private var inOverviewState = false
+ private var backgroundStateEnabled = false
+ private var gestureInProgress = false
+
+ private var desktopTaskListener: DesktopTaskListenerImpl?
+
+ init {
+ desktopTaskListener = DesktopTaskListenerImpl(this, context.displayId)
+ systemUiProxy.setDesktopTaskListener(desktopTaskListener)
+
+ lifecycleTracker.addCloseable {
+ desktopTaskListener = null
+ systemUiProxy.setDesktopTaskListener(null)
+ }
+ }
+
+ /** Whether desktop tasks are visible in desktop mode. */
+ fun areDesktopTasksVisible(): Boolean {
+ val desktopTasksVisible: Boolean = visibleDesktopTasksCount > 0
+ if (DEBUG) {
+ Log.d(TAG, "areDesktopTasksVisible: desktopVisible=$desktopTasksVisible")
+ }
+ return desktopTasksVisible
+ }
+
+ /** Whether desktop tasks are visible in desktop mode. */
+ fun areDesktopTasksVisibleAndNotInOverview(): Boolean {
+ val desktopTasksVisible: Boolean = visibleDesktopTasksCount > 0
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ ("areDesktopTasksVisible: desktopVisible=" +
+ desktopTasksVisible +
+ " overview=" +
+ inOverviewState),
+ )
+ }
+ return desktopTasksVisible && !inOverviewState
+ }
+
+ /** Registers a listener for Taskbar changes in Desktop Mode. */
+ fun registerTaskbarDesktopModeListener(listener: TaskbarDesktopModeListener) {
+ taskbarDesktopModeListeners.add(listener)
+ }
+
+ /** Removes a previously registered listener for Taskbar changes in Desktop Mode. */
+ fun unregisterTaskbarDesktopModeListener(listener: TaskbarDesktopModeListener) {
+ taskbarDesktopModeListeners.remove(listener)
+ }
+
+ fun onLauncherStateChanged(state: LauncherState) {
+ onLauncherStateChanged(
+ state,
+ state === LauncherState.BACKGROUND_APP,
+ state.isRecentsViewVisible,
+ )
+ }
+
+ fun onLauncherStateChanged(state: RecentsState) {
+ onLauncherStateChanged(
+ state,
+ state === RecentsState.BACKGROUND_APP,
+ state.isRecentsViewVisible,
+ )
+ }
+
+ /** Process launcher state change and update launcher view visibility based on desktop state */
+ fun onLauncherStateChanged(
+ state: BaseState<*>,
+ isBackgroundAppState: Boolean,
+ isRecentsViewVisible: Boolean,
+ ) {
+ if (DEBUG) {
+ Log.d(TAG, "onLauncherStateChanged: newState=$state")
+ }
+ setBackgroundStateEnabled(isBackgroundAppState)
+ // Desktop visibility tracks overview and background state separately
+ setOverviewStateEnabled(!isBackgroundAppState && isRecentsViewVisible)
+ }
+
+ private fun setOverviewStateEnabled(overviewStateEnabled: Boolean) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ ("setOverviewStateEnabled: enabled=" +
+ overviewStateEnabled +
+ " currentValue=" +
+ inOverviewState),
+ )
+ }
+ if (overviewStateEnabled != inOverviewState) {
+ val wereDesktopTasksVisibleBefore = areDesktopTasksVisible()
+ inOverviewState = overviewStateEnabled
+ val areDesktopTasksVisibleNow = areDesktopTasksVisible()
+ if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+ notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow)
+ }
+
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue) {
+ return
+ }
+
+ // TODO: b/333533253 - Clean up after flag rollout
+ if (inOverviewState) {
+ markLauncherResumed()
+ } else if (areDesktopTasksVisibleNow && !gestureInProgress) {
+ // Switching out of overview state and gesture finished.
+ // If desktop tasks are still visible, hide launcher again.
+ markLauncherPaused()
+ }
+ }
+ }
+
+ /** Registers a listener for Taskbar changes in Desktop Mode. */
+ fun registerDesktopVisibilityListener(listener: DesktopVisibilityListener) {
+ desktopVisibilityListeners.add(listener)
+ }
+
+ /** Removes a previously registered listener for Taskbar changes in Desktop Mode. */
+ fun unregisterDesktopVisibilityListener(listener: DesktopVisibilityListener) {
+ desktopVisibilityListeners.remove(listener)
+ }
+
+ private fun notifyDesktopVisibilityListeners(areDesktopTasksVisible: Boolean) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyDesktopVisibilityListeners: visible=$areDesktopTasksVisible")
+ }
+ for (listener in desktopVisibilityListeners) {
+ listener.onDesktopVisibilityChanged(areDesktopTasksVisible)
+ }
+ }
+
+ private fun notifyTaskbarDesktopModeListeners(doesAnyTaskRequireTaskbarRounding: Boolean) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "notifyTaskbarDesktopModeListeners: doesAnyTaskRequireTaskbarRounding=" +
+ doesAnyTaskRequireTaskbarRounding,
+ )
+ }
+ for (listener in taskbarDesktopModeListeners) {
+ listener.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding)
+ }
+ }
+
+ /** TODO: b/333533253 - Remove after flag rollout */
+ private fun setBackgroundStateEnabled(backgroundStateEnabled: Boolean) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ ("setBackgroundStateEnabled: enabled=" +
+ backgroundStateEnabled +
+ " currentValue=" +
+ this.backgroundStateEnabled),
+ )
+ }
+ if (backgroundStateEnabled != this.backgroundStateEnabled) {
+ this.backgroundStateEnabled = backgroundStateEnabled
+ if (this.backgroundStateEnabled) {
+ markLauncherResumed()
+ } else if (areDesktopTasksVisible() && !gestureInProgress) {
+ // Switching out of background state. If desktop tasks are visible, pause launcher.
+ markLauncherPaused()
+ }
+ }
+ }
+
+ var isRecentsGestureInProgress: Boolean
+ /**
+ * Whether recents gesture is currently in progress.
+ *
+ * TODO: b/333533253 - Remove after flag rollout
+ */
+ get() = gestureInProgress
+ /** TODO: b/333533253 - Remove after flag rollout */
+ private set(gestureInProgress) {
+ if (gestureInProgress != this.gestureInProgress) {
+ this.gestureInProgress = gestureInProgress
+ }
+ }
+
+ /**
+ * Notify controller that recents gesture has started.
+ *
+ * TODO: b/333533253 - Remove after flag rollout
+ */
+ fun setRecentsGestureStart() {
+ if (DEBUG) {
+ Log.d(TAG, "setRecentsGestureStart")
+ }
+ isRecentsGestureInProgress = true
+ }
+
+ /**
+ * Notify controller that recents gesture finished with the given
+ * [com.android.quickstep.GestureState.GestureEndTarget]
+ *
+ * TODO: b/333533253 - Remove after flag rollout
+ */
+ fun setRecentsGestureEnd(endTarget: GestureEndTarget?) {
+ if (DEBUG) {
+ Log.d(TAG, "setRecentsGestureEnd: endTarget=$endTarget")
+ }
+ isRecentsGestureInProgress = false
+
+ if (endTarget == null) {
+ // Gesture did not result in a new end target. Ensure launchers gets paused again.
+ markLauncherPaused()
+ }
+ }
+
+ /** TODO: b/333533253 - Remove after flag rollout */
+ private fun markLauncherPaused() {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue) {
+ return
+ }
+ if (DEBUG) {
+ Log.d(TAG, "markLauncherPaused " + Debug.getCaller())
+ }
+ val activity: StatefulActivity<LauncherState>? =
+ QuickstepLauncher.ACTIVITY_TRACKER.getCreatedContext()
+ activity?.setPaused()
+ }
+
+ /** TODO: b/333533253 - Remove after flag rollout */
+ private fun markLauncherResumed() {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue) {
+ return
+ }
+ if (DEBUG) {
+ Log.d(TAG, "markLauncherResumed " + Debug.getCaller())
+ }
+ val activity: StatefulActivity<LauncherState>? =
+ QuickstepLauncher.ACTIVITY_TRACKER.getCreatedContext()
+ // Check activity state before calling setResumed(). Launcher may have been actually
+ // paused (eg fullscreen task moved to front).
+ // In this case we should not mark the activity as resumed.
+ if (activity != null && activity.isResumed) {
+ activity.setResumed()
+ }
+ }
+
+ fun dumpLogs(prefix: String, pw: PrintWriter) {
+ pw.println(prefix + "DesktopVisibilityController:")
+
+ pw.println("$prefix\tdesktopVisibilityListeners=$desktopVisibilityListeners")
+ pw.println("$prefix\tvisibleDesktopTasksCount=$visibleDesktopTasksCount")
+ pw.println("$prefix\tinOverviewState=$inOverviewState")
+ pw.println("$prefix\tbackgroundStateEnabled=$backgroundStateEnabled")
+ pw.println("$prefix\tgestureInProgress=$gestureInProgress")
+ pw.println("$prefix\tdesktopTaskListener=$desktopTaskListener")
+ pw.println("$prefix\tcontext=$context")
+ }
+
+ /**
+ * Wrapper for the IDesktopTaskListener stub to prevent lingering references to the launcher
+ * activity via the controller.
+ */
+ private class DesktopTaskListenerImpl(
+ controller: DesktopVisibilityController,
+ private val displayId: Int,
+ ) : Stub() {
+ private val controller = WeakReference(controller)
+
+ override fun onTasksVisibilityChanged(displayId: Int, visibleTasksCount: Int) {
+ if (displayId != this.displayId) return
+ Executors.MAIN_EXECUTOR.execute {
+ controller.get()?.apply {
+ if (DEBUG) {
+ Log.d(TAG, "desktop visible tasks count changed=$visibleTasksCount")
+ }
+ visibleDesktopTasksCount = visibleTasksCount
+ }
+ }
+ }
+
+ override fun onStashedChanged(displayId: Int, stashed: Boolean) {
+ Log.w(TAG, "DesktopTaskListenerImpl: onStashedChanged is deprecated")
+ }
+
+ override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) {
+ if (!DesktopModeStatus.useRoundedCorners()) return
+ Executors.MAIN_EXECUTOR.execute {
+ controller.get()?.apply {
+ Log.d(
+ TAG,
+ "DesktopTaskListenerImpl: doesAnyTaskRequireTaskbarRounding= " +
+ doesAnyTaskRequireTaskbarRounding,
+ )
+ notifyTaskbarDesktopModeListeners(doesAnyTaskRequireTaskbarRounding)
+ }
+ }
+ }
+
+ override fun onEnterDesktopModeTransitionStarted(transitionDuration: Int) {}
+
+ override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {}
+ }
+
+ /** A listener for Taskbar in Desktop Mode. */
+ interface TaskbarDesktopModeListener {
+ /**
+ * Callback for when task is resized in desktop mode.
+ *
+ * @param doesAnyTaskRequireTaskbarRounding whether task requires taskbar corner roundness.
+ */
+ fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean)
+ }
+
+ companion object {
+ @JvmField
+ val INSTANCE = DaggerSingletonObject(LauncherAppComponent::getDesktopVisibilityController)
+
+ private const val TAG = "DesktopVisController"
+ private const val DEBUG = false
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 060173a..ee9c6a1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -237,7 +237,6 @@
@Nullable Context navigationBarPanelContext, DeviceProfile launcherDp,
TaskbarNavButtonController buttonController,
ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider,
- @NonNull DesktopVisibilityController desktopVisibilityController,
boolean isPrimaryDisplay) {
super(windowContext);
mIsPrimaryDisplay = isPrimaryDisplay;
@@ -363,7 +362,7 @@
new KeyboardQuickSwitchController(),
new TaskbarPinningController(this),
bubbleControllersOptional,
- new TaskbarDesktopModeController(desktopVisibilityController));
+ new TaskbarDesktopModeController(DesktopVisibilityController.INSTANCE.get(this)));
mLauncherPrefs = LauncherPrefs.get(this);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 13f9a51..3fa0e8e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -62,7 +62,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
@@ -223,14 +222,11 @@
}
};
- @NonNull private final DesktopVisibilityController mDesktopVisibilityController;
-
@SuppressLint("WrongConstant")
public TaskbarManager(
Context context,
AllAppsActionManager allAppsActionManager,
- TaskbarNavButtonCallbacks navCallbacks,
- @NonNull DesktopVisibilityController desktopVisibilityController) {
+ TaskbarNavButtonCallbacks navCallbacks) {
Display display =
context.getSystemService(DisplayManager.class).getDisplay(context.getDisplayId());
mWindowContext = context.createWindowContext(display,
@@ -240,7 +236,6 @@
mNavigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
? context.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
: null;
- mDesktopVisibilityController = desktopVisibilityController;
if (enableTaskbarNoRecreate()) {
mWindowManager = mWindowContext.getSystemService(WindowManager.class);
createTaskbarRootLayout(getDefaultDisplayId());
@@ -800,7 +795,7 @@
private TaskbarActivityContext createTaskbarActivityContext(DeviceProfile dp, int displayId) {
TaskbarActivityContext newTaskbar = new TaskbarActivityContext(mWindowContext,
mNavigationBarPanelContext, dp, mDefaultNavButtonController,
- mUnfoldProgressProvider, mDesktopVisibilityController, isDefaultDisplay(displayId));
+ mUnfoldProgressProvider, isDefaultDisplay(displayId));
addTaskbarToMap(displayId, newTaskbar);
return newTaskbar;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 6d744c2..70c53fa 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1018,9 +1018,9 @@
@Override
public void setResumed() {
- DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController();
+ DesktopVisibilityController desktopVisibilityController =
+ DesktopVisibilityController.INSTANCE.get(this);
if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
- && desktopVisibilityController != null
&& desktopVisibilityController.areDesktopTasksVisibleAndNotInOverview()
&& !desktopVisibilityController.isRecentsGestureInProgress()) {
// Return early to skip setting activity to appear as resumed
@@ -1187,12 +1187,6 @@
}
@Nullable
- @Override
- public DesktopVisibilityController getDesktopVisibilityController() {
- return mTISBindHelper.getDesktopVisibilityController();
- }
-
- @Nullable
public UnfoldTransitionProgressProvider getUnfoldTransitionProgressProvider() {
return mUnfoldTransitionProgressProvider;
}
@@ -1347,11 +1341,8 @@
@Override
public boolean areDesktopTasksVisible() {
- DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController();
- if (desktopVisibilityController != null) {
- return desktopVisibilityController.areDesktopTasksVisibleAndNotInOverview();
- }
- return false;
+ return DesktopVisibilityController.INSTANCE.get(this)
+ .areDesktopTasksVisibleAndNotInOverview();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 1437a6e..7cab751 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -86,8 +86,8 @@
if (endTarget != null) {
// We were on our way to this state when we got canceled, end there instead.
startState = stateFromGestureEndTarget(endTarget);
- DesktopVisibilityController controller = getDesktopVisibilityController();
- if (controller != null && controller.areDesktopTasksVisibleAndNotInOverview()
+ if (DesktopVisibilityController.INSTANCE.get(activity)
+ .areDesktopTasksVisibleAndNotInOverview()
&& endTarget == LAST_TASK) {
// When we are cancelling the transition and going back to last task, move to
// rest state instead when desktop tasks are visible.
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index 2171c47..e2ebaa5 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -179,13 +179,6 @@
mOnInitBackgroundStateUICallback = callback;
}
- @Nullable
- public DesktopVisibilityController getDesktopVisibilityController() {
- CONTAINER_TYPE container = getCreatedContainer();
-
- return container == null ? null : container.getDesktopVisibilityController();
- }
-
/**
* Called when the gesture ends and the animation starts towards the given target. Used to add
* an optional additional animation with the same duration.
@@ -241,9 +234,8 @@
if (endTarget != null) {
// We were on our way to this state when we got canceled, end there instead.
startState = stateFromGestureEndTarget(endTarget);
- DesktopVisibilityController controller = getDesktopVisibilityController();
- if (controller != null && controller.areDesktopTasksVisibleAndNotInOverview()
- && endTarget == LAST_TASK) {
+ if (DesktopVisibilityController.INSTANCE.get(recentsView.getContext())
+ .areDesktopTasksVisibleAndNotInOverview() && endTarget == LAST_TASK) {
// When we are cancelling the transition and going back to last task, move to
// rest state instead when desktop tasks are visible.
// If a fullscreen task is visible, launcher goes to normal state when the
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 243a577..7af0618 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -39,6 +39,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.MSDLPlayerWrapper;
@@ -105,9 +106,8 @@
boolean canUseWorkspaceView = workspaceView != null
&& workspaceView.isAttachedToWindow()
&& workspaceView.getHeight() > 0
- && (mContainer.getDesktopVisibilityController() == null
- || !mContainer.getDesktopVisibilityController()
- .areDesktopTasksVisibleAndNotInOverview());
+ && !DesktopVisibilityController.INSTANCE.get(mContainer)
+ .areDesktopTasksVisibleAndNotInOverview();
mContainer.getRootView().setForceHideBackArrow(true);
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 17c17cc..b34b502 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -65,7 +65,6 @@
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.desktop.DesktopRecentsTransitionController;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.statemanager.StateManager.StateHandler;
@@ -558,10 +557,4 @@
public boolean isRecentsViewVisible() {
return getStateManager().getState().isRecentsViewVisible();
}
-
- @Nullable
- @Override
- public DesktopVisibilityController getDesktopVisibilityController() {
- return mTISBindHelper.getDesktopVisibilityController();
- }
}
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 91d0776..89337e5 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -67,16 +67,13 @@
* running tasks
*/
public RemoteTargetGluer(Context context, BaseContainerInterface sizingStrategy) {
- DesktopVisibilityController desktopVisibilityController =
- sizingStrategy.getDesktopVisibilityController();
- if (desktopVisibilityController != null) {
- int visibleTasksCount = desktopVisibilityController.getVisibleDesktopTasksCount();
- if (visibleTasksCount > 0) {
- // Allocate +1 to account for a new task added to the desktop mode
- int numHandles = visibleTasksCount + 1;
- init(context, sizingStrategy, numHandles, true /* forDesktop */);
- return;
- }
+ int visibleTasksCount = DesktopVisibilityController.INSTANCE.get(context)
+ .getVisibleDesktopTasksCount();
+ if (visibleTasksCount > 0) {
+ // Allocate +1 to account for a new task added to the desktop mode
+ int numHandles = visibleTasksCount + 1;
+ init(context, sizingStrategy, numHandles, true /* forDesktop */);
+ return;
}
// Assume 2 handles needed for split, scale down as needed later on when we actually
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 3bfdc21..aea02af 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -424,18 +424,6 @@
return tis.mTaskbarManager;
}
- /**
- * Returns the {@link DesktopVisibilityController}
- * <p>
- * Returns {@code null} if TouchInteractionService is not connected
- */
- @Nullable
- public DesktopVisibilityController getDesktopVisibilityController() {
- TouchInteractionService tis = mTis.get();
- if (tis == null) return null;
- return tis.mDesktopVisibilityController;
- }
-
@VisibleForTesting
public void injectFakeTrackpadForTesting() {
TouchInteractionService tis = mTis.get();
@@ -554,7 +542,6 @@
private NavigationMode mGestureStartNavMode = null;
- private DesktopVisibilityController mDesktopVisibilityController;
private DesktopAppLaunchTransitionManager mDesktopAppLaunchTransitionManager;
@Override
@@ -578,9 +565,7 @@
initInputMonitor("onTrackpadConnected()");
});
- mDesktopVisibilityController = new DesktopVisibilityController(this);
- mTaskbarManager = new TaskbarManager(
- this, mAllAppsActionManager, mNavCallbacks, mDesktopVisibilityController);
+ mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager, mNavCallbacks);
mDesktopAppLaunchTransitionManager =
new DesktopAppLaunchTransitionManager(this, SystemUiProxy.INSTANCE.get(this));
mDesktopAppLaunchTransitionManager.registerTransitions();
@@ -741,7 +726,6 @@
mDesktopAppLaunchTransitionManager.unregisterTransitions();
}
mDesktopAppLaunchTransitionManager = null;
- mDesktopVisibilityController.onDestroy();
LockedUserState.get(this).removeOnUserUnlockedRunnable(mUserUnlockedRunnable);
ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener);
@@ -1164,7 +1148,7 @@
createdOverviewContainer.getDeviceProfile().dump(this, "", pw);
}
mTaskbarManager.dumpLogs("", pw);
- mDesktopVisibilityController.dumpLogs("", pw);
+ DesktopVisibilityController.INSTANCE.get(this).dumpLogs("", pw);
pw.println("ContextualSearchStateManager:");
ContextualSearchStateManager.INSTANCE.get(this).dump("\t", pw);
SystemUiProxy.INSTANCE.get(this).dump(pw);
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
index 20a66dd..549c15b 100644
--- a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
+++ b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
@@ -19,6 +19,7 @@
import com.android.launcher3.dagger.LauncherAppComponent;
import com.android.launcher3.dagger.LauncherBaseAppComponent;
import com.android.launcher3.model.WellbeingModel;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.quickstep.OverviewComponentObserver;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.fallback.window.RecentsDisplayModel;
@@ -43,4 +44,6 @@
RecentsDisplayModel getRecentsDisplayModel();
OverviewComponentObserver getOverviewComponentObserver();
+
+ DesktopVisibilityController getDesktopVisibilityController();
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 9625d29..b76e39a 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -36,6 +36,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.desktop.DesktopRecentsTransitionController;
import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.statemanager.StatefulContainer;
@@ -268,9 +269,7 @@
@Override
public void onStateTransitionComplete(RecentsState finalState) {
- if (mContainer.getDesktopVisibilityController() != null) {
- mContainer.getDesktopVisibilityController().onLauncherStateChanged(finalState);
- }
+ DesktopVisibilityController.INSTANCE.get(mContainer).onLauncherStateChanged(finalState);
if (!finalState.isRecentsViewVisible()) {
// Clean-up logic that occurs when recents is no longer in use/visible.
reset();
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
index 9bd7a19..9a38ff6 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
@@ -37,7 +37,6 @@
import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory
import com.android.launcher3.R
import com.android.launcher3.compat.AccessibilityManagerCompat
-import com.android.launcher3.statehandlers.DesktopVisibilityController
import com.android.launcher3.statemanager.StateManager
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory
import com.android.launcher3.statemanager.StatefulContainer
@@ -310,10 +309,6 @@
return overviewCommandHelper == null || overviewCommandHelper.canStartHomeSafely()
}
- override fun getDesktopVisibilityController(): DesktopVisibilityController? {
- return tisBindHelper.desktopVisibilityController
- }
-
override fun setTaskbarUIController(taskbarUIController: TaskbarUIController?) {
this.taskbarUIController = taskbarUIController
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index a952617..b040723 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -89,7 +89,9 @@
override fun onAttachedToWindow() {
super.onAttachedToWindow()
viewAttachedScope =
- CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("TaskThumbnailView"))
+ CoroutineScope(
+ SupervisorJob() + Dispatchers.Main.immediate + CoroutineName("TaskThumbnailView")
+ )
viewData = RecentsDependencies.get(this)
updateViewDataValues()
viewModel = RecentsDependencies.get(this)
diff --git a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
index 0f61b95..677875c 100644
--- a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
+++ b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
@@ -67,7 +67,9 @@
fun init() {
overlayInitializedScope =
- CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("TaskOverlayHelper"))
+ CoroutineScope(
+ SupervisorJob() + Dispatchers.Main.immediate + CoroutineName("TaskOverlayHelper")
+ )
viewModel =
TaskOverlayViewModel(
task = task,
diff --git a/quickstep/src/com/android/quickstep/util/ContextualSearchInvoker.kt b/quickstep/src/com/android/quickstep/util/ContextualSearchInvoker.kt
index 724fa40..d00a39c 100644
--- a/quickstep/src/com/android/quickstep/util/ContextualSearchInvoker.kt
+++ b/quickstep/src/com/android/quickstep/util/ContextualSearchInvoker.kt
@@ -161,7 +161,11 @@
statsLogManager.logger().log(LAUNCHER_LAUNCH_OMNI_FAILED_NOT_AVAILABLE)
return false
}
-
+ if (isFakeLandscape()) {
+ // TODO (b/383421642): Fake landscape is to be removed in 25Q3 and this entire block
+ // can be removed when that happens.
+ return false
+ }
return true
}
@@ -197,6 +201,13 @@
return true
}
+ private fun isFakeLandscape(): Boolean =
+ getRecentsContainerInterface()
+ ?.getCreatedContainer()
+ ?.getOverviewPanel<RecentsView<*, *>>()
+ ?.getPagedOrientationHandler()
+ ?.isLayoutNaturalToLauncher == false
+
private fun isInSplitscreen(): Boolean {
return topTaskTracker.getRunningSplitTaskIds().isNotEmpty()
}
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index 7fadc7d..4d56c63 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -27,10 +27,8 @@
import android.view.WindowMetrics;
import com.android.internal.policy.SystemBarUtils;
-import com.android.launcher3.dagger.ApplicationContext;
import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
-import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
@@ -48,14 +46,13 @@
@LauncherAppSingleton
public class SystemWindowManagerProxy extends WindowManagerProxy {
- private final TISBindHelper mTISBindHelper;
+ private final DesktopVisibilityController mDesktopVisibilityController;
+
@Inject
- public SystemWindowManagerProxy(@ApplicationContext Context context,
- DaggerSingletonTracker lifecycleTracker) {
+ public SystemWindowManagerProxy(DesktopVisibilityController desktopVisibilityController) {
super(true);
- mTISBindHelper = new TISBindHelper(context, binder -> {});
- lifecycleTracker.addCloseable(mTISBindHelper::onDestroy);
+ mDesktopVisibilityController = desktopVisibilityController;
}
@Override
@@ -65,10 +62,18 @@
}
@Override
+ public void registerDesktopVisibilityListener(DesktopVisibilityListener listener) {
+ mDesktopVisibilityController.registerDesktopVisibilityListener(listener);
+ }
+
+ @Override
+ public void unregisterDesktopVisibilityListener(DesktopVisibilityListener listener) {
+ mDesktopVisibilityController.unregisterDesktopVisibilityListener(listener);
+ }
+
+ @Override
public boolean isInDesktopMode() {
- DesktopVisibilityController desktopController =
- mTISBindHelper.getDesktopVisibilityController();
- return desktopController != null && desktopController.areDesktopTasksVisible();
+ return mDesktopVisibilityController.areDesktopTasksVisible();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/util/TISBindHelper.java b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
index b238dec..027dc08 100644
--- a/quickstep/src/com/android/quickstep/util/TISBindHelper.java
+++ b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
@@ -26,7 +26,6 @@
import androidx.annotation.Nullable;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.taskbar.TaskbarManager;
import com.android.quickstep.OverviewCommandHelper;
import com.android.quickstep.TouchInteractionService;
@@ -110,11 +109,6 @@
return mBinder == null ? null : mBinder.getTaskbarManager();
}
- @Nullable
- public DesktopVisibilityController getDesktopVisibilityController() {
- return mBinder == null ? null : mBinder.getDesktopVisibilityController();
- }
-
/**
* Sets flag whether a predictive back-to-home animation is in progress
*/
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index b9f44fe..7a7a7f9 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -168,9 +168,7 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- if (mContainer.getDesktopVisibilityController() != null) {
- mContainer.getDesktopVisibilityController().onLauncherStateChanged(finalState);
- }
+ DesktopVisibilityController.INSTANCE.get(mContainer).onLauncherStateChanged(finalState);
if (!finalState.isRecentsViewVisible) {
// Clean-up logic that occurs when recents is no longer in use/visible.
@@ -269,34 +267,26 @@
public void onGestureAnimationStart(Task[] runningTasks,
RotationTouchHelper rotationTouchHelper) {
super.onGestureAnimationStart(runningTasks, rotationTouchHelper);
- DesktopVisibilityController desktopVisibilityController =
- mContainer.getDesktopVisibilityController();
- if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
- && desktopVisibilityController != null) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
// TODO: b/333533253 - Remove after flag rollout
- desktopVisibilityController.setRecentsGestureStart();
+ DesktopVisibilityController.INSTANCE.get(mContainer).setRecentsGestureStart();
}
}
@Override
public void onGestureAnimationEnd() {
- DesktopVisibilityController desktopVisibilityController =
- mContainer.getDesktopVisibilityController();
+ final DesktopVisibilityController desktopVisibilityController =
+ DesktopVisibilityController.INSTANCE.get(mContainer);
boolean showDesktopApps = false;
- GestureState.GestureEndTarget endTarget = null;
- if (desktopVisibilityController != null) {
- desktopVisibilityController = mContainer.getDesktopVisibilityController();
- endTarget = mCurrentGestureEndTarget;
- if (endTarget == GestureState.GestureEndTarget.LAST_TASK
- && desktopVisibilityController.areDesktopTasksVisibleAndNotInOverview()) {
- // Recents gesture was cancelled and we are returning to the previous task.
- // After super class has handled clean up, show desktop apps on top again
- showDesktopApps = true;
- }
+ GestureState.GestureEndTarget endTarget = mCurrentGestureEndTarget;
+ if (endTarget == GestureState.GestureEndTarget.LAST_TASK
+ && desktopVisibilityController.areDesktopTasksVisibleAndNotInOverview()) {
+ // Recents gesture was cancelled and we are returning to the previous task.
+ // After super class has handled clean up, show desktop apps on top again
+ showDesktopApps = true;
}
super.onGestureAnimationEnd();
- if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
- && desktopVisibilityController != null) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
// TODO: b/333533253 - Remove after flag rollout
desktopVisibilityController.setRecentsGestureEnd(endTarget);
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 3983fe9..ab96474 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1250,7 +1250,6 @@
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
-
// Clear the task data for the removed child if it was visible unless:
// - It's the initial taskview for entering split screen, we only pretend to dismiss the
// task
@@ -1258,22 +1257,25 @@
if (child instanceof TaskView) {
mTaskViewCount = Math.max(0, --mTaskViewCount);
if (child != mSplitHiddenTaskView && child != mMovingTaskView) {
- TaskView taskView = (TaskView) child;
- for (int i : taskView.getTaskIds()) {
- mHasVisibleTaskData.delete(i);
- }
- if (child instanceof GroupedTaskView) {
- mGroupedTaskViewPool.recycle((GroupedTaskView) taskView);
- } else if (child instanceof DesktopTaskView) {
- mDesktopTaskViewPool.recycle((DesktopTaskView) taskView);
- } else {
- mTaskViewPool.recycle(taskView);
- }
- mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, !hasTaskViews());
+ clearAndRecycleTaskView((TaskView) child);
}
}
}
+ private void clearAndRecycleTaskView(TaskView taskView) {
+ for (int i : taskView.getTaskIds()) {
+ mHasVisibleTaskData.delete(i);
+ }
+ if (taskView instanceof GroupedTaskView) {
+ mGroupedTaskViewPool.recycle((GroupedTaskView) taskView);
+ } else if (taskView instanceof DesktopTaskView) {
+ mDesktopTaskViewPool.recycle((DesktopTaskView) taskView);
+ } else {
+ mTaskViewPool.recycle(taskView);
+ }
+ mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, !hasTaskViews());
+ }
+
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
@@ -5434,6 +5436,13 @@
mSplitHiddenTaskViewIndex = -1;
if (mSplitHiddenTaskView != null) {
mSplitHiddenTaskView.setThumbnailVisibility(VISIBLE, INVALID_TASK_ID);
+ // mSplitHiddenTaskView is set when split select animation starts. The TaskView is only
+ // removed when when the animation finishes. So in the case of overview being dismissed
+ // during the animation, we should not call clearAndRecycleTaskView() because it has
+ // not been removed yet.
+ if (mSplitHiddenTaskView.getParent() == null) {
+ clearAndRecycleTaskView(mSplitHiddenTaskView);
+ }
mSplitHiddenTaskView = null;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
index a1d22fe..b1a4808 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
@@ -29,7 +29,6 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.logger.LauncherAtom;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.ScrimView;
@@ -209,9 +208,6 @@
.build());
}
- @Nullable
- DesktopVisibilityController getDesktopVisibilityController();
-
void setTaskbarUIController(@Nullable TaskbarUIController taskbarUIController);
@Nullable TaskbarUIController getTaskbarUIController();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
index 87771c6..d92c4d0 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
@@ -44,10 +44,12 @@
// Update recentsViewModel and apply the thumbnailOverride ASAP, before waiting inside
// viewAttachedScope.
recentsViewModel.setRunningTaskShowScreenshot(true)
- recentsCoroutineScope.launch(dispatcherProvider.main) {
+ recentsCoroutineScope.launch(dispatcherProvider.background) {
recentsViewModel.waitForRunningTaskShowScreenshotToUpdate()
recentsViewModel.waitForThumbnailsToUpdate(updatedThumbnails)
- withContext(Dispatchers.Main) { ViewUtils.postFrameDrawn(taskView, onFinishRunnable) }
+ withContext(Dispatchers.Main.immediate) {
+ ViewUtils.postFrameDrawn(taskView, onFinishRunnable)
+ }
}
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarControllerTestUtil.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarControllerTestUtil.kt
index 6e2f74a..0e066cd 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarControllerTestUtil.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarControllerTestUtil.kt
@@ -17,15 +17,16 @@
package com.android.launcher3.taskbar
import android.content.Context
-import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.ConstantItem
import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.TestUtil
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
object TaskbarControllerTestUtil {
inline fun runOnMainSync(crossinline runTest: () -> Unit) {
- getInstrumentation().runOnMainSync { runTest() }
+ TestUtil.runOnExecutorSync(MAIN_EXECUTOR) { runTest() }
}
/** Returns a property to read/write the value of a [ConstantItem]. */
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
index 36e8a82..13880f1 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
@@ -85,7 +85,8 @@
@get:Rule(order = 4) val animatorTestRule = AnimatorTestRule(this)
- @get:Rule(order = 5) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+ @get:Rule(order = 5)
+ val taskbarUnitTestRule = TaskbarUnitTestRule(this, context, this::onControllersInitialized)
@InjectController lateinit var taskbarViewController: TaskbarViewController
@InjectController lateinit var recentAppsController: TaskbarRecentAppsController
@@ -94,18 +95,29 @@
private var desktopTaskListener: IDesktopTaskListener? = null
- @Before
- fun ensureRunningAppsShowing() {
+ private var currentControllerInitCallback: () -> Unit = {}
+ set(value) {
+ runOnMainSync { value.invoke() }
+ field = value
+ }
+
+ private fun onControllersInitialized() {
runOnMainSync {
if (!recentAppsController.canShowRunningApps) {
recentAppsController.onDestroy()
recentAppsController.canShowRunningApps = true
recentAppsController.init(taskbarUnitTestRule.activityContext.controllers)
}
- recentsModel.resolvePendingTaskRequests()
+
+ currentControllerInitCallback.invoke()
}
}
+ @Before
+ fun ensureRunningAppsShowing() {
+ runOnMainSync { recentsModel.resolvePendingTaskRequests() }
+ }
+
@Test
@TaskbarMode(PINNED)
fun testTaskbarWithMaxNumIcons_pinned() {
@@ -196,7 +208,7 @@
var initialMaxNumIconViews = maxNumberOfTaskbarIcons
assertThat(initialMaxNumIconViews).isGreaterThan(0)
- runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+ currentControllerInitCallback = { bubbleBarViewController.setHiddenForBubbles(false) }
val maxNumIconViews = addRunningAppsAndVerifyOverflowState(2)
assertThat(maxNumIconViews).isLessThan(initialMaxNumIconViews)
@@ -210,7 +222,7 @@
var initialMaxNumIconViews = maxNumberOfTaskbarIcons
assertThat(initialMaxNumIconViews).isGreaterThan(0)
- runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+ currentControllerInitCallback = { bubbleBarViewController.setHiddenForBubbles(false) }
val maxNumIconViews = addRunningAppsAndVerifyOverflowState(2)
assertThat(maxNumIconViews).isLessThan(initialMaxNumIconViews)
@@ -228,7 +240,7 @@
fun testBubbleBarReducesTaskbarMaxNumIcons_transientBubbleInitiallyStashed() {
var initialMaxNumIconViews = maxNumberOfTaskbarIcons
assertThat(initialMaxNumIconViews).isGreaterThan(0)
- runOnMainSync {
+ currentControllerInitCallback = {
bubbleStashController.stashBubbleBarImmediate()
bubbleBarViewController.setHiddenForBubbles(false)
}
@@ -247,7 +259,7 @@
@Test
@TaskbarMode(TRANSIENT)
fun testStashingBubbleBarMaintainsMaxNumIcons_transient() {
- runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+ currentControllerInitCallback = { bubbleBarViewController.setHiddenForBubbles(false) }
val initialNumIcons = currentNumberOfTaskbarIcons
val maxNumIconViews = addRunningAppsAndVerifyOverflowState(2)
@@ -261,15 +273,13 @@
@Test
@TaskbarMode(PINNED)
fun testHidingBubbleBarIncreasesMaxNumIcons_pinned() {
- runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+ currentControllerInitCallback = { bubbleBarViewController.setHiddenForBubbles(false) }
val initialNumIcons = currentNumberOfTaskbarIcons
val initialMaxNumIconViews = addRunningAppsAndVerifyOverflowState(5)
- runOnMainSync {
- bubbleBarViewController.setHiddenForBubbles(true)
- animatorTestRule.advanceTimeBy(150)
- }
+ currentControllerInitCallback = { bubbleBarViewController.setHiddenForBubbles(true) }
+ runOnMainSync { animatorTestRule.advanceTimeBy(150) }
val maxNumIconViews = maxNumberOfTaskbarIcons
assertThat(maxNumIconViews).isGreaterThan(initialMaxNumIconViews)
@@ -282,15 +292,13 @@
@Test
@TaskbarMode(TRANSIENT)
fun testHidingBubbleBarIncreasesMaxNumIcons_transient() {
- runOnMainSync { bubbleBarViewController.setHiddenForBubbles(false) }
+ currentControllerInitCallback = { bubbleBarViewController.setHiddenForBubbles(false) }
val initialNumIcons = currentNumberOfTaskbarIcons
val initialMaxNumIconViews = addRunningAppsAndVerifyOverflowState(5)
- runOnMainSync {
- bubbleBarViewController.setHiddenForBubbles(true)
- animatorTestRule.advanceTimeBy(150)
- }
+ currentControllerInitCallback = { bubbleBarViewController.setHiddenForBubbles(true) }
+ runOnMainSync { animatorTestRule.advanceTimeBy(150) }
val maxNumIconViews = maxNumberOfTaskbarIcons
assertThat(maxNumIconViews).isGreaterThan(initialMaxNumIconViews)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
index 07b32af..e150568 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
@@ -24,7 +24,6 @@
import android.provider.Settings.Secure.getUriFor
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.LauncherAppState
-import com.android.launcher3.statehandlers.DesktopVisibilityController
import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.taskbar.TaskbarControllers
import com.android.launcher3.taskbar.TaskbarManager
@@ -72,6 +71,7 @@
class TaskbarUnitTestRule(
private val testInstance: Any,
private val context: TaskbarWindowSandboxContext,
+ private val controllerInjectionCallback: () -> Unit = {},
) : TestRule {
private val instrumentation = InstrumentationRegistry.getInstrumentation()
@@ -110,11 +110,13 @@
PendingIntent(IIntentSender.Default())
},
object : TaskbarNavButtonCallbacks {},
- DesktopVisibilityController(context),
) {
override fun recreateTaskbar() {
super.recreateTaskbar()
- if (currentActivityContext != null) injectControllers()
+ if (currentActivityContext != null) {
+ injectControllers()
+ controllerInjectionCallback.invoke()
+ }
}
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/ContextualSearchInvokerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/ContextualSearchInvokerTest.java
index 88774be..61971b1 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/ContextualSearchInvokerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/ContextualSearchInvokerTest.java
@@ -52,6 +52,7 @@
import com.android.quickstep.DeviceConfigWrapper;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TopTaskTracker;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
@@ -82,6 +83,7 @@
private @Mock BaseContainerInterface mMockContainerInterface;
private @Mock RecentsViewContainer mMockRecentsViewContainer;
private @Mock RecentsView mMockRecentsView;
+ private @Mock RecentsPagedOrientationHandler mMockOrientationHandler;
private ContextualSearchInvoker mContextualSearchInvoker;
@Before
@@ -190,6 +192,15 @@
}
@Test
+ public void runContextualSearchInvocationChecksAndLogFailures_isFakeLandscape() {
+ when(mMockRecentsView.getPagedOrientationHandler()).thenReturn(mMockOrientationHandler);
+ when(mMockOrientationHandler.isLayoutNaturalToLauncher()).thenReturn(false);
+ assertFalse("Expect invocation checks to fail in fake landscape.",
+ mContextualSearchInvoker.runContextualSearchInvocationChecksAndLogFailures());
+ verifyNoMoreInteractions(mMockStatsLogManager);
+ }
+
+ @Test
public void invokeContextualSearchUncheckedWithHaptic_cssIsAvailable_commitHapticEnabled() {
try (AutoCloseable flag = overrideSearchHapticCommitFlag(true)) {
assertTrue("Expected invocation unchecked to succeed",
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 83c8d6c..adf4597 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -29,6 +29,7 @@
android:importantForAccessibility="no">
<com.android.launcher3.views.AccessibilityActionsView
+ android:id="@+id/accessibility_action_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/home_screen"
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4097dca..f68c8e0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -630,6 +630,10 @@
return new ColdRebootStartupLatencyLogger();
}
+ @NonNull View getAccessibilityActionView() {
+ return findViewById(R.id.accessibility_action_view);
+ }
+
/**
* Provide {@link OnBackAnimationCallback} in below order:
* <ol>
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a064c88..bc751d9 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -70,6 +70,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.core.view.ViewCompat;
import com.android.app.animation.Interpolators;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
@@ -303,6 +304,8 @@
private final StatsLogManager mStatsLogManager;
private final MSDLPlayerWrapper mMSDLPlayerWrapper;
+ @Nullable
+ private DragController.DragListener mAccessibilityDragListener;
/**
* Used to inflate the Workspace from XML.
@@ -512,6 +515,9 @@
}
}
+ if (mAccessibilityDragListener != null) {
+ mAccessibilityDragListener.onDragStart(dragObject, options);
+ }
if (!mLauncher.isInState(EDIT_MODE)) {
mLauncher.getStateManager().goToState(SPRING_LOADED);
}
@@ -548,6 +554,9 @@
}
});
+ if (mAccessibilityDragListener != null) {
+ mAccessibilityDragListener.onDragEnd();
+ }
mDragInfo = null;
mDragSourceInternal = null;
}
@@ -1656,7 +1665,7 @@
child.setVisibility(INVISIBLE);
if (options.isAccessibleDrag) {
- mDragController.addDragListener(
+ mAccessibilityDragListener =
new AccessibleDragListenerAdapter(this, WorkspaceAccessibilityHelper::new) {
@Override
protected void enableAccessibleDrag(boolean enable,
@@ -1669,7 +1678,7 @@
IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
}
- });
+ };
}
beginDragShared(child, this, options);
@@ -3519,8 +3528,15 @@
@Override
protected boolean canAnnouncePageDescription() {
- // b/383247157: Disable disruptive home screen page announcement
- return false;
+ return Float.compare(mOverlayProgress, 0f) == 0;
+ }
+
+ @Override
+ protected void announcePageForAccessibility() {
+ // Talkback focuses on AccessibilityActionView by default, so we need to modify the state
+ // description there in order for the change in page scroll to be announced.
+ ViewCompat.setStateDescription(mLauncher.getAccessibilityActionView(),
+ getCurrentPageDescription());
}
@Override
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 26912eb..d8a2a3d 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -56,6 +56,7 @@
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
+import com.android.launcher3.util.window.WindowManagerProxy.DesktopVisibilityListener;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -70,7 +71,8 @@
* Utility class to cache properties of default display to avoid a system RPC on every call.
*/
@SuppressLint("NewApi")
-public class DisplayController implements ComponentCallbacks, SafeCloseable {
+public class DisplayController implements ComponentCallbacks, SafeCloseable,
+ DesktopVisibilityListener {
private static final String TAG = "DisplayController";
private static final boolean DEBUG = false;
@@ -99,7 +101,6 @@
private static final String TARGET_OVERLAY_PACKAGE = "android";
private final Context mContext;
- private final DisplayManager mDM;
// Null for SDK < S
private final Context mWindowContext;
@@ -121,13 +122,12 @@
@VisibleForTesting
protected DisplayController(Context context) {
mContext = context;
- mDM = context.getSystemService(DisplayManager.class);
-
if (enableTaskbarPinning()) {
attachTaskbarPinningSharedPreferenceChangeListener(mContext);
}
- Display display = mDM.getDisplay(DEFAULT_DISPLAY);
+ Display display = context.getSystemService(DisplayManager.class)
+ .getDisplay(DEFAULT_DISPLAY);
mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null);
mWindowContext.registerComponentCallbacks(this);
@@ -137,6 +137,7 @@
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(context);
mInfo = new Info(mWindowContext, wmProxy,
wmProxy.estimateInternalDisplayBounds(mWindowContext));
+ wmProxy.registerDesktopVisibilityListener(this);
FileLog.i(TAG, "(CTOR) perDisplayBounds: " + mInfo.mPerDisplayBounds);
}
@@ -215,12 +216,14 @@
LauncherPrefs.get(mContext).removeListener(
mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING_IN_DESKTOP_MODE);
}
- if (mWindowContext != null) {
- mWindowContext.unregisterComponentCallbacks(this);
- } else {
- // TODO: unregister broadcast receiver
- }
+ mWindowContext.unregisterComponentCallbacks(this);
mReceiver.unregisterReceiverSafely(mContext);
+ WindowManagerProxy.INSTANCE.get(mContext).unregisterDesktopVisibilityListener(this);
+ }
+
+ @Override
+ public void onDesktopVisibilityChanged(boolean visible) {
+ notifyConfigChange();
}
/**
diff --git a/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt b/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
index 8877535..1f01b07 100644
--- a/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
+++ b/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
@@ -33,7 +33,7 @@
override val default: CoroutineDispatcher = Dispatchers.Default
override val background: CoroutineDispatcher = bgDispatcher
- override val main: CoroutineDispatcher = Dispatchers.Main
+ override val main: CoroutineDispatcher = Dispatchers.Main.immediate
override val unconfined: CoroutineDispatcher = Dispatchers.Unconfined
}
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 1d9751e..e568eed 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -485,4 +485,21 @@
return new Rect(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
cutout.getSafeInsetRight(), cutout.getSafeInsetBottom());
}
+
+ /** Registers a listener for Taskbar changes in Desktop Mode. */
+ public void registerDesktopVisibilityListener(DesktopVisibilityListener listener) { }
+
+ /** Removes a previously registered listener for Taskbar changes in Desktop Mode. */
+ public void unregisterDesktopVisibilityListener(DesktopVisibilityListener listener) { }
+
+ /** A listener for when the user enters/exits Desktop Mode. */
+ public interface DesktopVisibilityListener {
+ /**
+ * Callback for when the user enters or exits Desktop Mode
+ *
+ * @param visible whether Desktop Mode is now visible
+ */
+ void onDesktopVisibilityChanged(boolean visible);
+ }
+
}
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
index 237f2a9..cb04e13 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
@@ -114,6 +114,7 @@
* Similar to {@link TaplWorkspaceTest#testWorkspace} but here we also make sure we can delete
* the pages.
*/
+ @ScreenRecord // b/381918059
@Test
public void testAddAndDeletePageAndFling() {
Workspace workspace = mLauncher.getWorkspace();