Files
Lawnchair/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
T
Alex Chau 13b7ceeff0 Clean-up unnecessary desktop windowing flag usage
- mDesktopVisibilityController will now be null if desktop windowing flag is disabled
- As a result, all code that uses mDesktopVisibilityController no longer need to check desktop windowing flag
- DesktopTaskView/DesktopTask only populates when flag is enabled, so we don't need to check flag if we already check DesktopTaskView/DesktopTask
- Removed the flag check in SplitToWorkspaceController, as we shouldn't enable split from workspace base on desktop windowing, contextual split already have its own flag
- Also avoid creating GroupTask or DesktopTask for freeform tasks when flag is off, to avoid a crash in RecentsView

Bug: 332655617
Test: manual with desktop windowing flag on/off
Flag: ACONFIG com.android.window.flags.enable_desktop_windowing_mode DEVELOPMENT
Change-Id: I0e45f73ad2b0d99dfb4ec3215f973679ca93957c
2024-04-04 12:21:43 +01:00

327 lines
12 KiB
Java

/*
* 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 com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.os.Debug;
import android.os.SystemProperties;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.GestureState;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.DesktopAppSelectView;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
/**
* 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 static final boolean IS_STASHING_ENABLED = SystemProperties.getBoolean(
"persist.wm.debug.desktop_stashing", false);
private final Launcher mLauncher;
private int mVisibleFreeformTasksCount;
private boolean mInOverviewState;
private boolean mBackgroundStateEnabled;
private boolean mGestureInProgress;
@Nullable
private IDesktopTaskListener mDesktopTaskListener;
private DesktopAppSelectView mSelectAppToast;
public DesktopVisibilityController(Launcher launcher) {
mLauncher = launcher;
}
/**
* Register a listener with System UI to receive updates about desktop tasks state
*/
public void registerSystemUiListener() {
mDesktopTaskListener = new IDesktopTaskListener.Stub() {
@Override
public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) {
MAIN_EXECUTOR.execute(() -> {
if (displayId == mLauncher.getDisplayId()) {
if (DEBUG) {
Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount);
}
setVisibleFreeformTasksCount(visibleTasksCount);
}
});
}
@Override
public void onStashedChanged(int displayId, boolean stashed) {
if (!IS_STASHING_ENABLED) {
return;
}
MAIN_EXECUTOR.execute(() -> {
if (displayId == mLauncher.getDisplayId()) {
if (DEBUG) {
Log.d(TAG, "desktop stashed changed value=" + stashed);
}
if (stashed) {
showSelectAppToast();
} else {
hideSelectAppToast();
}
}
});
}
};
SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(mDesktopTaskListener);
}
/**
* Clear listener from System UI that was set with {@link #registerSystemUiListener()}
*/
public void unregisterSystemUiListener() {
SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(null);
}
/**
* Whether freeform windows are visible in desktop mode.
*/
public boolean areFreeformTasksVisible() {
boolean freeformTasksVisible = mVisibleFreeformTasksCount > 0;
if (DEBUG) {
Log.d(TAG, "areFreeformTasksVisible: freeformVisible=" + freeformTasksVisible
+ " overview=" + mInOverviewState);
}
return freeformTasksVisible && !mInOverviewState;
}
/**
* Number of visible freeform windows in desktop mode.
*/
public int getVisibleFreeformTasksCount() {
return mVisibleFreeformTasksCount;
}
/**
* Sets the number of freeform windows that are visible and updates launcher visibility based on
* it.
*/
public void setVisibleFreeformTasksCount(int visibleTasksCount) {
if (DEBUG) {
Log.d(TAG, "setVisibleFreeformTasksCount: visibleTasksCount=" + visibleTasksCount
+ " currentValue=" + mVisibleFreeformTasksCount);
}
if (visibleTasksCount != mVisibleFreeformTasksCount) {
final boolean wasVisible = mVisibleFreeformTasksCount > 0;
final boolean isVisible = visibleTasksCount > 0;
mVisibleFreeformTasksCount = visibleTasksCount;
if (wasVisible != isVisible) {
if (mVisibleFreeformTasksCount > 0) {
setLauncherViewsVisibility(View.INVISIBLE);
if (!mInOverviewState) {
// When freeform is visible & we're not in overview, we want launcher to
// appear paused, this ensures that taskbar displays.
markLauncherPaused();
}
} else {
setLauncherViewsVisibility(View.VISIBLE);
// If freeform isn't visible ensure that launcher appears resumed to behave
// normally.
markLauncherResumed();
}
}
}
}
/**
* Process launcher state change and update launcher view visibility based on desktop state
*/
public void onLauncherStateChanged(LauncherState state) {
if (DEBUG) {
Log.d(TAG, "onLauncherStateChanged: newState=" + state);
}
setBackgroundStateEnabled(state == BACKGROUND_APP);
// Desktop visibility tracks overview and background state separately
setOverviewStateEnabled(state != BACKGROUND_APP && state.overviewUi);
}
private void setOverviewStateEnabled(boolean overviewStateEnabled) {
if (DEBUG) {
Log.d(TAG, "setOverviewStateEnabled: enabled=" + overviewStateEnabled
+ " currentValue=" + mInOverviewState);
}
if (overviewStateEnabled != mInOverviewState) {
mInOverviewState = overviewStateEnabled;
if (mInOverviewState) {
setLauncherViewsVisibility(View.VISIBLE);
markLauncherResumed();
} else if (areFreeformTasksVisible() && !mGestureInProgress) {
// Switching out of overview state and gesture finished.
// If freeform tasks are still visible, hide launcher again.
setLauncherViewsVisibility(View.INVISIBLE);
markLauncherPaused();
}
}
}
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 (areFreeformTasksVisible() && !mGestureInProgress) {
// Switching out of background state. If freeform tasks are visible, pause launcher.
setLauncherViewsVisibility(View.INVISIBLE);
markLauncherPaused();
}
}
}
/**
* Whether recents gesture is currently in progress.
*/
public boolean isRecentsGestureInProgress() {
return mGestureInProgress;
}
/**
* Notify controller that recents gesture has started.
*/
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}
*/
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();
}
}
private void setRecentsGestureInProgress(boolean gestureInProgress) {
if (gestureInProgress != mGestureInProgress) {
mGestureInProgress = gestureInProgress;
}
}
/**
* Handle launcher moving to home due to home gesture or home button press.
*/
public void onHomeActionTriggered() {
if (IS_STASHING_ENABLED && areFreeformTasksVisible()) {
SystemUiProxy.INSTANCE.get(mLauncher).stashDesktopApps(mLauncher.getDisplayId());
}
}
private void setLauncherViewsVisibility(int visibility) {
if (DEBUG) {
Log.d(TAG, "setLauncherViewsVisibility: visibility=" + visibility + " "
+ Debug.getCaller());
}
View workspaceView = mLauncher.getWorkspace();
if (workspaceView != null) {
workspaceView.setVisibility(visibility);
}
View dragLayer = mLauncher.getDragLayer();
if (dragLayer != null) {
dragLayer.setVisibility(visibility);
}
if (mLauncher instanceof QuickstepLauncher ql && ql.getTaskbarUIController() != null
&& mVisibleFreeformTasksCount != 0) {
ql.getTaskbarUIController().onLauncherVisibilityChanged(visibility == VISIBLE);
}
}
private void markLauncherPaused() {
if (DEBUG) {
Log.d(TAG, "markLauncherPaused " + Debug.getCaller());
}
StatefulActivity<LauncherState> activity =
QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
if (activity != null) {
activity.setPaused();
}
}
private void markLauncherResumed() {
if (DEBUG) {
Log.d(TAG, "markLauncherResumed " + Debug.getCaller());
}
StatefulActivity<LauncherState> activity =
QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
// 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();
}
}
private void showSelectAppToast() {
if (mSelectAppToast != null) {
return;
}
if (DEBUG) {
Log.d(TAG, "show toast to select desktop apps");
}
Runnable onCloseCallback = () -> {
SystemUiProxy.INSTANCE.get(mLauncher).hideStashedDesktopApps(mLauncher.getDisplayId());
};
mSelectAppToast = DesktopAppSelectView.show(mLauncher, onCloseCallback);
}
private void hideSelectAppToast() {
if (mSelectAppToast == null) {
return;
}
if (DEBUG) {
Log.d(TAG, "hide toast to select desktop apps");
}
mSelectAppToast.hide();
mSelectAppToast = null;
}
}