Merge "Allows Launcher to recover gracefully into OverviewSplitSelect state" into tm-qpr-dev
This commit is contained in:
@@ -20,6 +20,8 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
|
||||
import static com.android.launcher3.LauncherState.FLAG_HIDE_BACK_BUTTON;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.NO_OFFSET;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE;
|
||||
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
|
||||
@@ -70,6 +72,7 @@ import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.DisplayController.NavigationMode;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.ObjectWrapper;
|
||||
import com.android.launcher3.util.PendingSplitSelectInfo;
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
@@ -91,10 +94,10 @@ import com.android.systemui.shared.system.ActivityOptionsCompat;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import com.android.systemui.unfold.UnfoldTransitionFactory;
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
|
||||
import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig;
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
|
||||
import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider;
|
||||
import com.android.systemui.unfold.system.DeviceStateManagerFoldProvider;
|
||||
import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -130,9 +133,19 @@ public abstract class BaseQuickstepLauncher extends Launcher {
|
||||
private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider;
|
||||
private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController;
|
||||
|
||||
/**
|
||||
* If Launcher restarted while in the middle of an Overview split select, it needs this data to
|
||||
* recover. In all other cases this will remain null.
|
||||
*/
|
||||
private PendingSplitSelectInfo mPendingSplitSelectInfo = null;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (savedInstanceState != null) {
|
||||
mPendingSplitSelectInfo = ObjectWrapper.unwrap(
|
||||
savedInstanceState.getIBinder(PENDING_SPLIT_SELECT_INFO));
|
||||
}
|
||||
addMultiWindowModeChangedListener(mDepthController);
|
||||
initUnfoldTransitionProgressProvider();
|
||||
}
|
||||
@@ -643,4 +656,53 @@ public abstract class BaseQuickstepLauncher extends Launcher {
|
||||
mDepthController.dump(prefix, writer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
// If Launcher shuts downs during split select, we save some extra data in the recovery
|
||||
// bundle to allow graceful recovery. The normal LauncherState restore mechanism doesn't
|
||||
// work in this case because restoring straight to OverviewSplitSelect without staging data,
|
||||
// or before the tasks themselves have loaded into Overview, causes a crash. So we tell
|
||||
// Launcher to first restore into Overview state, wait for the relevant tasks and icons to
|
||||
// load in, and then proceed to OverviewSplitSelect.
|
||||
if (isInState(OVERVIEW_SPLIT_SELECT)) {
|
||||
SplitSelectStateController splitSelectStateController =
|
||||
((RecentsView) getOverviewPanel()).getSplitPlaceholder();
|
||||
// Launcher will restart in Overview and then transition to OverviewSplitSelect.
|
||||
outState.putIBinder(PENDING_SPLIT_SELECT_INFO, ObjectWrapper.wrap(
|
||||
new PendingSplitSelectInfo(
|
||||
splitSelectStateController.getInitialTaskId(),
|
||||
splitSelectStateController.getActiveSplitStagePosition()
|
||||
)
|
||||
));
|
||||
outState.putInt(RUNTIME_STATE, OVERVIEW.ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When Launcher restarts, it sometimes needs to recover to a split selection state.
|
||||
* This function checks if such a recovery is needed.
|
||||
* @return a boolean representing whether the launcher is waiting to recover to
|
||||
* OverviewSplitSelect state.
|
||||
*/
|
||||
public boolean hasPendingSplitSelectInfo() {
|
||||
return mPendingSplitSelectInfo != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link #hasPendingSplitSelectInfo()}
|
||||
*/
|
||||
public @Nullable PendingSplitSelectInfo getPendingSplitSelectInfo() {
|
||||
return mPendingSplitSelectInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the launcher has successfully recovered to OverviewSplitSelect state, this function
|
||||
* deletes the recovery data, returning it to a null state.
|
||||
*/
|
||||
public void finishSplitSelectRecovery() {
|
||||
mPendingSplitSelectInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.android.launcher3.icons.IconProvider.IconChangeListener;
|
||||
import com.android.launcher3.util.Executors.SimpleThreadFactory;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.quickstep.util.GroupTask;
|
||||
import com.android.quickstep.util.TaskVisualsChangeListener;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
@@ -54,7 +55,8 @@ import java.util.function.Consumer;
|
||||
* Singleton class to load and manage recents model.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public class RecentsModel implements IconChangeListener, TaskStackChangeListener {
|
||||
public class RecentsModel implements IconChangeListener, TaskStackChangeListener,
|
||||
TaskVisualsChangeListener {
|
||||
|
||||
// We do not need any synchronization for this variable as its only written on UI thread.
|
||||
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
|
||||
@@ -77,6 +79,7 @@ public class RecentsModel implements IconChangeListener, TaskStackChangeListener
|
||||
|
||||
IconProvider iconProvider = new IconProvider(context);
|
||||
mIconCache = new TaskIconCache(context, RECENTS_MODEL_EXECUTOR, iconProvider);
|
||||
mIconCache.registerTaskVisualsChangeListener(this);
|
||||
mThumbnailCache = new TaskThumbnailCache(context, RECENTS_MODEL_EXECUTOR);
|
||||
|
||||
TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
|
||||
@@ -203,6 +206,13 @@ public class RecentsModel implements IconChangeListener, TaskStackChangeListener
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskIconChanged(int taskId) {
|
||||
for (TaskVisualsChangeListener listener : mThumbnailChangeListeners) {
|
||||
listener.onTaskIconChanged(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSystemIconStateChanged(String iconState) {
|
||||
mIconCache.clearCache();
|
||||
@@ -226,20 +236,4 @@ public class RecentsModel implements IconChangeListener, TaskStackChangeListener
|
||||
writer.println(prefix + "RecentsModel:");
|
||||
mTaskList.dump(" ", writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for receiving various task properties changes
|
||||
*/
|
||||
public interface TaskVisualsChangeListener {
|
||||
|
||||
/**
|
||||
* Called whn the task thumbnail changes
|
||||
*/
|
||||
Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData);
|
||||
|
||||
/**
|
||||
* Called when the icon for a task changes
|
||||
*/
|
||||
void onTaskIconChanged(String pkg, UserHandle user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.quickstep;
|
||||
import static com.android.launcher3.uioverrides.QuickstepLauncher.GO_LOW_RAM_RECENTS_ENABLED;
|
||||
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.TaskDescription;
|
||||
import android.content.Context;
|
||||
@@ -46,6 +47,7 @@ import com.android.launcher3.util.DisplayController.Info;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.quickstep.util.CancellableTask;
|
||||
import com.android.quickstep.util.TaskKeyLruCache;
|
||||
import com.android.quickstep.util.TaskVisualsChangeListener;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.Task.TaskKey;
|
||||
import com.android.systemui.shared.system.PackageManagerWrapper;
|
||||
@@ -70,6 +72,9 @@ public class TaskIconCache implements DisplayInfoChangeListener {
|
||||
|
||||
private BaseIconFactory mIconFactory;
|
||||
|
||||
@Nullable
|
||||
public TaskVisualsChangeListener mTaskVisualsChangeListener = null;
|
||||
|
||||
public TaskIconCache(Context context, Executor bgExecutor, IconProvider iconProvider) {
|
||||
mContext = context;
|
||||
mBgExecutor = bgExecutor;
|
||||
@@ -116,6 +121,7 @@ public class TaskIconCache implements DisplayInfoChangeListener {
|
||||
task.icon = result.icon;
|
||||
task.titleDescription = result.contentDescription;
|
||||
callback.accept(task);
|
||||
dispatchIconUpdate(task.key.id);
|
||||
}
|
||||
};
|
||||
mBgExecutor.execute(request);
|
||||
@@ -272,4 +278,18 @@ public class TaskIconCache implements DisplayInfoChangeListener {
|
||||
public Drawable icon;
|
||||
public String contentDescription = "";
|
||||
}
|
||||
|
||||
void registerTaskVisualsChangeListener(TaskVisualsChangeListener newListener) {
|
||||
mTaskVisualsChangeListener = newListener;
|
||||
}
|
||||
|
||||
void removeTaskVisualsChangeListener() {
|
||||
mTaskVisualsChangeListener = null;
|
||||
}
|
||||
|
||||
void dispatchIconUpdate(int taskId) {
|
||||
if (mTaskVisualsChangeListener != null) {
|
||||
mTaskVisualsChangeListener.onTaskIconChanged(taskId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,4 +330,8 @@ public class SplitSelectStateController {
|
||||
private boolean isInitialTaskIntentSet() {
|
||||
return (mInitialTaskId != INVALID_TASK_ID || mInitialTaskIntent != null);
|
||||
}
|
||||
|
||||
public int getInitialTaskId() {
|
||||
return mInitialTaskId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.quickstep.util;
|
||||
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
/**
|
||||
* Listener for receiving various task properties changes
|
||||
*/
|
||||
public interface TaskVisualsChangeListener {
|
||||
|
||||
/**
|
||||
* Called when the task thumbnail changes
|
||||
*/
|
||||
default Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the icon for a task changes
|
||||
*/
|
||||
default void onTaskIconChanged(String pkg, UserHandle user) {}
|
||||
|
||||
/**
|
||||
* Called when the icon for a task changes
|
||||
*/
|
||||
default void onTaskIconChanged(int taskId) {}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.popup.QuickstepSystemShortcut;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
import com.android.launcher3.util.PendingSplitSelectInfo;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions;
|
||||
import com.android.quickstep.LauncherActivityInterface;
|
||||
import com.android.quickstep.util.SplitSelectStateController;
|
||||
@@ -88,6 +89,21 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher, Laun
|
||||
super.onTaskLaunchAnimationEnd(success);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskIconChanged(int taskId) {
|
||||
// If Launcher needs to return to split select state, do it now, after the icon has updated.
|
||||
if (mActivity.hasPendingSplitSelectInfo()) {
|
||||
PendingSplitSelectInfo recoveryData = mActivity.getPendingSplitSelectInfo();
|
||||
if (recoveryData.getStagedTaskId() == taskId) {
|
||||
initiateSplitSelect(
|
||||
getTaskViewByTaskId(recoveryData.getStagedTaskId()),
|
||||
recoveryData.getStagePosition()
|
||||
);
|
||||
mActivity.finishSplitSelectRecovery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
|
||||
@@ -152,7 +152,6 @@ import com.android.quickstep.GestureState;
|
||||
import com.android.quickstep.RecentsAnimationController;
|
||||
import com.android.quickstep.RecentsAnimationTargets;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
|
||||
import com.android.quickstep.RemoteAnimationTargets;
|
||||
import com.android.quickstep.RemoteTargetGluer;
|
||||
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
|
||||
@@ -170,6 +169,7 @@ import com.android.quickstep.util.SplitScreenBounds;
|
||||
import com.android.quickstep.util.SplitSelectStateController;
|
||||
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||
import com.android.quickstep.util.TaskViewSimulator;
|
||||
import com.android.quickstep.util.TaskVisualsChangeListener;
|
||||
import com.android.quickstep.util.TransformParams;
|
||||
import com.android.quickstep.util.VibratorWrapper;
|
||||
import com.android.systemui.plugins.ResourceProvider;
|
||||
|
||||
@@ -87,7 +87,6 @@ import com.android.launcher3.util.ViewPool.Reusable;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RemoteAnimationTargets;
|
||||
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TaskIconCache;
|
||||
import com.android.quickstep.TaskOverlayFactory;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
|
||||
@@ -33,7 +33,6 @@ import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
|
||||
import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
|
||||
import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
@@ -266,7 +265,7 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
protected static final int REQUEST_LAST = 100;
|
||||
|
||||
// Type: int
|
||||
private static final String RUNTIME_STATE = "launcher.state";
|
||||
protected static final String RUNTIME_STATE = "launcher.state";
|
||||
// Type: PendingRequestArgs
|
||||
private static final String RUNTIME_STATE_PENDING_REQUEST_ARGS = "launcher.request_args";
|
||||
// Type: int
|
||||
@@ -278,6 +277,9 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
// Type int[]
|
||||
private static final String RUNTIME_STATE_CURRENT_SCREEN_IDS = "launcher.current_screen_ids";
|
||||
|
||||
// Type PendingSplitSelectInfo<Parcelable>
|
||||
protected static final String PENDING_SPLIT_SELECT_INFO = "launcher.pending_split_select_info";
|
||||
|
||||
public static final String ON_CREATE_EVT = "Launcher.onCreate";
|
||||
public static final String ON_START_EVT = "Launcher.onStart";
|
||||
public static final String ON_RESUME_EVT = "Launcher.onResume";
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
|
||||
|
||||
/**
|
||||
* Utility class to store information regarding a split select request. This includes the taskId of
|
||||
* the originating task, plus the stage position.
|
||||
* This information is intended to be saved across launcher instances, e.g. when Launcher needs to
|
||||
* recover straight into a split select state.
|
||||
*/
|
||||
public class PendingSplitSelectInfo {
|
||||
|
||||
private final int mStagedTaskId;
|
||||
private final int mStagePosition;
|
||||
|
||||
public PendingSplitSelectInfo(int stagedTaskId, int stagePosition) {
|
||||
this.mStagedTaskId = stagedTaskId;
|
||||
this.mStagePosition = stagePosition;
|
||||
}
|
||||
|
||||
public int getStagedTaskId() {
|
||||
return mStagedTaskId;
|
||||
}
|
||||
|
||||
public @StagePosition int getStagePosition() {
|
||||
return mStagePosition;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user