From d6801af69aaaf67f74a8e974736bd4dd33778d6d Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 18 Aug 2022 09:51:07 -0700 Subject: [PATCH] Inlining BaseQuickstepLauncher to QuickstepLauncher Bug: 243022799 Test: Presubmit Change-Id: I3706fc1f10d88ea73bd873c7e94c3e78795791eb --- .../DebugQuickstepTestInformationHandler.java | 6 +- .../launcher3/BaseQuickstepLauncher.java | 708 ------------------ .../launcher3/LauncherInitListener.java | 3 +- .../launcher3/QuickstepTransitionManager.java | 3 +- .../popup/QuickstepSystemShortcut.java | 8 +- .../statehandlers/BackButtonAlphaHandler.java | 8 +- .../taskbar/DesktopTaskbarUIController.java | 6 +- .../taskbar/LauncherTaskbarUIController.java | 6 +- .../TaskbarLauncherStateController.java | 6 +- .../launcher3/taskbar/TaskbarManager.java | 12 +- .../BaseRecentsViewStateController.java | 5 +- .../uioverrides/QuickstepLauncher.java | 636 +++++++++++++++- .../RecentsViewStateController.java | 3 +- ...ButtonNavbarToOverviewTouchController.java | 6 +- .../NoButtonQuickSwitchTouchController.java | 6 +- .../quickstep/LauncherActivityInterface.java | 18 +- .../LauncherBackAnimationController.java | 6 +- .../quickstep/LauncherSwipeHandlerV2.java | 4 +- .../util/StaggeredWorkspaceAnim.java | 6 +- .../quickstep/util/WorkspaceRevealAnim.java | 6 +- .../quickstep/views/LauncherRecentsView.java | 4 +- 21 files changed, 694 insertions(+), 772 deletions(-) delete mode 100644 quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java diff --git a/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java b/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java index 84b907f190..2ffb28e8fb 100644 --- a/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java +++ b/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java @@ -23,12 +23,12 @@ import android.os.Bundle; import androidx.annotation.Nullable; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.testing.DebugTestInformationHandler; import com.android.launcher3.testing.shared.TestProtocol; +import com.android.launcher3.uioverrides.QuickstepLauncher; import java.util.concurrent.ExecutionException; @@ -64,7 +64,7 @@ public abstract class DebugQuickstepTestInformationHandler extends QuickstepTest runOnUIThread(l -> { enableManualTaskbarStashing(l, true); - BaseQuickstepLauncher quickstepLauncher = (BaseQuickstepLauncher) l; + QuickstepLauncher quickstepLauncher = (QuickstepLauncher) l; LauncherTaskbarUIController taskbarUIController = quickstepLauncher.getTaskbarUIController(); @@ -90,7 +90,7 @@ public abstract class DebugQuickstepTestInformationHandler extends QuickstepTest } private void enableManualTaskbarStashing(Launcher launcher, boolean enable) { - BaseQuickstepLauncher quickstepLauncher = (BaseQuickstepLauncher) launcher; + QuickstepLauncher quickstepLauncher = (QuickstepLauncher) launcher; LauncherTaskbarUIController taskbarUIController = quickstepLauncher.getTaskbarUIController(); diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java deleted file mode 100644 index c2e8658401..0000000000 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ /dev/null @@ -1,708 +0,0 @@ -/* - * Copyright (C) 2019 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; - -import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; -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; -import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition; -import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX; -import static com.android.launcher3.taskbar.LauncherTaskbarUIController.MINUS_ONE_PAGE_PROGRESS_INDEX; -import static com.android.launcher3.taskbar.LauncherTaskbarUIController.WIDGETS_PAGE_PROGRESS_INDEX; -import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; -import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE; -import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS; -import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR; -import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; -import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; - -import android.animation.AnimatorSet; -import android.animation.ValueAnimator; -import android.app.ActivityManager; -import android.app.ActivityOptions; -import android.content.Context; -import android.content.Intent; -import android.content.IntentSender; -import android.hardware.SensorManager; -import android.hardware.devicestate.DeviceStateManager; -import android.os.Bundle; -import android.os.CancellationSignal; -import android.os.IBinder; -import android.view.Display; -import android.view.View; -import android.window.SplashScreen; - -import androidx.annotation.Nullable; - -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.dragndrop.DragOptions; -import com.android.launcher3.model.WellbeingModel; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.popup.SystemShortcut; -import com.android.launcher3.proxy.ProxyActivityStarter; -import com.android.launcher3.proxy.StartActivityParams; -import com.android.launcher3.statehandlers.BackButtonAlphaHandler; -import com.android.launcher3.statehandlers.DepthController; -import com.android.launcher3.statemanager.StateManager.StateHandler; -import com.android.launcher3.taskbar.LauncherTaskbarUIController; -import com.android.launcher3.taskbar.TaskbarManager; -import com.android.launcher3.uioverrides.RecentsViewStateController; -import com.android.launcher3.util.ActivityOptionsWrapper; -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; -import com.android.quickstep.OverviewCommandHelper; -import com.android.quickstep.RecentsModel; -import com.android.quickstep.SystemUiProxy; -import com.android.quickstep.TaskUtils; -import com.android.quickstep.TouchInteractionService.TISBinder; -import com.android.quickstep.util.LauncherUnfoldAnimationController; -import com.android.quickstep.util.ProxyScreenStatusProvider; -import com.android.quickstep.util.RemoteAnimationProvider; -import com.android.quickstep.util.RemoteFadeOutAnimationListener; -import com.android.quickstep.util.SplitSelectStateController; -import com.android.quickstep.util.TISBindHelper; -import com.android.quickstep.views.OverviewActionsView; -import com.android.quickstep.views.RecentsView; -import com.android.systemui.shared.system.ActivityManagerWrapper; -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 java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; - -/** - * Extension of Launcher activity to provide quickstep specific functionality - */ -public abstract class BaseQuickstepLauncher extends Launcher { - - private DepthController mDepthController; - private QuickstepTransitionManager mAppTransitionManager; - - /** - * Reusable command for applying the back button alpha on the background thread. - */ - public static final UiThreadHelper.AsyncCommand SET_BACK_BUTTON_ALPHA = - (context, arg1, arg2) -> SystemUiProxy.INSTANCE.get(context).setNavBarButtonAlpha( - Float.intBitsToFloat(arg1), arg2 != 0); - - private OverviewActionsView mActionsView; - - private TISBindHelper mTISBindHelper; - private @Nullable TaskbarManager mTaskbarManager; - private @Nullable OverviewCommandHelper mOverviewCommandHelper; - private @Nullable LauncherTaskbarUIController mTaskbarUIController; - - // Will be updated when dragging from taskbar. - private @Nullable DragOptions mNextWorkspaceDragOptions = null; - - 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(); - } - - @Override - protected void onResume() { - super.onResume(); - - if (mLauncherUnfoldAnimationController != null) { - mLauncherUnfoldAnimationController.onResume(); - } - } - - @Override - protected void onPause() { - if (mLauncherUnfoldAnimationController != null) { - mLauncherUnfoldAnimationController.onPause(); - } - - super.onPause(); - } - - @Override - public void onDestroy() { - mAppTransitionManager.onActivityDestroyed(); - if (mUnfoldTransitionProgressProvider != null) { - mUnfoldTransitionProgressProvider.destroy(); - } - - mTISBindHelper.onDestroy(); - if (mTaskbarManager != null) { - mTaskbarManager.clearActivity(this); - } - - if (mLauncherUnfoldAnimationController != null) { - mLauncherUnfoldAnimationController.onDestroy(); - } - - super.onDestroy(); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - if (mOverviewCommandHelper != null) { - mOverviewCommandHelper.clearPendingCommands(); - } - } - - public QuickstepTransitionManager getAppTransitionManager() { - return mAppTransitionManager; - } - - @Override - public void onEnterAnimationComplete() { - super.onEnterAnimationComplete(); - // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled - // as a part of quickstep, so that high-res thumbnails can load the next time we enter - // overview - RecentsModel.INSTANCE.get(this).getThumbnailCache() - .getHighResLoadingState().setVisible(true); - } - - @Override - protected void handleGestureContract(Intent intent) { - if (FeatureFlags.SEPARATE_RECENTS_ACTIVITY.get()) { - super.handleGestureContract(intent); - } - } - - @Override - public void onTrimMemory(int level) { - super.onTrimMemory(level); - RecentsModel.INSTANCE.get(this).onTrimMemory(level); - } - - @Override - public void onUiChangedWhileSleeping() { - // Remove the snapshot because the content view may have obvious changes. - UI_HELPER_EXECUTOR.execute( - () -> ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(this)); - } - - @Override - protected void onScreenOff() { - super.onScreenOff(); - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - RecentsView recentsView = getOverviewPanel(); - recentsView.finishRecentsAnimation(true /* toRecents */, null); - } - } - - /** - * {@code LauncherOverlayCallbacks} scroll amount. - * Indicates transition progress to -1 screen. - * @param progress From 0 to 1. - */ - @Override - public void onScrollChanged(float progress) { - super.onScrollChanged(progress); - onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX); - } - - @Override - public void onAllAppsTransition(float progress) { - super.onAllAppsTransition(progress); - onTaskbarInAppDisplayProgressUpdate(progress, ALL_APPS_PAGE_PROGRESS_INDEX); - } - - @Override - public void onWidgetsTransition(float progress) { - super.onWidgetsTransition(progress); - onTaskbarInAppDisplayProgressUpdate(progress, WIDGETS_PAGE_PROGRESS_INDEX); - } - - private void onTaskbarInAppDisplayProgressUpdate(float progress, int flag) { - if (mTaskbarManager == null - || mTaskbarManager.getCurrentActivityContext() == null - || mTaskbarUIController == null) { - return; - } - mTaskbarUIController.onTaskbarInAppDisplayProgressUpdate(progress, flag); - } - - @Override - public void startIntentSenderForResult(IntentSender intent, int requestCode, - Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) { - if (requestCode != -1) { - mPendingActivityRequestCode = requestCode; - StartActivityParams params = new StartActivityParams(this, requestCode); - params.intentSender = intent; - params.fillInIntent = fillInIntent; - params.flagsMask = flagsMask; - params.flagsValues = flagsValues; - params.extraFlags = extraFlags; - params.options = options; - startActivity(ProxyActivityStarter.getLaunchIntent(this, params)); - } else { - super.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask, - flagsValues, extraFlags, options); - } - } - - @Override - public void startActivityForResult(Intent intent, int requestCode, Bundle options) { - if (requestCode != -1) { - mPendingActivityRequestCode = requestCode; - StartActivityParams params = new StartActivityParams(this, requestCode); - params.intent = intent; - params.options = options; - startActivity(ProxyActivityStarter.getLaunchIntent(this, params)); - } else { - super.startActivityForResult(intent, requestCode, options); - } - } - - @Override - protected void onDeferredResumed() { - super.onDeferredResumed(); - handlePendingActivityRequest(); - } - - @Override - public void onStateSetEnd(LauncherState state) { - super.onStateSetEnd(state); - handlePendingActivityRequest(); - } - - private void handlePendingActivityRequest() { - if (mPendingActivityRequestCode != -1 && isInState(NORMAL) - && ((getActivityFlags() & ACTIVITY_STATE_DEFERRED_RESUMED) != 0)) { - // Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher. - onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null); - // ProxyActivityStarter is started with clear task to reset the task after which it - // removes the task itself. - startActivity(ProxyActivityStarter.getLaunchIntent(this, null)); - } - } - - @Override - protected void setupViews() { - super.setupViews(); - - mActionsView = findViewById(R.id.overview_actions_view); - RecentsView overviewPanel = (RecentsView) getOverviewPanel(); - SplitSelectStateController controller = - new SplitSelectStateController(this, mHandler, getStateManager(), - getDepthController()); - overviewPanel.init(mActionsView, controller); - mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize()); - mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this)); - - mAppTransitionManager = new QuickstepTransitionManager(this); - mAppTransitionManager.registerRemoteAnimations(); - mAppTransitionManager.registerRemoteTransitions(); - - mTISBindHelper = new TISBindHelper(this, this::onTISConnected); - mDepthController = new DepthController(this); - } - - private void onTISConnected(TISBinder binder) { - mTaskbarManager = binder.getTaskbarManager(); - mTaskbarManager.setActivity(this); - mOverviewCommandHelper = binder.getOverviewCommandHelper(); - } - - @Override - public void runOnBindToTouchInteractionService(Runnable r) { - mTISBindHelper.runOnBindToTouchInteractionService(r); - } - - private void initUnfoldTransitionProgressProvider() { - final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig(); - if (config.isEnabled()) { - mUnfoldTransitionProgressProvider = - UnfoldTransitionFactory.createUnfoldTransitionProgressProvider( - /* context= */ this, - config, - ProxyScreenStatusProvider.INSTANCE, - new DeviceStateManagerFoldProvider( - getSystemService(DeviceStateManager.class), /* context */this), - new ActivityManagerActivityTypeProvider( - getSystemService(ActivityManager.class)), - getSystemService(SensorManager.class), - getMainThreadHandler(), - getMainExecutor(), - /* backgroundExecutor= */ THREAD_POOL_EXECUTOR, - /* tracingTagPrefix= */ "launcher" - ); - - mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController( - this, - getWindowManager(), - mUnfoldTransitionProgressProvider - ); - } - } - - public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) { - mTaskbarUIController = taskbarUIController; - } - - public @Nullable LauncherTaskbarUIController getTaskbarUIController() { - return mTaskbarUIController; - } - - public T getActionsView() { - return (T) mActionsView; - } - - @Override - protected void closeOpenViews(boolean animate) { - super.closeOpenViews(animate); - TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY); - } - - @Override - protected void collectStateHandlers(List out) { - super.collectStateHandlers(out); - out.add(getDepthController()); - out.add(new RecentsViewStateController(this)); - out.add(new BackButtonAlphaHandler(this)); - } - - public DepthController getDepthController() { - return mDepthController; - } - - @Nullable - public UnfoldTransitionProgressProvider getUnfoldTransitionProgressProvider() { - return mUnfoldTransitionProgressProvider; - } - - @Override - public boolean supportsAdaptiveIconAnimation(View clickedView) { - return mAppTransitionManager.hasControlRemoteAppTransitionPermission(); - } - - @Override - public DragOptions getDefaultWorkspaceDragOptions() { - if (mNextWorkspaceDragOptions != null) { - DragOptions options = mNextWorkspaceDragOptions; - mNextWorkspaceDragOptions = null; - return options; - } - return super.getDefaultWorkspaceDragOptions(); - } - - public void setNextWorkspaceDragOptions(DragOptions dragOptions) { - mNextWorkspaceDragOptions = dragOptions; - } - - @Override - public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) { - QuickstepTransitionManager appTransitionManager = getAppTransitionManager(); - appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() { - @Override - public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { - - // On the first call clear the reference. - signal.cancel(); - - ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0); - fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets, - wallpaperTargets)); - AnimatorSet anim = new AnimatorSet(); - anim.play(fadeAnimation); - return anim; - } - }, signal); - } - - @Override - public float[] getNormalOverviewScaleAndOffset() { - return DisplayController.getNavigationMode(this).hasGestures - ? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET}; - } - - @Override - public void onDragLayerHierarchyChanged() { - onLauncherStateOrFocusChanged(); - } - - @Override - protected void onActivityFlagsChanged(int changeBits) { - if ((changeBits - & (ACTIVITY_STATE_WINDOW_FOCUSED | ACTIVITY_STATE_TRANSITION_ACTIVE)) != 0) { - onLauncherStateOrFocusChanged(); - } - - if ((changeBits & ACTIVITY_STATE_STARTED) != 0) { - mDepthController.setActivityStarted(isStarted()); - } - - if ((changeBits & ACTIVITY_STATE_RESUMED) != 0) { - if (mTaskbarUIController != null) { - mTaskbarUIController.onLauncherResumedOrPaused(hasBeenResumed()); - } - } - - super.onActivityFlagsChanged(changeBits); - } - - public boolean shouldBackButtonBeHidden(LauncherState toState) { - NavigationMode mode = DisplayController.getNavigationMode(this); - boolean shouldBackButtonBeHidden = mode.hasGestures - && toState.hasFlag(FLAG_HIDE_BACK_BUTTON) - && hasWindowFocus() - && (getActivityFlags() & ACTIVITY_STATE_TRANSITION_ACTIVE) == 0; - if (shouldBackButtonBeHidden) { - // Show the back button if there is a floating view visible. - shouldBackButtonBeHidden = AbstractFloatingView.getTopOpenViewWithType(this, - TYPE_ALL & ~TYPE_HIDE_BACK_BUTTON) == null; - } - return shouldBackButtonBeHidden; - } - - /** - * Sets the back button visibility based on the current state/window focus. - */ - private void onLauncherStateOrFocusChanged() { - boolean shouldBackButtonBeHidden = shouldBackButtonBeHidden(getStateManager().getState()); - if (DisplayController.getNavigationMode(this) == TWO_BUTTONS) { - UiThreadHelper.setBackButtonAlphaAsync(this, SET_BACK_BUTTON_ALPHA, - shouldBackButtonBeHidden ? 0f : 1f, true /* animate */); - } - if (getDragLayer() != null) { - getRootView().setDisallowBackGesture(shouldBackButtonBeHidden); - } - } - - @Override - public void finishBindingItems(IntSet pagesBoundFirst) { - super.finishBindingItems(pagesBoundFirst); - // Instantiate and initialize WellbeingModel now that its loading won't interfere with - // populating workspace. - // TODO: Find a better place for this - WellbeingModel.INSTANCE.get(this); - } - - @Override - public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks) { - pendingTasks.add(() -> { - // This is added in pending task as we need to wait for views to be positioned - // correctly before registering them for the animation. - if (mLauncherUnfoldAnimationController != null) { - // This is needed in case items are rebound while the unfold animation is in - // progress. - mLauncherUnfoldAnimationController.updateRegisteredViewsIfNeeded(); - } - }); - super.onInitialBindComplete(boundPages, pendingTasks); - } - - @Override - public Stream getSupportedShortcuts() { - Stream base = Stream.of(WellbeingModel.SHORTCUT_FACTORY); - if (ENABLE_SPLIT_FROM_WORKSPACE.get() && mDeviceProfile.isTablet) { - RecentsView recentsView = getOverviewPanel(); - // TODO: Pull it out of PagedOrentationHandler for split from workspace. - List positions = - recentsView.getPagedOrientationHandler().getSplitPositionOptions( - mDeviceProfile); - List> splitShortcuts = new ArrayList<>(); - for (SplitPositionOption position : positions) { - splitShortcuts.add(getSplitSelectShortcutByPosition(position)); - } - base = Stream.concat(base, splitShortcuts.stream()); - } - return Stream.concat(base, super.getSupportedShortcuts()); - } - - @Override - public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { - ActivityOptionsWrapper activityOptions = - mAppTransitionManager.hasControlRemoteAppTransitionPermission() - ? mAppTransitionManager.getActivityLaunchOptions(v) - : super.getActivityLaunchOptions(v, item); - if (mLastTouchUpTime > 0) { - ActivityOptionsCompat.setLauncherSourceInfo( - activityOptions.options, mLastTouchUpTime); - } - activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); - activityOptions.options.setLaunchDisplayId( - (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId() - : Display.DEFAULT_DISPLAY); - addLaunchCookie(item, activityOptions.options); - return activityOptions; - } - - /** - * Adds a new launch cookie for the activity launch if supported. - * - * @param info the item info for the launch - * @param opts the options to set the launchCookie on. - */ - public void addLaunchCookie(ItemInfo info, ActivityOptions opts) { - IBinder launchCookie = getLaunchCookie(info); - if (launchCookie != null) { - opts.setLaunchCookie(launchCookie); - } - } - - /** - * Return a new launch cookie for the activity launch if supported. - * - * @param info the item info for the launch - */ - public IBinder getLaunchCookie(ItemInfo info) { - if (info == null) { - return null; - } - switch (info.container) { - case LauncherSettings.Favorites.CONTAINER_DESKTOP: - case LauncherSettings.Favorites.CONTAINER_HOTSEAT: - // Fall through and continue it's on the workspace (we don't support swiping back - // to other containers like all apps or the hotseat predictions (which can change) - break; - default: - if (info.container >= 0) { - // Also allow swiping to folders - break; - } - // Reset any existing launch cookies associated with the cookie - return ObjectWrapper.wrap(NO_MATCHING_ID); - } - switch (info.itemType) { - case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: - case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: - case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: - case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: - // Fall through and continue if it's an app, shortcut, or widget - break; - default: - // Reset any existing launch cookies associated with the cookie - return ObjectWrapper.wrap(NO_MATCHING_ID); - } - return ObjectWrapper.wrap(new Integer(info.id)); - } - - public void setHintUserWillBeActive() { - addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE); - } - - @Override - public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) { - super.onDisplayInfoChanged(context, info, flags); - // When changing screens, force moving to rest state similar to StatefulActivity.onStop, as - // StatefulActivity isn't called consistently. - if ((flags & CHANGE_ACTIVE_SCREEN) != 0) { - getStateManager().moveToRestState(); - } - - if ((flags & CHANGE_NAVIGATION_MODE) != 0) { - getDragLayer().recreateControllers(); - if (mActionsView != null) { - mActionsView.updateVerticalMargin(info.navigationMode); - } - } - } - - @Override - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - super.dump(prefix, fd, writer, args); - if (mDepthController != null) { - 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; - } -} diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java index 35151f1a68..c4e85f6014 100644 --- a/quickstep/src/com/android/launcher3/LauncherInitListener.java +++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java @@ -20,6 +20,7 @@ import android.annotation.TargetApi; import android.os.Build; import android.os.CancellationSignal; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.RemoteAnimationProvider; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -44,7 +45,7 @@ public class LauncherInitListener extends ActivityInitListener { public boolean handleInit(Launcher launcher, boolean alreadyOnHome) { if (mRemoteAnimationProvider != null) { QuickstepTransitionManager appTransitionManager = - ((BaseQuickstepLauncher) launcher).getAppTransitionManager(); + ((QuickstepLauncher) launcher).getAppTransitionManager(); // Set a one-time animation provider. After the first call, this will get cleared. // TODO: Probably also check the intended target id. diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index d348cc3353..521b3fe66e 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -102,6 +102,7 @@ import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.testing.shared.ResourceUtils; import com.android.launcher3.touch.PagedOrientationHandler; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.util.DynamicResource; import com.android.launcher3.util.ObjectWrapper; @@ -193,7 +194,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener // Cross-fade duration between App Widget and App private static final int WIDGET_CROSSFADE_DURATION_MILLIS = 125; - protected final BaseQuickstepLauncher mLauncher; + protected final QuickstepLauncher mLauncher; private final DragLayer mDragLayer; final Handler mHandler; diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java index 89c07f234b..a0cf6cb1e6 100644 --- a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java +++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java @@ -23,9 +23,9 @@ import android.os.UserHandle; import android.util.Log; import android.view.View; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.quickstep.views.RecentsView; @@ -33,18 +33,18 @@ public interface QuickstepSystemShortcut { String TAG = QuickstepSystemShortcut.class.getSimpleName(); - static SystemShortcut.Factory getSplitSelectShortcutByPosition( + static SystemShortcut.Factory getSplitSelectShortcutByPosition( SplitPositionOption position) { return (activity, itemInfo, originalView) -> new QuickstepSystemShortcut.SplitSelectSystemShortcut(activity, itemInfo, originalView, position); } - class SplitSelectSystemShortcut extends SystemShortcut { + class SplitSelectSystemShortcut extends SystemShortcut { private final SplitPositionOption mPosition; - public SplitSelectSystemShortcut(BaseQuickstepLauncher launcher, ItemInfo itemInfo, + public SplitSelectSystemShortcut(QuickstepLauncher launcher, ItemInfo itemInfo, View originalView, SplitPositionOption position) { super(position.iconResId, position.textResId, launcher, itemInfo, originalView); diff --git a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java index 07d3a51603..8c11081a62 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java +++ b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java @@ -20,11 +20,11 @@ import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS; import static com.android.quickstep.AnimatedFloat.VALUE; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.UiThreadHelper; import com.android.quickstep.AnimatedFloat; @@ -35,10 +35,10 @@ import com.android.quickstep.SystemUiProxy; */ public class BackButtonAlphaHandler implements StateHandler { - private final BaseQuickstepLauncher mLauncher; + private final QuickstepLauncher mLauncher; private final AnimatedFloat mBackAlpha = new AnimatedFloat(this::updateBackAlpha); - public BackButtonAlphaHandler(BaseQuickstepLauncher launcher) { + public BackButtonAlphaHandler(QuickstepLauncher launcher) { mLauncher = launcher; } @@ -59,6 +59,6 @@ public class BackButtonAlphaHandler implements StateHandler { private void updateBackAlpha() { UiThreadHelper.setBackButtonAlphaAsync(mLauncher, - BaseQuickstepLauncher.SET_BACK_BUTTON_ALPHA, mBackAlpha.value, false /* animate */); + QuickstepLauncher.SET_BACK_BUTTON_ALPHA, mBackAlpha.value, false /* animate */); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java index 3c76e8ec2d..d69b8d291c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java @@ -16,7 +16,7 @@ package com.android.launcher3.taskbar; -import com.android.launcher3.BaseQuickstepLauncher; +import com.android.launcher3.uioverrides.QuickstepLauncher; /** * A data source which integrates with a Launcher instance, used specifically for a @@ -24,9 +24,9 @@ import com.android.launcher3.BaseQuickstepLauncher; */ public class DesktopTaskbarUIController extends TaskbarUIController { - private final BaseQuickstepLauncher mLauncher; + private final QuickstepLauncher mLauncher; - public DesktopTaskbarUIController(BaseQuickstepLauncher launcher) { + public DesktopTaskbarUIController(QuickstepLauncher launcher) { mLauncher = launcher; } diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 62a11d4954..6c740bac50 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -32,7 +32,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; @@ -42,6 +41,7 @@ import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.InstanceIdSequence; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.OnboardingPrefs; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.RecentsAnimationCallbacks; @@ -65,7 +65,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { private final SparseArray mTaskbarInAppDisplayProgress = new SparseArray<>(4); - private final BaseQuickstepLauncher mLauncher; + private final QuickstepLauncher mLauncher; private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener = dp -> { @@ -81,7 +81,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { private final TaskbarLauncherStateController mTaskbarLauncherStateController = new TaskbarLauncherStateController(); - public LauncherTaskbarUIController(BaseQuickstepLauncher launcher) { + public LauncherTaskbarUIController(QuickstepLauncher launcher) { mLauncher = launcher; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 0bda3cd324..ee94e8cd9b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -31,13 +31,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.statemanager.StateManager; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.MultiValueAlpha; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.RecentsAnimationCallbacks; @@ -78,7 +78,7 @@ import java.util.function.Supplier; private TaskbarControllers mControllers; private AnimatedFloat mTaskbarBackgroundAlpha; private MultiValueAlpha.AlphaProperty mIconAlphaForHome; - private BaseQuickstepLauncher mLauncher; + private QuickstepLauncher mLauncher; private Integer mPrevState; private int mState; @@ -132,7 +132,7 @@ import java.util.function.Supplier; } }; - public void init(TaskbarControllers controllers, BaseQuickstepLauncher launcher) { + public void init(TaskbarControllers controllers, QuickstepLauncher launcher) { mCanSyncViews = false; mControllers = controllers; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 1212c6161c..35c5b96b9a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -37,12 +37,12 @@ import android.view.Display; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.SettingsCache; import com.android.launcher3.util.SimpleBroadcastReceiver; @@ -237,8 +237,8 @@ public class TaskbarManager { */ private UnfoldTransitionProgressProvider getUnfoldTransitionProgressProviderForActivity( StatefulActivity activity) { - if (activity instanceof BaseQuickstepLauncher) { - return ((BaseQuickstepLauncher) activity).getUnfoldTransitionProgressProvider(); + if (activity instanceof QuickstepLauncher) { + return ((QuickstepLauncher) activity).getUnfoldTransitionProgressProvider(); } return null; } @@ -247,11 +247,11 @@ public class TaskbarManager { * Creates a {@link TaskbarUIController} to use while the given StatefulActivity is active. */ private TaskbarUIController createTaskbarUIControllerForActivity(StatefulActivity activity) { - if (activity instanceof BaseQuickstepLauncher) { + if (activity instanceof QuickstepLauncher) { if (mTaskbarActivityContext.getPackageManager().hasSystemFeature(FEATURE_PC)) { - return new DesktopTaskbarUIController((BaseQuickstepLauncher) activity); + return new DesktopTaskbarUIController((QuickstepLauncher) activity); } - return new LauncherTaskbarUIController((BaseQuickstepLauncher) activity); + return new LauncherTaskbarUIController((QuickstepLauncher) activity); } if (activity instanceof RecentsActivity) { return new FallbackTaskbarUIController((RecentsActivity) activity); diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java index ea0972f293..8427885d10 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java @@ -42,7 +42,6 @@ import android.util.FloatProperty; import androidx.annotation.NonNull; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; @@ -61,9 +60,9 @@ import com.android.quickstep.views.RecentsView; public abstract class BaseRecentsViewStateController implements StateHandler { protected final T mRecentsView; - protected final BaseQuickstepLauncher mLauncher; + protected final QuickstepLauncher mLauncher; - public BaseRecentsViewStateController(@NonNull BaseQuickstepLauncher launcher) { + public BaseRecentsViewStateController(@NonNull QuickstepLauncher launcher) { mLauncher = launcher; mRecentsView = launcher.getOverviewPanel(); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 951226cd1a..0f3ea15b80 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -17,46 +17,90 @@ package com.android.launcher3.uioverrides; import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED; +import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; +import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; import static com.android.launcher3.LauncherState.ALL_APPS; +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_MODAL_TASK; +import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; +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.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; +import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; +import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition; +import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX; +import static com.android.launcher3.taskbar.LauncherTaskbarUIController.MINUS_ONE_PAGE_PROGRESS_INDEX; +import static com.android.launcher3.taskbar.LauncherTaskbarUIController.WIDGETS_PAGE_PROGRESS_INDEX; import static com.android.launcher3.testing.shared.TestProtocol.HINT_STATE_ORDINAL; import static com.android.launcher3.testing.shared.TestProtocol.HINT_STATE_TWO_BUTTON_ORDINAL; import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL; import static com.android.launcher3.testing.shared.TestProtocol.QUICK_SWITCH_STATE_ORDINAL; +import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; +import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE; +import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS; +import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; +import android.animation.AnimatorSet; +import android.animation.ValueAnimator; +import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.content.Context; import android.content.Intent; +import android.content.IntentSender; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.hardware.SensorManager; +import android.hardware.devicestate.DeviceStateManager; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.IBinder; +import android.view.Display; import android.view.HapticFeedbackConstants; import android.view.View; +import android.window.SplashScreen; -import com.android.launcher3.BaseQuickstepLauncher; +import androidx.annotation.Nullable; + +import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepAccessibilityDelegate; +import com.android.launcher3.QuickstepTransitionManager; +import com.android.launcher3.R; import com.android.launcher3.Workspace; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.appprediction.PredictionRowView; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.model.BgDataModel.FixedContainerItems; +import com.android.launcher3.model.WellbeingModel; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.popup.SystemShortcut; +import com.android.launcher3.proxy.ProxyActivityStarter; +import com.android.launcher3.proxy.StartActivityParams; +import com.android.launcher3.statehandlers.BackButtonAlphaHandler; +import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory; +import com.android.launcher3.statemanager.StateManager.StateHandler; +import com.android.launcher3.taskbar.LauncherTaskbarUIController; +import com.android.launcher3.taskbar.TaskbarManager; import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory; import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController; import com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController; @@ -67,27 +111,53 @@ import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchControll import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController; import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController; import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController; +import com.android.launcher3.util.ActivityOptionsWrapper; 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.PendingRequestArgs; +import com.android.launcher3.util.PendingSplitSelectInfo; +import com.android.launcher3.util.RunnableList; +import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.UiThreadHelper.AsyncCommand; import com.android.launcher3.widget.LauncherAppWidgetHost; +import com.android.quickstep.OverviewCommandHelper; +import com.android.quickstep.RecentsModel; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskUtils; +import com.android.quickstep.TouchInteractionService.TISBinder; +import com.android.quickstep.util.LauncherUnfoldAnimationController; +import com.android.quickstep.util.ProxyScreenStatusProvider; import com.android.quickstep.util.QuickstepOnboardingPrefs; +import com.android.quickstep.util.RemoteAnimationProvider; +import com.android.quickstep.util.RemoteFadeOutAnimationListener; +import com.android.quickstep.util.SplitSelectStateController; +import com.android.quickstep.util.TISBindHelper; +import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.system.ActivityManagerWrapper; +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 java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Stream; -public class QuickstepLauncher extends BaseQuickstepLauncher { +public class QuickstepLauncher extends Launcher { public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false; /** @@ -95,13 +165,51 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { */ public static final AsyncCommand SET_SHELF_HEIGHT = (context, arg1, arg2) -> SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2); + /** + * Reusable command for applying the back button alpha on the background thread. + */ + public static final AsyncCommand SET_BACK_BUTTON_ALPHA = + (context, arg1, arg2) -> SystemUiProxy.INSTANCE.get(context).setNavBarButtonAlpha( + Float.intBitsToFloat(arg1), arg2 != 0); private FixedContainerItems mAllAppsPredictions; private HotseatPredictionController mHotseatPredictionController; + private DepthController mDepthController; + private QuickstepTransitionManager mAppTransitionManager; + private OverviewActionsView mActionsView; + private TISBindHelper mTISBindHelper; + private @Nullable TaskbarManager mTaskbarManager; + private @Nullable OverviewCommandHelper mOverviewCommandHelper; + private @Nullable LauncherTaskbarUIController mTaskbarUIController; + // Will be updated when dragging from taskbar. + private @Nullable DragOptions mNextWorkspaceDragOptions = null; + 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 setupViews() { super.setupViews(); + + mActionsView = findViewById(R.id.overview_actions_view); + RecentsView overviewPanel = (RecentsView) getOverviewPanel(); + SplitSelectStateController controller = + new SplitSelectStateController(this, mHandler, getStateManager(), + getDepthController()); + overviewPanel.init(mActionsView, controller); + mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize()); + mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this)); + + mAppTransitionManager = new QuickstepTransitionManager(this); + mAppTransitionManager.registerRemoteAnimations(); + mAppTransitionManager.registerRemoteTransitions(); + + mTISBindHelper = new TISBindHelper(this, this::onTISConnected); + mDepthController = new DepthController(this); mHotseatPredictionController = new HotseatPredictionController(this); } @@ -183,6 +291,21 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override protected void onActivityFlagsChanged(int changeBits) { + if ((changeBits + & (ACTIVITY_STATE_WINDOW_FOCUSED | ACTIVITY_STATE_TRANSITION_ACTIVE)) != 0) { + onLauncherStateOrFocusChanged(); + } + + if ((changeBits & ACTIVITY_STATE_STARTED) != 0) { + mDepthController.setActivityStarted(isStarted()); + } + + if ((changeBits & ACTIVITY_STATE_RESUMED) != 0) { + if (mTaskbarUIController != null) { + mTaskbarUIController.onLauncherResumedOrPaused(hasBeenResumed()); + } + } + super.onActivityFlagsChanged(changeBits); if ((changeBits & (ACTIVITY_STATE_DEFERRED_RESUMED | ACTIVITY_STATE_STARTED | ACTIVITY_STATE_USER_ACTIVE | ACTIVITY_STATE_TRANSITION_ACTIVE)) != 0) { @@ -203,8 +326,22 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public Stream getSupportedShortcuts() { + Stream base = Stream.of(WellbeingModel.SHORTCUT_FACTORY); + if (ENABLE_SPLIT_FROM_WORKSPACE.get() && mDeviceProfile.isTablet) { + RecentsView recentsView = getOverviewPanel(); + // TODO: Pull it out of PagedOrentationHandler for split from workspace. + List positions = + recentsView.getPagedOrientationHandler().getSplitPositionOptions( + mDeviceProfile); + List> splitShortcuts = new ArrayList<>(); + for (SplitPositionOption position : positions) { + splitShortcuts.add(getSplitSelectShortcutByPosition(position)); + } + base = Stream.concat(base, splitShortcuts.stream()); + } return Stream.concat( - Stream.of(mHotseatPredictionController), super.getSupportedShortcuts()); + Stream.of(mHotseatPredictionController), + Stream.concat(base, super.getSupportedShortcuts())); } /** @@ -251,6 +388,20 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public void onDestroy() { + mAppTransitionManager.onActivityDestroyed(); + if (mUnfoldTransitionProgressProvider != null) { + mUnfoldTransitionProgressProvider.destroy(); + } + + mTISBindHelper.onDestroy(); + if (mTaskbarManager != null) { + mTaskbarManager.clearActivity(this); + } + + if (mLauncherUnfoldAnimationController != null) { + mLauncherUnfoldAnimationController.onDestroy(); + } + super.onDestroy(); mHotseatPredictionController.destroy(); } @@ -258,6 +409,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public void onStateSetEnd(LauncherState state) { super.onStateSetEnd(state); + handlePendingActivityRequest(); switch (state.ordinal) { case HINT_STATE_ORDINAL: { @@ -342,6 +494,481 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { return appWidgetHost; } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState != null) { + mPendingSplitSelectInfo = ObjectWrapper.unwrap( + savedInstanceState.getIBinder(PENDING_SPLIT_SELECT_INFO)); + } + addMultiWindowModeChangedListener(mDepthController); + initUnfoldTransitionProgressProvider(); + } + + @Override + protected void onResume() { + super.onResume(); + + if (mLauncherUnfoldAnimationController != null) { + mLauncherUnfoldAnimationController.onResume(); + } + } + + @Override + protected void onPause() { + if (mLauncherUnfoldAnimationController != null) { + mLauncherUnfoldAnimationController.onPause(); + } + + super.onPause(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + if (mOverviewCommandHelper != null) { + mOverviewCommandHelper.clearPendingCommands(); + } + } + + public QuickstepTransitionManager getAppTransitionManager() { + return mAppTransitionManager; + } + + @Override + public void onEnterAnimationComplete() { + super.onEnterAnimationComplete(); + // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled + // as a part of quickstep, so that high-res thumbnails can load the next time we enter + // overview + RecentsModel.INSTANCE.get(this).getThumbnailCache() + .getHighResLoadingState().setVisible(true); + } + + @Override + protected void handleGestureContract(Intent intent) { + if (FeatureFlags.SEPARATE_RECENTS_ACTIVITY.get()) { + super.handleGestureContract(intent); + } + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + RecentsModel.INSTANCE.get(this).onTrimMemory(level); + } + + @Override + public void onUiChangedWhileSleeping() { + // Remove the snapshot because the content view may have obvious changes. + UI_HELPER_EXECUTOR.execute( + () -> ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(this)); + } + + @Override + protected void onScreenOff() { + super.onScreenOff(); + if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + RecentsView recentsView = getOverviewPanel(); + recentsView.finishRecentsAnimation(true /* toRecents */, null); + } + } + + /** + * {@code LauncherOverlayCallbacks} scroll amount. + * Indicates transition progress to -1 screen. + * @param progress From 0 to 1. + */ + @Override + public void onScrollChanged(float progress) { + super.onScrollChanged(progress); + onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX); + } + + @Override + public void onAllAppsTransition(float progress) { + super.onAllAppsTransition(progress); + onTaskbarInAppDisplayProgressUpdate(progress, ALL_APPS_PAGE_PROGRESS_INDEX); + } + + @Override + public void onWidgetsTransition(float progress) { + super.onWidgetsTransition(progress); + onTaskbarInAppDisplayProgressUpdate(progress, WIDGETS_PAGE_PROGRESS_INDEX); + } + + private void onTaskbarInAppDisplayProgressUpdate(float progress, int flag) { + if (mTaskbarManager == null + || mTaskbarManager.getCurrentActivityContext() == null + || mTaskbarUIController == null) { + return; + } + mTaskbarUIController.onTaskbarInAppDisplayProgressUpdate(progress, flag); + } + + @Override + public void startIntentSenderForResult(IntentSender intent, int requestCode, + Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) { + if (requestCode != -1) { + mPendingActivityRequestCode = requestCode; + StartActivityParams params = new StartActivityParams(this, requestCode); + params.intentSender = intent; + params.fillInIntent = fillInIntent; + params.flagsMask = flagsMask; + params.flagsValues = flagsValues; + params.extraFlags = extraFlags; + params.options = options; + startActivity(ProxyActivityStarter.getLaunchIntent(this, params)); + } else { + super.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask, + flagsValues, extraFlags, options); + } + } + + @Override + public void startActivityForResult(Intent intent, int requestCode, Bundle options) { + if (requestCode != -1) { + mPendingActivityRequestCode = requestCode; + StartActivityParams params = new StartActivityParams(this, requestCode); + params.intent = intent; + params.options = options; + startActivity(ProxyActivityStarter.getLaunchIntent(this, params)); + } else { + super.startActivityForResult(intent, requestCode, options); + } + } + + @Override + protected void onDeferredResumed() { + super.onDeferredResumed(); + handlePendingActivityRequest(); + } + + private void handlePendingActivityRequest() { + if (mPendingActivityRequestCode != -1 && isInState(NORMAL) + && ((getActivityFlags() & ACTIVITY_STATE_DEFERRED_RESUMED) != 0)) { + // Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher. + onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null); + // ProxyActivityStarter is started with clear task to reset the task after which it + // removes the task itself. + startActivity(ProxyActivityStarter.getLaunchIntent(this, null)); + } + } + + private void onTISConnected(TISBinder binder) { + mTaskbarManager = binder.getTaskbarManager(); + mTaskbarManager.setActivity(this); + mOverviewCommandHelper = binder.getOverviewCommandHelper(); + } + + @Override + public void runOnBindToTouchInteractionService(Runnable r) { + mTISBindHelper.runOnBindToTouchInteractionService(r); + } + + private void initUnfoldTransitionProgressProvider() { + final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig(); + if (config.isEnabled()) { + mUnfoldTransitionProgressProvider = + UnfoldTransitionFactory.createUnfoldTransitionProgressProvider( + /* context= */ this, + config, + ProxyScreenStatusProvider.INSTANCE, + new DeviceStateManagerFoldProvider( + getSystemService(DeviceStateManager.class), /* context */this), + new ActivityManagerActivityTypeProvider( + getSystemService(ActivityManager.class)), + getSystemService(SensorManager.class), + getMainThreadHandler(), + getMainExecutor(), + /* backgroundExecutor= */ THREAD_POOL_EXECUTOR, + /* tracingTagPrefix= */ "launcher" + ); + + mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController( + this, + getWindowManager(), + mUnfoldTransitionProgressProvider + ); + } + } + + public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) { + mTaskbarUIController = taskbarUIController; + } + + public @Nullable LauncherTaskbarUIController getTaskbarUIController() { + return mTaskbarUIController; + } + + public T getActionsView() { + return (T) mActionsView; + } + + @Override + protected void closeOpenViews(boolean animate) { + super.closeOpenViews(animate); + TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY); + } + + @Override + protected void collectStateHandlers(List out) { + super.collectStateHandlers(out); + out.add(getDepthController()); + out.add(new RecentsViewStateController(this)); + out.add(new BackButtonAlphaHandler(this)); + } + + public DepthController getDepthController() { + return mDepthController; + } + + @Nullable + public UnfoldTransitionProgressProvider getUnfoldTransitionProgressProvider() { + return mUnfoldTransitionProgressProvider; + } + + @Override + public boolean supportsAdaptiveIconAnimation(View clickedView) { + return mAppTransitionManager.hasControlRemoteAppTransitionPermission(); + } + + @Override + public DragOptions getDefaultWorkspaceDragOptions() { + if (mNextWorkspaceDragOptions != null) { + DragOptions options = mNextWorkspaceDragOptions; + mNextWorkspaceDragOptions = null; + return options; + } + return super.getDefaultWorkspaceDragOptions(); + } + + public void setNextWorkspaceDragOptions(DragOptions dragOptions) { + mNextWorkspaceDragOptions = dragOptions; + } + + @Override + public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) { + QuickstepTransitionManager appTransitionManager = getAppTransitionManager(); + appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() { + @Override + public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { + + // On the first call clear the reference. + signal.cancel(); + + ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0); + fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets, + wallpaperTargets)); + AnimatorSet anim = new AnimatorSet(); + anim.play(fadeAnimation); + return anim; + } + }, signal); + } + + @Override + public float[] getNormalOverviewScaleAndOffset() { + return DisplayController.getNavigationMode(this).hasGestures + ? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET}; + } + + @Override + public void onDragLayerHierarchyChanged() { + onLauncherStateOrFocusChanged(); + } + + public boolean shouldBackButtonBeHidden(LauncherState toState) { + NavigationMode mode = DisplayController.getNavigationMode(this); + boolean shouldBackButtonBeHidden = mode.hasGestures + && toState.hasFlag(FLAG_HIDE_BACK_BUTTON) + && hasWindowFocus() + && (getActivityFlags() & ACTIVITY_STATE_TRANSITION_ACTIVE) == 0; + if (shouldBackButtonBeHidden) { + // Show the back button if there is a floating view visible. + shouldBackButtonBeHidden = AbstractFloatingView.getTopOpenViewWithType(this, + TYPE_ALL & ~TYPE_HIDE_BACK_BUTTON) == null; + } + return shouldBackButtonBeHidden; + } + + /** + * Sets the back button visibility based on the current state/window focus. + */ + private void onLauncherStateOrFocusChanged() { + boolean shouldBackButtonBeHidden = shouldBackButtonBeHidden(getStateManager().getState()); + if (DisplayController.getNavigationMode(this) == TWO_BUTTONS) { + UiThreadHelper.setBackButtonAlphaAsync(this, SET_BACK_BUTTON_ALPHA, + shouldBackButtonBeHidden ? 0f : 1f, true /* animate */); + } + if (getDragLayer() != null) { + getRootView().setDisallowBackGesture(shouldBackButtonBeHidden); + } + } + + @Override + public void finishBindingItems(IntSet pagesBoundFirst) { + super.finishBindingItems(pagesBoundFirst); + // Instantiate and initialize WellbeingModel now that its loading won't interfere with + // populating workspace. + // TODO: Find a better place for this + WellbeingModel.INSTANCE.get(this); + } + + @Override + public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks) { + pendingTasks.add(() -> { + // This is added in pending task as we need to wait for views to be positioned + // correctly before registering them for the animation. + if (mLauncherUnfoldAnimationController != null) { + // This is needed in case items are rebound while the unfold animation is in + // progress. + mLauncherUnfoldAnimationController.updateRegisteredViewsIfNeeded(); + } + }); + super.onInitialBindComplete(boundPages, pendingTasks); + } + + @Override + public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { + ActivityOptionsWrapper activityOptions = + mAppTransitionManager.hasControlRemoteAppTransitionPermission() + ? mAppTransitionManager.getActivityLaunchOptions(v) + : super.getActivityLaunchOptions(v, item); + if (mLastTouchUpTime > 0) { + ActivityOptionsCompat.setLauncherSourceInfo( + activityOptions.options, mLastTouchUpTime); + } + activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); + activityOptions.options.setLaunchDisplayId( + (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId() + : Display.DEFAULT_DISPLAY); + addLaunchCookie(item, activityOptions.options); + return activityOptions; + } + + /** + * Adds a new launch cookie for the activity launch if supported. + * + * @param info the item info for the launch + * @param opts the options to set the launchCookie on. + */ + public void addLaunchCookie(ItemInfo info, ActivityOptions opts) { + IBinder launchCookie = getLaunchCookie(info); + if (launchCookie != null) { + opts.setLaunchCookie(launchCookie); + } + } + + /** + * Return a new launch cookie for the activity launch if supported. + * + * @param info the item info for the launch + */ + public IBinder getLaunchCookie(ItemInfo info) { + if (info == null) { + return null; + } + switch (info.container) { + case Favorites.CONTAINER_DESKTOP: + case Favorites.CONTAINER_HOTSEAT: + // Fall through and continue it's on the workspace (we don't support swiping back + // to other containers like all apps or the hotseat predictions (which can change) + break; + default: + if (info.container >= 0) { + // Also allow swiping to folders + break; + } + // Reset any existing launch cookies associated with the cookie + return ObjectWrapper.wrap(NO_MATCHING_ID); + } + switch (info.itemType) { + case Favorites.ITEM_TYPE_APPLICATION: + case Favorites.ITEM_TYPE_SHORTCUT: + case Favorites.ITEM_TYPE_DEEP_SHORTCUT: + case Favorites.ITEM_TYPE_APPWIDGET: + // Fall through and continue if it's an app, shortcut, or widget + break; + default: + // Reset any existing launch cookies associated with the cookie + return ObjectWrapper.wrap(NO_MATCHING_ID); + } + return ObjectWrapper.wrap(new Integer(info.id)); + } + + public void setHintUserWillBeActive() { + addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE); + } + + @Override + public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) { + super.onDisplayInfoChanged(context, info, flags); + // When changing screens, force moving to rest state similar to StatefulActivity.onStop, as + // StatefulActivity isn't called consistently. + if ((flags & CHANGE_ACTIVE_SCREEN) != 0) { + getStateManager().moveToRestState(); + } + + if ((flags & CHANGE_NAVIGATION_MODE) != 0) { + getDragLayer().recreateControllers(); + if (mActionsView != null) { + mActionsView.updateVerticalMargin(info.navigationMode); + } + } + } + + @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; + } + private static final class LauncherTaskViewController extends TaskViewTouchController { @@ -368,6 +995,9 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { super.dump(prefix, fd, writer, args); + if (mDepthController != null) { + mDepthController.dump(prefix, writer); + } RecentsView recentsView = getOverviewPanel(); writer.println("\nQuickstepLauncher:"); writer.println(prefix + "\tmOrientationState: " + (recentsView == null ? "recentsNull" : diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 00a98c0647..5cddd07340 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -35,7 +35,6 @@ import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.PendingAnimation; @@ -55,7 +54,7 @@ import com.android.quickstep.views.RecentsView; public final class RecentsViewStateController extends BaseRecentsViewStateController { - public RecentsViewStateController(BaseQuickstepLauncher launcher) { + public RecentsViewStateController(QuickstepLauncher launcher) { super(launcher); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java index 8faabc9561..918b3c1bf8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java @@ -34,13 +34,13 @@ import android.graphics.PointF; import android.view.MotionEvent; import android.view.ViewConfiguration; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.taskbar.LauncherTaskbarUIController; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.MotionPauseDetector; @@ -114,7 +114,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch public void onDragStart(boolean start, float startDisplacement) { if (mLauncher.isInState(ALL_APPS)) { LauncherTaskbarUIController controller = - ((BaseQuickstepLauncher) mLauncher).getTaskbarUIController(); + ((QuickstepLauncher) mLauncher).getTaskbarUIController(); if (controller != null) { controller.setShouldDelayLauncherStateAnim(true); } @@ -151,7 +151,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch @Override public void onDragEnd(float velocity) { LauncherTaskbarUIController controller = - ((BaseQuickstepLauncher) mLauncher).getTaskbarUIController(); + ((QuickstepLauncher) mLauncher).getTaskbarUIController(); if (controller != null) { controller.setShouldDelayLauncherStateAnim(false); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index bc76487cf8..6f925db36e 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -58,7 +58,6 @@ import android.graphics.PointF; import android.view.MotionEvent; import android.view.animation.Interpolator; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -67,6 +66,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.BaseSwipeDetector; import com.android.launcher3.touch.BothAxesSwipeDetector; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.TouchController; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.SystemUiProxy; @@ -91,7 +91,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, private static final Interpolator SCALE_DOWN_INTERPOLATOR = LINEAR; private static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300; - private final BaseQuickstepLauncher mLauncher; + private final QuickstepLauncher mLauncher; private final BothAxesSwipeDetector mSwipeDetector; private final float mXRange; private final float mYRange; @@ -113,7 +113,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, private AnimatorPlaybackController mXOverviewAnim; private AnimatedFloat mYOverviewAnim; - public NoButtonQuickSwitchTouchController(BaseQuickstepLauncher launcher) { + public NoButtonQuickSwitchTouchController(QuickstepLauncher launcher) { mLauncher = launcher; mSwipeDetector = new BothAxesSwipeDetector(mLauncher, this); mRecentsView = mLauncher.getOverviewPanel(); diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index c13b95f2ab..4ceafeb79a 100644 --- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -33,7 +33,6 @@ import android.view.MotionEvent; import androidx.annotation.Nullable; import androidx.annotation.UiThread; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherInitListener; @@ -44,6 +43,7 @@ import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.touch.PagedOrientationHandler; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DisplayController.NavigationMode; import com.android.quickstep.GestureState.GestureEndTarget; @@ -61,7 +61,7 @@ import java.util.function.Predicate; * {@link BaseActivityInterface} for the in-launcher recents. */ public final class LauncherActivityInterface extends - BaseActivityInterface { + BaseActivityInterface { public static final LauncherActivityInterface INSTANCE = new LauncherActivityInterface(); @@ -122,7 +122,7 @@ public final class LauncherActivityInterface extends notifyRecentsOfOrientation(deviceState.getRotationTouchHelper()); DefaultAnimationFactory factory = new DefaultAnimationFactory(callback) { @Override - protected void createBackgroundToOverviewAnim(BaseQuickstepLauncher activity, + protected void createBackgroundToOverviewAnim(QuickstepLauncher activity, PendingAnimation pa) { super.createBackgroundToOverviewAnim(activity, pa); @@ -135,7 +135,7 @@ public final class LauncherActivityInterface extends } }; - BaseQuickstepLauncher launcher = factory.initBackgroundStateUI(); + QuickstepLauncher launcher = factory.initBackgroundStateUI(); // Since all apps is not visible, we can safely reset the scroll position. // This ensures then the next swipe up to all-apps starts from scroll 0. launcher.getAppsView().reset(false /* animate */); @@ -159,14 +159,14 @@ public final class LauncherActivityInterface extends @Nullable @Override - public BaseQuickstepLauncher getCreatedActivity() { - return BaseQuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity(); + public QuickstepLauncher getCreatedActivity() { + return QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity(); } @Nullable @Override public DepthController getDepthController() { - BaseQuickstepLauncher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedActivity(); if (launcher == null) { return null; } @@ -176,7 +176,7 @@ public final class LauncherActivityInterface extends @Nullable @Override public LauncherTaskbarUIController getTaskbarController() { - BaseQuickstepLauncher launcher = getCreatedActivity(); + QuickstepLauncher launcher = getCreatedActivity(); if (launcher == null) { return null; } @@ -318,7 +318,7 @@ public final class LauncherActivityInterface extends } @Override - protected int getOverviewScrimColorForState(BaseQuickstepLauncher launcher, + protected int getOverviewScrimColorForState(QuickstepLauncher launcher, LauncherState state) { return state.getWorkspaceScrimColor(launcher); } diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java index fd9f922005..7a281dd2a7 100644 --- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java +++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java @@ -39,10 +39,10 @@ import android.window.BackEvent; import android.window.IOnBackInvokedCallback; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.quickstep.util.RectFSpringAnim; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -75,7 +75,7 @@ public class LauncherBackAnimationController { private final RectF mCancelRect = new RectF(); /** The current window position. */ private final RectF mCurrentRect = new RectF(); - private final BaseQuickstepLauncher mLauncher; + private final QuickstepLauncher mLauncher; private final int mWindowScaleMarginX; /** Max window translation in the Y axis. */ private final int mWindowMaxDeltaY; @@ -93,7 +93,7 @@ public class LauncherBackAnimationController { private IOnBackInvokedCallback mBackCallback; public LauncherBackAnimationController( - BaseQuickstepLauncher launcher, + QuickstepLauncher launcher, QuickstepTransitionManager quickstepTransitionManager) { mLauncher = launcher; mQuickstepTransitionManager = quickstepTransitionManager; diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index 196a6642ba..36ca993f85 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -35,10 +35,10 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.views.FloatingIconView; import com.android.launcher3.views.FloatingView; @@ -57,7 +57,7 @@ import java.util.ArrayList; * Temporary class to allow easier refactoring */ public class LauncherSwipeHandlerV2 extends - AbsSwipeUpHandler { + AbsSwipeUpHandler { public LauncherSwipeHandlerV2(Context context, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs, diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index de527a7d0c..eec8582756 100644 --- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -35,7 +35,6 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Hotseat; @@ -49,6 +48,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.SpringAnimationBuilder; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.DynamicResource; import com.android.quickstep.views.RecentsView; import com.android.systemui.plugins.ResourceProvider; @@ -295,11 +295,11 @@ public class StaggeredWorkspaceAnim { } private void addDepthAnimationForState(Launcher launcher, LauncherState state, long duration) { - if (!(launcher instanceof BaseQuickstepLauncher)) { + if (!(launcher instanceof QuickstepLauncher)) { return; } PendingAnimation builder = new PendingAnimation(duration); - DepthController depthController = ((BaseQuickstepLauncher) launcher).getDepthController(); + DepthController depthController = ((QuickstepLauncher) launcher).getDepthController(); depthController.setStateWithAnimation(state, new StateAnimationConfig(), builder); mAnimators.play(builder.buildAnim()); } diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java index 5eb543e40d..34fa7f1764 100644 --- a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java +++ b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java @@ -32,7 +32,6 @@ import android.animation.ObjectAnimator; import android.util.FloatProperty; import android.view.View; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.Hotseat; import com.android.launcher3.Launcher; import com.android.launcher3.R; @@ -41,6 +40,7 @@ import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.DynamicResource; import com.android.quickstep.views.RecentsView; import com.android.systemui.plugins.ResourceProvider; @@ -84,9 +84,9 @@ public class WorkspaceRevealAnim { } // Add depth controller animation. - if (launcher instanceof BaseQuickstepLauncher) { + if (launcher instanceof QuickstepLauncher) { PendingAnimation depthBuilder = new PendingAnimation(DURATION_MS); - DepthController depth = ((BaseQuickstepLauncher) launcher).getDepthController(); + DepthController depth = ((QuickstepLauncher) launcher).getDepthController(); depth.setStateWithAnimation(NORMAL, new StateAnimationConfig(), depthBuilder); mAnimators.play(depthBuilder.buildAnim()); } diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 3c5a626085..6a33d36ab4 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -32,11 +32,11 @@ import android.view.Surface; import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseQuickstepLauncher; 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.uioverrides.QuickstepLauncher; import com.android.launcher3.util.PendingSplitSelectInfo; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.quickstep.LauncherActivityInterface; @@ -46,7 +46,7 @@ import com.android.quickstep.util.SplitSelectStateController; * {@link RecentsView} used in Launcher activity */ @TargetApi(Build.VERSION_CODES.O) -public class LauncherRecentsView extends RecentsView +public class LauncherRecentsView extends RecentsView implements StateListener { public LauncherRecentsView(Context context) {