1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.launcher3.uioverrides; 17 18 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 19 import static android.os.Trace.TRACE_TAG_APP; 20 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE; 21 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED; 22 import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY; 23 24 import static com.android.app.animation.Interpolators.EMPHASIZED; 25 import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE; 26 import static com.android.launcher3.Flags.enableExpressiveDismissTaskMotion; 27 import static com.android.launcher3.Flags.enableUnfoldStateAnimation; 28 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO; 29 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE; 30 import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON; 31 import static com.android.launcher3.LauncherSettings.Animation.VIEW_BACKGROUND; 32 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; 33 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; 34 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; 35 import static com.android.launcher3.LauncherState.ALL_APPS; 36 import static com.android.launcher3.LauncherState.NORMAL; 37 import static com.android.launcher3.LauncherState.NO_OFFSET; 38 import static com.android.launcher3.LauncherState.OVERVIEW; 39 import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK; 40 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; 41 import static com.android.launcher3.Utilities.isRtl; 42 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; 43 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; 44 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME; 45 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED; 46 import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition; 47 import static com.android.launcher3.popup.SystemShortcut.APP_INFO; 48 import static com.android.launcher3.popup.SystemShortcut.BUBBLE_SHORTCUT; 49 import static com.android.launcher3.popup.SystemShortcut.DONT_SUGGEST_APP; 50 import static com.android.launcher3.popup.SystemShortcut.INSTALL; 51 import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL; 52 import static com.android.launcher3.popup.SystemShortcut.UNINSTALL_APP; 53 import static com.android.launcher3.popup.SystemShortcut.WIDGETS; 54 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX; 55 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.MINUS_ONE_PAGE_PROGRESS_INDEX; 56 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.WIDGETS_PAGE_PROGRESS_INDEX; 57 import static com.android.launcher3.testing.shared.TestProtocol.HINT_STATE_ORDINAL; 58 import static com.android.launcher3.testing.shared.TestProtocol.HINT_STATE_TWO_BUTTON_ORDINAL; 59 import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL; 60 import static com.android.launcher3.testing.shared.TestProtocol.QUICK_SWITCH_STATE_ORDINAL; 61 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; 62 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE; 63 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; 64 import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback; 65 import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT; 66 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; 67 68 import android.animation.Animator; 69 import android.animation.AnimatorListenerAdapter; 70 import android.animation.AnimatorSet; 71 import android.app.ActivityOptions; 72 import android.content.Context; 73 import android.content.Intent; 74 import android.content.IntentSender; 75 import android.content.pm.ShortcutInfo; 76 import android.content.res.Configuration; 77 import android.graphics.Rect; 78 import android.graphics.RectF; 79 import android.hardware.display.DisplayManager; 80 import android.media.permission.SafeCloseable; 81 import android.os.Build; 82 import android.os.Bundle; 83 import android.os.IRemoteCallback; 84 import android.os.SystemProperties; 85 import android.os.Trace; 86 import android.os.UserHandle; 87 import android.text.TextUtils; 88 import android.util.AttributeSet; 89 import android.view.Display; 90 import android.view.HapticFeedbackConstants; 91 import android.view.KeyEvent; 92 import android.view.View; 93 import android.widget.AnalogClock; 94 import android.widget.TextClock; 95 import android.window.BackEvent; 96 import android.window.OnBackAnimationCallback; 97 import android.window.OnBackInvokedDispatcher; 98 import android.window.RemoteTransition; 99 import android.window.SplashScreen; 100 101 import androidx.annotation.BinderThread; 102 import androidx.annotation.NonNull; 103 import androidx.annotation.Nullable; 104 import androidx.annotation.RequiresApi; 105 106 import com.android.app.viewcapture.ViewCaptureFactory; 107 import com.android.launcher3.AbstractFloatingView; 108 import com.android.launcher3.DeviceProfile; 109 import com.android.launcher3.Flags; 110 import com.android.launcher3.InvariantDeviceProfile; 111 import com.android.launcher3.Launcher; 112 import com.android.launcher3.LauncherSettings.Favorites; 113 import com.android.launcher3.LauncherState; 114 import com.android.launcher3.QuickstepAccessibilityDelegate; 115 import com.android.launcher3.QuickstepTransitionManager; 116 import com.android.launcher3.R; 117 import com.android.launcher3.Utilities; 118 import com.android.launcher3.Workspace; 119 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; 120 import com.android.launcher3.allapps.AllAppsRecyclerView; 121 import com.android.launcher3.anim.AnimatorPlaybackController; 122 import com.android.launcher3.anim.PendingAnimation; 123 import com.android.launcher3.apppairs.AppPairIcon; 124 import com.android.launcher3.appprediction.PredictionRowView; 125 import com.android.launcher3.config.FeatureFlags; 126 import com.android.launcher3.desktop.DesktopRecentsTransitionController; 127 import com.android.launcher3.hybridhotseat.HotseatPredictionController; 128 import com.android.launcher3.logging.InstanceId; 129 import com.android.launcher3.logging.StatsLogManager; 130 import com.android.launcher3.logging.StatsLogManager.StatsLogger; 131 import com.android.launcher3.model.BgDataModel.FixedContainerItems; 132 import com.android.launcher3.model.WellbeingModel; 133 import com.android.launcher3.model.data.ItemInfo; 134 import com.android.launcher3.popup.SystemShortcut; 135 import com.android.launcher3.proxy.ProxyActivityStarter; 136 import com.android.launcher3.statehandlers.DepthController; 137 import com.android.launcher3.statehandlers.DesktopVisibilityController; 138 import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory; 139 import com.android.launcher3.statemanager.StateManager.StateHandler; 140 import com.android.launcher3.taskbar.LauncherTaskbarUIController; 141 import com.android.launcher3.taskbar.TaskbarManager; 142 import com.android.launcher3.taskbar.TaskbarUIController; 143 import com.android.launcher3.testing.TestLogging; 144 import com.android.launcher3.testing.shared.TestProtocol; 145 import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory; 146 import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController; 147 import com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController; 148 import com.android.launcher3.uioverrides.touchcontrollers.NoButtonQuickSwitchTouchController; 149 import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController; 150 import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchController; 151 import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController; 152 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewDismissTouchController; 153 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewLaunchTouchController; 154 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewRecentsTouchContext; 155 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchControllerDeprecated; 156 import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController; 157 import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController; 158 import com.android.launcher3.util.ActivityOptionsWrapper; 159 import com.android.launcher3.util.DisplayController; 160 import com.android.launcher3.util.IntSet; 161 import com.android.launcher3.util.NavigationMode; 162 import com.android.launcher3.util.ObjectWrapper; 163 import com.android.launcher3.util.PendingRequestArgs; 164 import com.android.launcher3.util.PendingSplitSelectInfo; 165 import com.android.launcher3.util.RunnableList; 166 import com.android.launcher3.util.SplitConfigurationOptions; 167 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; 168 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource; 169 import com.android.launcher3.util.StableViewInfo; 170 import com.android.launcher3.util.StartActivityParams; 171 import com.android.launcher3.util.TouchController; 172 import com.android.launcher3.views.FloatingIconView; 173 import com.android.quickstep.OverviewCommandHelper; 174 import com.android.quickstep.OverviewComponentObserver; 175 import com.android.quickstep.OverviewComponentObserver.OverviewChangeListener; 176 import com.android.quickstep.RecentsModel; 177 import com.android.quickstep.SystemUiProxy; 178 import com.android.quickstep.TaskUtils; 179 import com.android.quickstep.TouchInteractionService.TISBinder; 180 import com.android.quickstep.util.ActiveGestureProtoLogProxy; 181 import com.android.quickstep.util.AsyncClockEventDelegate; 182 import com.android.quickstep.util.LauncherUnfoldAnimationController; 183 import com.android.quickstep.util.QuickstepOnboardingPrefs; 184 import com.android.quickstep.util.SplitSelectStateController; 185 import com.android.quickstep.util.SplitTask; 186 import com.android.quickstep.util.SplitToWorkspaceController; 187 import com.android.quickstep.util.SplitWithKeyboardShortcutController; 188 import com.android.quickstep.util.TISBindHelper; 189 import com.android.quickstep.util.unfold.LauncherUnfoldTransitionController; 190 import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider; 191 import com.android.quickstep.views.FloatingTaskView; 192 import com.android.quickstep.views.OverviewActionsView; 193 import com.android.quickstep.views.RecentsView; 194 import com.android.quickstep.views.RecentsViewContainer; 195 import com.android.quickstep.views.TaskView; 196 import com.android.systemui.animation.back.FlingOnBackAnimationCallback; 197 import com.android.systemui.shared.recents.model.Task; 198 import com.android.systemui.shared.system.ActivityManagerWrapper; 199 import com.android.systemui.unfold.RemoteUnfoldSharedComponent; 200 import com.android.systemui.unfold.UnfoldTransitionFactory; 201 import com.android.systemui.unfold.UnfoldTransitionProgressProvider; 202 import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig; 203 import com.android.systemui.unfold.config.UnfoldTransitionConfig; 204 import com.android.systemui.unfold.dagger.UnfoldMain; 205 import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver; 206 import com.android.systemui.unfold.updates.RotationChangeProvider; 207 import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper; 208 import com.android.wm.shell.shared.bubbles.BubbleBarLocation; 209 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; 210 211 import kotlin.Unit; 212 213 import java.io.FileDescriptor; 214 import java.io.PrintWriter; 215 import java.util.ArrayList; 216 import java.util.Arrays; 217 import java.util.Collections; 218 import java.util.List; 219 import java.util.Objects; 220 import java.util.Optional; 221 import java.util.function.BiConsumer; 222 import java.util.function.Predicate; 223 import java.util.stream.Stream; 224 225 public class QuickstepLauncher extends Launcher implements RecentsViewContainer, 226 SystemShortcut.BubbleActivityStarter { 227 private static final boolean TRACE_LAYOUTS = 228 SystemProperties.getBoolean("persist.debug.trace_layouts", false); 229 private static final String TRACE_RELAYOUT_CLASS = 230 SystemProperties.get("persist.debug.trace_request_layout_class", null); 231 232 protected static final String RING_APPEAR_ANIMATION_PREFIX = "RingAppearAnimation\t"; 233 234 private FixedContainerItems mAllAppsPredictions; 235 private HotseatPredictionController mHotseatPredictionController; 236 private DepthController mDepthController; 237 private QuickstepTransitionManager mAppTransitionManager; 238 239 private OverviewActionsView<?> mActionsView; 240 private TISBindHelper mTISBindHelper; 241 private @Nullable LauncherTaskbarUIController mTaskbarUIController; 242 // Will be updated when dragging from taskbar. 243 private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider; 244 private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController; 245 246 private SplitSelectStateController mSplitSelectStateController; 247 private SplitWithKeyboardShortcutController mSplitWithKeyboardShortcutController; 248 private SplitToWorkspaceController mSplitToWorkspaceController; 249 private BubbleBarLocation mBubbleBarLocation; 250 251 /** 252 * If Launcher restarted while in the middle of an Overview split select, it needs this data to 253 * recover. In all other cases this will remain null. 254 */ 255 private PendingSplitSelectInfo mPendingSplitSelectInfo = null; 256 257 @Nullable 258 private DesktopRecentsTransitionController mDesktopRecentsTransitionController; 259 260 private SafeCloseable mViewCapture; 261 262 private boolean mEnableWidgetDepth; 263 264 private boolean mIsPredictiveBackToHomeInProgress; 265 266 private boolean mCanShowAllAppsEducationView; 267 268 private boolean mIsOverlayVisible; 269 270 private final OverviewChangeListener mOverviewChangeListener = this::onOverviewTargetChanged; 271 272 private final TaskViewRecentsTouchContext mTaskViewRecentsTouchContext = 273 new TaskViewRecentsTouchContext() { 274 @Override 275 public boolean isRecentsInteractive() { 276 return isInState(OVERVIEW) || isInState(OVERVIEW_MODAL_TASK); 277 } 278 279 @Override 280 public boolean isRecentsModal() { 281 return isInState(OVERVIEW_MODAL_TASK); 282 } 283 284 @Override 285 public void onUserControlledAnimationCreated( 286 AnimatorPlaybackController animController) { 287 getStateManager().setCurrentUserControlledAnimation(animController); 288 } 289 }; 290 getLauncher(Context context)291 public static QuickstepLauncher getLauncher(Context context) { 292 return fromContext(context); 293 } 294 295 @Override setupViews()296 protected void setupViews() { 297 getAppWidgetHolder().setOnViewCreationCallback(new QuickstepInteractionHandler(this)); 298 super.setupViews(); 299 300 mActionsView = findViewById(R.id.overview_actions_view); 301 RecentsView<?,?> overviewPanel = getOverviewPanel(); 302 SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(this); 303 mSplitSelectStateController = 304 new SplitSelectStateController(this, getStateManager(), 305 getDepthController(), getStatsLogManager(), 306 systemUiProxy, RecentsModel.INSTANCE.get(this), 307 () -> onStateBack()); 308 if (DesktopModeStatus.canEnterDesktopMode(this)) { 309 mDesktopRecentsTransitionController = new DesktopRecentsTransitionController( 310 getStateManager(), systemUiProxy, getIApplicationThread(), 311 getDepthController()); 312 } 313 overviewPanel.init(mActionsView, mSplitSelectStateController, 314 mDesktopRecentsTransitionController); 315 mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController( 316 this, mSplitSelectStateController); 317 mSplitToWorkspaceController = new SplitToWorkspaceController(this, 318 mSplitSelectStateController); 319 mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize()); 320 mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this)); 321 322 mAppTransitionManager = buildAppTransitionManager(); 323 mAppTransitionManager.registerRemoteAnimations(); 324 mAppTransitionManager.registerRemoteTransitions(); 325 326 mTISBindHelper = new TISBindHelper(this, this::onTISConnected); 327 mDepthController = new DepthController(this); 328 if (DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(this)) { 329 mSplitSelectStateController.initSplitFromDesktopController(this); 330 } 331 mHotseatPredictionController = new HotseatPredictionController(this); 332 333 mEnableWidgetDepth = SystemProperties.getBoolean("ro.launcher.depth.widget", true); 334 getWorkspace().addOverlayCallback(progress -> 335 onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX)); 336 addBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler()); 337 } 338 339 @Override logAppLaunch(StatsLogManager statsLogManager, ItemInfo info, InstanceId instanceId)340 public void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info, 341 InstanceId instanceId) { 342 // If the app launch is from any of the surfaces in AllApps then add the InstanceId from 343 // LiveSearchManager to recreate the AllApps session on the server side. 344 if (mAllAppsSessionLogId != null && ALL_APPS.equals( 345 getStateManager().getCurrentStableState())) { 346 instanceId = mAllAppsSessionLogId; 347 } 348 349 StatsLogger logger = statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId); 350 351 if (mAllAppsPredictions != null 352 && (info.itemType == ITEM_TYPE_APPLICATION 353 || info.itemType == ITEM_TYPE_DEEP_SHORTCUT)) { 354 int count = mAllAppsPredictions.items.size(); 355 for (int i = 0; i < count; i++) { 356 ItemInfo targetInfo = mAllAppsPredictions.items.get(i); 357 if (targetInfo.itemType == info.itemType 358 && targetInfo.user.equals(info.user) 359 && Objects.equals(targetInfo.getIntent(), info.getIntent())) { 360 logger.withRank(i); 361 break; 362 } 363 364 } 365 } 366 logger.log(LAUNCHER_APP_LAUNCH_TAP); 367 368 mHotseatPredictionController.logLaunchedAppRankingInfo(info, instanceId); 369 } 370 371 @Override completeAddShortcut(Intent data, int container, int screenId, int cellX, int cellY, PendingRequestArgs args)372 protected void completeAddShortcut(Intent data, int container, int screenId, int cellX, 373 int cellY, PendingRequestArgs args) { 374 if (container == CONTAINER_HOTSEAT) { 375 mHotseatPredictionController.onDeferredDrop(cellX, cellY); 376 } 377 super.completeAddShortcut(data, container, screenId, cellX, cellY, args); 378 } 379 380 @Override createAccessibilityDelegate()381 protected LauncherAccessibilityDelegate createAccessibilityDelegate() { 382 return new QuickstepAccessibilityDelegate(this); 383 } 384 385 /** 386 * Returns Prediction controller for hybrid hotseat 387 */ getHotseatPredictionController()388 public HotseatPredictionController getHotseatPredictionController() { 389 return mHotseatPredictionController; 390 } 391 392 @Override enableHotseatEdu(boolean enable)393 public void enableHotseatEdu(boolean enable) { 394 super.enableHotseatEdu(enable); 395 mHotseatPredictionController.enableHotseatEdu(enable); 396 } 397 398 /** 399 * Builds the {@link QuickstepTransitionManager} instance to use for managing transitions. 400 */ buildAppTransitionManager()401 protected QuickstepTransitionManager buildAppTransitionManager() { 402 return new QuickstepTransitionManager(this); 403 } 404 405 @Override onConfigurationChanged(Configuration newConfig)406 public void onConfigurationChanged(Configuration newConfig) { 407 super.onConfigurationChanged(newConfig); 408 onStateOrResumeChanging(false /* inTransition */); 409 } 410 411 @Override startActivitySafely(View v, Intent intent, ItemInfo item)412 public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) { 413 // Only pause is taskbar controller is not present until the transition (if it exists) ends 414 mHotseatPredictionController.setPauseUIUpdate(getTaskbarUIController() == null); 415 PredictionRowView<?> predictionRowView = 416 getAppsView().getFloatingHeaderView().findFixedRowByType(PredictionRowView.class); 417 // Pause the prediction row updates until the transition (if it exists) ends. 418 predictionRowView.setPredictionUiUpdatePaused(true); 419 RunnableList result = super.startActivitySafely(v, intent, item); 420 if (result == null) { 421 mHotseatPredictionController.setPauseUIUpdate(false); 422 predictionRowView.setPredictionUiUpdatePaused(false); 423 } else { 424 result.add(() -> { 425 mHotseatPredictionController.setPauseUIUpdate(false); 426 predictionRowView.setPredictionUiUpdatePaused(false); 427 }); 428 } 429 return result; 430 } 431 432 @Override startBinding()433 public void startBinding() { 434 super.startBinding(); 435 mHotseatPredictionController.verifyUIUpdateNotPaused(); 436 } 437 438 @Override onActivityFlagsChanged(int changeBits)439 protected void onActivityFlagsChanged(int changeBits) { 440 if ((changeBits & ACTIVITY_STATE_STARTED) != 0) { 441 mDepthController.setActivityStarted(isStarted()); 442 } 443 444 if ((changeBits & ACTIVITY_STATE_RESUMED) != 0) { 445 if (!FeatureFlags.enableHomeTransitionListener() && mTaskbarUIController != null) { 446 mTaskbarUIController.onLauncherVisibilityChanged(hasBeenResumed()); 447 } 448 } 449 450 super.onActivityFlagsChanged(changeBits); 451 if ((changeBits & (ACTIVITY_STATE_DEFERRED_RESUMED | ACTIVITY_STATE_STARTED 452 | ACTIVITY_STATE_USER_ACTIVE | ACTIVITY_STATE_TRANSITION_ACTIVE)) != 0) { 453 onStateOrResumeChanging((getActivityFlags() & ACTIVITY_STATE_TRANSITION_ACTIVE) == 0); 454 } 455 } 456 457 @Override showAllAppsFromIntent(boolean alreadyOnHome)458 protected void showAllAppsFromIntent(boolean alreadyOnHome) { 459 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY); 460 super.showAllAppsFromIntent(alreadyOnHome); 461 } 462 onItemClicked(View view)463 protected void onItemClicked(View view) { 464 if (!mSplitToWorkspaceController.handleSecondAppSelectionForSplit(view)) { 465 super.getItemOnClickListener().onClick(view); 466 } 467 } 468 469 @Override getItemOnClickListener()470 public View.OnClickListener getItemOnClickListener() { 471 return this::onItemClicked; 472 } 473 474 @Override getSupportedShortcuts()475 public Stream<SystemShortcut.Factory> getSupportedShortcuts() { 476 // Order matters as it affects order of appearance in popup container 477 List<SystemShortcut.Factory> shortcuts = new ArrayList(Arrays.asList( 478 APP_INFO, WellbeingModel.SHORTCUT_FACTORY, mHotseatPredictionController)); 479 480 shortcuts.addAll(getSplitShortcuts()); 481 shortcuts.add(WIDGETS); 482 shortcuts.add(INSTALL); 483 if (Flags.enablePrivateSpaceInstallShortcut()) { 484 shortcuts.add(PRIVATE_PROFILE_INSTALL); 485 } 486 if (Flags.enableShortcutDontSuggestApp()) { 487 shortcuts.add(DONT_SUGGEST_APP); 488 } 489 if (Flags.enablePrivateSpace()) { 490 shortcuts.add(UNINSTALL_APP); 491 } 492 if (BubbleAnythingFlagHelper.enableCreateAnyBubble()) { 493 shortcuts.add(BUBBLE_SHORTCUT); 494 } 495 return shortcuts.stream(); 496 } 497 getSplitShortcuts()498 private List<SystemShortcut.Factory<QuickstepLauncher>> getSplitShortcuts() { 499 if (!mDeviceProfile.isTablet || mSplitSelectStateController.isSplitSelectActive()) { 500 return Collections.emptyList(); 501 } 502 RecentsView recentsView = getOverviewPanel(); 503 // TODO(b/266482558): Pull it out of PagedOrentationHandler for split from workspace. 504 List<SplitPositionOption> positions = 505 recentsView.getPagedOrientationHandler().getSplitPositionOptions( 506 mDeviceProfile); 507 List<SystemShortcut.Factory<QuickstepLauncher>> splitShortcuts = new ArrayList<>(); 508 for (SplitPositionOption position : positions) { 509 splitShortcuts.add(getSplitSelectShortcutByPosition(position)); 510 } 511 return splitShortcuts; 512 } 513 514 /** 515 * Recents logic that triggers when launcher state changes or launcher activity stops/resumes. 516 */ onStateOrResumeChanging(boolean inTransition)517 private void onStateOrResumeChanging(boolean inTransition) { 518 LauncherState state = getStateManager().getState(); 519 boolean started = ((getActivityFlags() & ACTIVITY_STATE_STARTED)) != 0; 520 if (started) { 521 DeviceProfile profile = getDeviceProfile(); 522 boolean visible = (state == NORMAL || state == OVERVIEW) 523 && isUserActive() 524 && !profile.isVerticalBarLayout() 525 && !mIsOverlayVisible; 526 SystemUiProxy.INSTANCE.get(this) 527 .setLauncherKeepClearAreaHeight(visible, profile.hotseatBarSizePx); 528 } 529 if (state == NORMAL && !inTransition) { 530 ((RecentsView) getOverviewPanel()).setSwipeDownShouldLaunchApp(false); 531 } 532 } 533 534 @Override onOverlayVisibilityChanged(boolean visible)535 public void onOverlayVisibilityChanged(boolean visible) { 536 super.onOverlayVisibilityChanged(visible); 537 mIsOverlayVisible = visible; 538 } 539 540 @Override bindExtraContainerItems(FixedContainerItems item)541 public void bindExtraContainerItems(FixedContainerItems item) { 542 if (item.containerId == Favorites.CONTAINER_PREDICTION) { 543 mAllAppsPredictions = item; 544 PredictionRowView<?> predictionRowView = 545 getAppsView().getFloatingHeaderView().findFixedRowByType( 546 PredictionRowView.class); 547 predictionRowView.setPredictedApps(item.items); 548 } else if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) { 549 mHotseatPredictionController.setPredictedItems(item); 550 } else if (item.containerId == Favorites.CONTAINER_WIDGETS_PREDICTION) { 551 getWidgetPickerDataProvider().setWidgetRecommendations(item.items); 552 } 553 } 554 555 @Override bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher)556 public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { 557 super.bindWorkspaceComponentsRemoved(matcher); 558 mHotseatPredictionController.onModelItemsRemoved(matcher); 559 } 560 561 @Override onDestroy()562 public void onDestroy() { 563 if (mAppTransitionManager != null) { 564 mAppTransitionManager.onActivityDestroyed(); 565 } 566 mAppTransitionManager = null; 567 mIsPredictiveBackToHomeInProgress = false; 568 569 if (mUnfoldTransitionProgressProvider != null) { 570 SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null); 571 mUnfoldTransitionProgressProvider.destroy(); 572 } 573 574 OverviewComponentObserver.INSTANCE.get(this) 575 .removeOverviewChangeListener(mOverviewChangeListener); 576 mTISBindHelper.onDestroy(); 577 578 if (mLauncherUnfoldAnimationController != null) { 579 mLauncherUnfoldAnimationController.onDestroy(); 580 } 581 582 if (mSplitSelectStateController != null) { 583 mSplitSelectStateController.onDestroy(); 584 } 585 586 RecentsView recentsView = getOverviewPanel(); 587 if (recentsView != null) { 588 recentsView.destroy(); 589 } 590 591 super.onDestroy(); 592 mHotseatPredictionController.destroy(); 593 if (mViewCapture != null) mViewCapture.close(); 594 removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler()); 595 } 596 597 @Override onStateSetEnd(LauncherState state)598 public void onStateSetEnd(LauncherState state) { 599 super.onStateSetEnd(state); 600 handlePendingActivityRequest(); 601 602 switch (state.ordinal) { 603 case HINT_STATE_ORDINAL: { 604 Workspace<?> workspace = getWorkspace(); 605 getStateManager().goToState(NORMAL); 606 if (workspace.getNextPage() != Workspace.DEFAULT_PAGE) { 607 workspace.post(workspace::moveToDefaultScreen); 608 } 609 break; 610 } 611 case HINT_STATE_TWO_BUTTON_ORDINAL: { 612 getStateManager().goToState(OVERVIEW); 613 getDragLayer().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); 614 break; 615 } 616 case OVERVIEW_STATE_ORDINAL: { 617 RecentsView rv = getOverviewPanel(); 618 sendCustomAccessibilityEvent( 619 rv.getPageAt(rv.getCurrentPage()), TYPE_VIEW_FOCUSED, null); 620 break; 621 } 622 case QUICK_SWITCH_STATE_ORDINAL: { 623 RecentsView rv = getOverviewPanel(); 624 TaskView currentPageTask = rv.getCurrentPageTaskView(); 625 TaskView fallbackTask = rv.getFirstTaskView(); 626 if (currentPageTask != null || fallbackTask != null) { 627 TaskView taskToLaunch = currentPageTask; 628 if (currentPageTask == null) { 629 taskToLaunch = fallbackTask; 630 ActiveGestureProtoLogProxy.logQuickSwitchFromHomeFallback( 631 rv.getCurrentPage()); 632 } 633 taskToLaunch.launchWithoutAnimation(success -> { 634 if (!success) { 635 getStateManager().goToState(OVERVIEW); 636 } else { 637 getStateManager().moveToRestState(); 638 } 639 return Unit.INSTANCE; 640 }); 641 } else { 642 ActiveGestureProtoLogProxy.logQuickSwitchFromHomeFailed(rv.getCurrentPage()); 643 getStateManager().goToState(NORMAL); 644 } 645 break; 646 } 647 648 } 649 } 650 651 @Override createTouchControllers()652 public TouchController[] createTouchControllers() { 653 NavigationMode mode = DisplayController.getNavigationMode(this); 654 655 ArrayList<TouchController> list = new ArrayList<>(); 656 list.add(getDragController()); 657 BiConsumer<AnimatorSet, Long> splitAnimator = (animatorSet, duration) -> 658 animatorSet.play(mSplitSelectStateController.getSplitAnimationController() 659 .createPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_HOME, 660 duration)); 661 switch (mode) { 662 case NO_BUTTON: 663 list.add(new NoButtonQuickSwitchTouchController(this)); 664 list.add(new NavBarToHomeTouchController(this, splitAnimator)); 665 list.add(new NoButtonNavbarToOverviewTouchController(this, splitAnimator)); 666 break; 667 case TWO_BUTTONS: 668 list.add(new TwoButtonNavbarTouchController(this)); 669 list.add(getDeviceProfile().isVerticalBarLayout() 670 ? new TransposedQuickSwitchTouchController(this) 671 : new QuickSwitchTouchController(this)); 672 list.add(new PortraitStatesTouchController(this)); 673 break; 674 case THREE_BUTTONS: 675 list.add(new NoButtonQuickSwitchTouchController(this)); 676 list.add(new NavBarToHomeTouchController(this, splitAnimator)); 677 list.add(new NoButtonNavbarToOverviewTouchController(this, splitAnimator)); 678 list.add(new PortraitStatesTouchController(this)); 679 break; 680 default: 681 list.add(new PortraitStatesTouchController(this)); 682 break; 683 } 684 685 if (!getDeviceProfile().isMultiWindowMode) { 686 list.add(new StatusBarTouchController(this)); 687 } 688 689 if (enableExpressiveDismissTaskMotion()) { 690 list.add(new TaskViewLaunchTouchController<>(this, mTaskViewRecentsTouchContext)); 691 list.add(new TaskViewDismissTouchController<>(this, mTaskViewRecentsTouchContext)); 692 } else { 693 list.add(new TaskViewTouchControllerDeprecated<>(this, mTaskViewRecentsTouchContext)); 694 } 695 return list.toArray(new TouchController[list.size()]); 696 } 697 698 @Override createAtomicAnimationFactory()699 public AtomicAnimationFactory createAtomicAnimationFactory() { 700 return new QuickstepAtomicAnimationFactory(this); 701 } 702 703 @Override onCreate(Bundle savedInstanceState)704 protected void onCreate(Bundle savedInstanceState) { 705 super.onCreate(savedInstanceState); 706 if (savedInstanceState != null) { 707 mPendingSplitSelectInfo = ObjectWrapper.unwrap( 708 savedInstanceState.getIBinder(PENDING_SPLIT_SELECT_INFO)); 709 } 710 addMultiWindowModeChangedListener(mDepthController); 711 initUnfoldTransitionProgressProvider(); 712 mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow()); 713 getWindow().addPrivateFlags(PRIVATE_FLAG_OPTIMIZE_MEASURE); 714 QuickstepOnboardingPrefs.setup(this); 715 View.setTraceLayoutSteps(TRACE_LAYOUTS); 716 View.setTracedRequestLayoutClassClass(TRACE_RELAYOUT_CLASS); 717 OverviewComponentObserver.INSTANCE.get(this) 718 .addOverviewChangeListener(mOverviewChangeListener); 719 } 720 721 @Override initDeviceProfile(InvariantDeviceProfile idp)722 protected boolean initDeviceProfile(InvariantDeviceProfile idp) { 723 final boolean ret = super.initDeviceProfile(idp); 724 mDeviceProfile.isPredictiveBackSwipe = 725 getApplicationInfo().isOnBackInvokedCallbackEnabled(); 726 if (ret) { 727 SystemUiProxy.INSTANCE.get(this).setLauncherAppIconSize(mDeviceProfile.iconSizePx); 728 } 729 return ret; 730 } 731 732 @Override startSplitSelection(SplitSelectSource splitSelectSource)733 public void startSplitSelection(SplitSelectSource splitSelectSource) { 734 RecentsView recentsView = getOverviewPanel(); 735 // Check if there is already an instance of this app running, if so, initiate the split 736 // using that. 737 mSplitSelectStateController.findLastActiveTasksAndRunCallback( 738 Collections.singletonList(splitSelectSource.getItemInfo().getComponentKey()), 739 false /* findExactPairMatch */, 740 foundTasks -> { 741 @Nullable Task foundTask = foundTasks[0]; 742 boolean taskWasFound = foundTask != null; 743 splitSelectSource.alreadyRunningTaskId = taskWasFound 744 ? foundTask.key.id 745 : INVALID_TASK_ID; 746 startSplitToHome(splitSelectSource); 747 } 748 ); 749 } 750 751 /** TODO(b/266482558) Migrate into SplitSelectStateController or someplace split specific. */ startSplitToHome(SplitSelectSource source)752 private void startSplitToHome(SplitSelectSource source) { 753 AbstractFloatingView.closeAllOpenViews(this); 754 int splitPlaceholderSize = getResources().getDimensionPixelSize( 755 R.dimen.split_placeholder_size); 756 int splitPlaceholderInset = getResources().getDimensionPixelSize( 757 R.dimen.split_placeholder_inset); 758 Rect tempRect = new Rect(); 759 760 mSplitSelectStateController.setInitialTaskSelect(source.intent, 761 source.position.stagePosition, source.getItemInfo(), source.splitEvent, 762 source.alreadyRunningTaskId); 763 764 RecentsView recentsView = getOverviewPanel(); 765 recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds( 766 splitPlaceholderSize, splitPlaceholderInset, getDeviceProfile(), 767 mSplitSelectStateController.getActiveSplitStagePosition(), tempRect); 768 769 PendingAnimation anim = new PendingAnimation(TABLET_HOME_TO_SPLIT.getDuration()); 770 RectF startingTaskRect = new RectF(); 771 final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(this, 772 source.getView(), null /* thumbnail */, source.getDrawable(), startingTaskRect); 773 floatingTaskView.setAlpha(1); 774 floatingTaskView.addStagingAnimation(anim, startingTaskRect, tempRect, 775 false /* fadeWithThumbnail */, true /* isStagedTask */); 776 floatingTaskView.setOnClickListener(view -> 777 mSplitSelectStateController.getSplitAnimationController(). 778 playAnimPlaceholderToFullscreen(this, view, Optional.empty())); 779 floatingTaskView.setContentDescription(source.getItemInfo().contentDescription); 780 781 mSplitSelectStateController.setFirstFloatingTaskView(floatingTaskView); 782 anim.addListener(new AnimatorListenerAdapter() { 783 @Override 784 public void onAnimationCancel(Animator animation) { 785 getDragLayer().removeView(floatingTaskView); 786 mSplitSelectStateController.getSplitAnimationController() 787 .removeSplitInstructionsView(QuickstepLauncher.this); 788 mSplitSelectStateController.resetState(); 789 } 790 }); 791 anim.add(mSplitSelectStateController.getSplitAnimationController() 792 .getShowSplitInstructionsAnim(this).buildAnim()); 793 anim.buildAnim().start(); 794 } 795 796 @Override isSplitSelectionActive()797 public boolean isSplitSelectionActive() { 798 if (mSplitSelectStateController == null) { 799 return false; 800 } 801 return mSplitSelectStateController.isSplitSelectActive(); 802 } 803 areBothSplitAppsConfirmed()804 public boolean areBothSplitAppsConfirmed() { 805 return mSplitSelectStateController.isBothSplitAppsConfirmed(); 806 } 807 808 @Override onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState)809 public void onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState) { 810 if (mTaskbarUIController != null) { 811 mTaskbarUIController.onStateTransitionCompletedAfterSwipeToHome(finalState); 812 } 813 } 814 815 @Override onResume()816 protected void onResume() { 817 super.onResume(); 818 819 if (mLauncherUnfoldAnimationController != null) { 820 mLauncherUnfoldAnimationController.onResume(); 821 } 822 823 if (mTaskbarUIController != null && FeatureFlags.enableHomeTransitionListener()) { 824 mTaskbarUIController.onLauncherResume(); 825 } 826 } 827 828 @Override onPause()829 protected void onPause() { 830 if (mLauncherUnfoldAnimationController != null) { 831 mLauncherUnfoldAnimationController.onPause(); 832 } 833 834 super.onPause(); 835 836 // If Launcher pauses before both split apps are selected, exit split screen. 837 if (!mSplitSelectStateController.isBothSplitAppsConfirmed() && 838 !mSplitSelectStateController.isLaunchingFirstAppFullscreen()) { 839 mSplitSelectStateController 840 .logExitReason(LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED); 841 mSplitSelectStateController.getSplitAnimationController() 842 .playPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED); 843 } 844 845 if (mTaskbarUIController != null && FeatureFlags.enableHomeTransitionListener()) { 846 mTaskbarUIController.onLauncherPause(); 847 } 848 } 849 850 @Override onStop()851 protected void onStop() { 852 super.onStop(); 853 if (mTaskbarUIController != null && FeatureFlags.enableHomeTransitionListener()) { 854 mTaskbarUIController.onLauncherStop(); 855 } 856 } 857 858 @Override onNewIntent(Intent intent)859 protected void onNewIntent(Intent intent) { 860 super.onNewIntent(intent); 861 OverviewCommandHelper overviewCommandHelper = mTISBindHelper.getOverviewCommandHelper(); 862 if (overviewCommandHelper != null) { 863 overviewCommandHelper.clearPendingCommands(); 864 } 865 } 866 getAppTransitionManager()867 public QuickstepTransitionManager getAppTransitionManager() { 868 return mAppTransitionManager; 869 } 870 871 @Override onEnterAnimationComplete()872 public void onEnterAnimationComplete() { 873 super.onEnterAnimationComplete(); 874 // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled 875 // as a part of quickstep, so that high-res thumbnails can load the next time we enter 876 // overview 877 RecentsModel.INSTANCE.get(this).getThumbnailCache() 878 .getHighResLoadingState().setVisible(true); 879 } 880 881 @Override handleGestureContract(Intent intent)882 protected void handleGestureContract(Intent intent) { 883 if (FeatureFlags.SEPARATE_RECENTS_ACTIVITY.get()) { 884 super.handleGestureContract(intent); 885 } 886 } 887 888 @Override onTrimMemory(int level)889 public void onTrimMemory(int level) { 890 super.onTrimMemory(level); 891 RecentsModel.INSTANCE.get(this).onTrimMemory(level); 892 } 893 894 @Override onUiChangedWhileSleeping()895 public void onUiChangedWhileSleeping() { 896 // Remove the snapshot because the content view may have obvious changes. 897 UI_HELPER_EXECUTOR.execute( 898 () -> ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(this)); 899 } 900 901 @Override onAllAppsTransition(float progress)902 public void onAllAppsTransition(float progress) { 903 super.onAllAppsTransition(progress); 904 onTaskbarInAppDisplayProgressUpdate(progress, ALL_APPS_PAGE_PROGRESS_INDEX); 905 } 906 907 @Override onWidgetsTransition(float progress)908 public void onWidgetsTransition(float progress) { 909 super.onWidgetsTransition(progress); 910 onTaskbarInAppDisplayProgressUpdate(progress, WIDGETS_PAGE_PROGRESS_INDEX); 911 if (mEnableWidgetDepth) { 912 getDepthController().widgetDepth.setValue(Utilities.mapToRange( 913 progress, 0f, 1f, 0f, getDeviceProfile().bottomSheetDepth, EMPHASIZED)); 914 } 915 } 916 917 @Override dispatchKeyEvent(KeyEvent event)918 public boolean dispatchKeyEvent(KeyEvent event) { 919 return tryHandleBackKey(event) || super.dispatchKeyEvent(event); 920 } 921 922 // TODO (b/267248420) Once the recents input consumer has been removed, there is no need to 923 // handle the back key specially. tryHandleBackKey(KeyEvent event)924 private boolean tryHandleBackKey(KeyEvent event) { 925 // Unlike normal activity, recents can receive input event from InputConsumer, so the input 926 // event won't go through ViewRootImpl#InputStage#onProcess. 927 // So when receive back key, try to do the same check thing in 928 // ViewRootImpl#NativePreImeInputStage#onProcess 929 if (event.getKeyCode() != KeyEvent.KEYCODE_BACK 930 || event.getAction() != KeyEvent.ACTION_UP || event.isCanceled()) { 931 return false; 932 } 933 934 getOnBackAnimationCallback().onBackInvoked(); 935 return true; 936 } 937 938 @Override registerBackDispatcher()939 protected void registerBackDispatcher() { 940 getOnBackInvokedDispatcher().registerOnBackInvokedCallback( 941 OnBackInvokedDispatcher.PRIORITY_DEFAULT, 942 new FlingOnBackAnimationCallback() { 943 944 @Nullable OnBackAnimationCallback mActiveOnBackAnimationCallback; 945 946 @Override 947 public void onBackStartedCompat(@NonNull BackEvent backEvent) { 948 if (mActiveOnBackAnimationCallback != null) { 949 mActiveOnBackAnimationCallback.onBackCancelled(); 950 } 951 mActiveOnBackAnimationCallback = getOnBackAnimationCallback(); 952 mActiveOnBackAnimationCallback.onBackStarted(backEvent); 953 } 954 955 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 956 @Override 957 public void onBackInvokedCompat() { 958 // Recreate mActiveOnBackAnimationCallback if necessary to avoid NPE 959 // because: 960 // 1. b/260636433: In 3-button-navigation mode, onBackStarted() is not 961 // called on ACTION_DOWN before onBackInvoked() is called in ACTION_UP. 962 // 2. Launcher#onBackPressed() will call onBackInvoked() without calling 963 // onBackInvoked() beforehand. 964 if (mActiveOnBackAnimationCallback == null) { 965 mActiveOnBackAnimationCallback = getOnBackAnimationCallback(); 966 } 967 mActiveOnBackAnimationCallback.onBackInvoked(); 968 mActiveOnBackAnimationCallback = null; 969 TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked"); 970 } 971 972 @Override 973 public void onBackProgressedCompat(@NonNull BackEvent backEvent) { 974 if (!FeatureFlags.IS_STUDIO_BUILD 975 && mActiveOnBackAnimationCallback == null) { 976 return; 977 } 978 mActiveOnBackAnimationCallback.onBackProgressed(backEvent); 979 } 980 981 @Override 982 public void onBackCancelledCompat() { 983 if (!FeatureFlags.IS_STUDIO_BUILD 984 && mActiveOnBackAnimationCallback == null) { 985 return; 986 } 987 mActiveOnBackAnimationCallback.onBackCancelled(); 988 mActiveOnBackAnimationCallback = null; 989 } 990 }); 991 } 992 onTaskbarInAppDisplayProgressUpdate(float progress, int flag)993 private void onTaskbarInAppDisplayProgressUpdate(float progress, int flag) { 994 TaskbarManager taskbarManager = mTISBindHelper.getTaskbarManager(); 995 if (taskbarManager == null 996 || taskbarManager.getCurrentActivityContext() == null 997 || mTaskbarUIController == null) { 998 return; 999 } 1000 mTaskbarUIController.onTaskbarInAppDisplayProgressUpdate(progress, flag); 1001 } 1002 1003 @Override startIntentSenderForResult(IntentSender intent, int requestCode, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options)1004 public void startIntentSenderForResult(IntentSender intent, int requestCode, 1005 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) { 1006 if (requestCode != -1) { 1007 mPendingActivityRequestCode = requestCode; 1008 StartActivityParams params = new StartActivityParams(this, requestCode); 1009 params.intentSender = intent; 1010 params.fillInIntent = fillInIntent; 1011 params.flagsMask = flagsMask; 1012 params.flagsValues = flagsValues; 1013 params.extraFlags = extraFlags; 1014 params.options = options; 1015 startActivity(ProxyActivityStarter.getLaunchIntent(this, params)); 1016 } else { 1017 super.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask, 1018 flagsValues, extraFlags, options); 1019 } 1020 } 1021 1022 @Override startActivityForResult(Intent intent, int requestCode, Bundle options)1023 public void startActivityForResult(Intent intent, int requestCode, Bundle options) { 1024 if (requestCode != -1) { 1025 mPendingActivityRequestCode = requestCode; 1026 StartActivityParams params = new StartActivityParams(this, requestCode); 1027 params.intent = intent; 1028 params.options = options; 1029 startActivity(ProxyActivityStarter.getLaunchIntent(this, params)); 1030 } else { 1031 super.startActivityForResult(intent, requestCode, options); 1032 } 1033 } 1034 1035 @Override setResumed()1036 public void setResumed() { 1037 DesktopVisibilityController desktopVisibilityController = 1038 DesktopVisibilityController.INSTANCE.get(this); 1039 if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue() 1040 && desktopVisibilityController.isInDesktopModeAndNotInOverview(getDisplayId()) 1041 && !desktopVisibilityController.isRecentsGestureInProgress()) { 1042 // Return early to skip setting activity to appear as resumed 1043 // TODO: b/333533253 - Remove after flag rollout 1044 return; 1045 } 1046 super.setResumed(); 1047 } 1048 1049 @Override onDeferredResumed()1050 protected void onDeferredResumed() { 1051 super.onDeferredResumed(); 1052 handlePendingActivityRequest(); 1053 } 1054 handlePendingActivityRequest()1055 private void handlePendingActivityRequest() { 1056 if (mPendingActivityRequestCode != -1 && isInState(NORMAL) 1057 && ((getActivityFlags() & ACTIVITY_STATE_DEFERRED_RESUMED) != 0)) { 1058 // Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher. 1059 onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null); 1060 // ProxyActivityStarter is started with clear task to reset the task after which it 1061 // removes the task itself. 1062 startActivity(ProxyActivityStarter.getLaunchIntent(this, null)); 1063 } 1064 } 1065 onOverviewTargetChanged(boolean isHomeAndOverviewSame)1066 private void onOverviewTargetChanged(boolean isHomeAndOverviewSame) { 1067 QuickstepTransitionManager transitionManager = getAppTransitionManager(); 1068 if (transitionManager != null) { 1069 transitionManager.onOverviewTargetChange(); 1070 } 1071 } 1072 onTISConnected(TISBinder binder)1073 private void onTISConnected(TISBinder binder) { 1074 TaskbarManager taskbarManager = mTISBindHelper.getTaskbarManager(); 1075 if (taskbarManager != null) { 1076 taskbarManager.setActivity(this); 1077 } 1078 mTISBindHelper.setPredictiveBackToHomeInProgress(mIsPredictiveBackToHomeInProgress); 1079 } 1080 1081 @Override runOnBindToTouchInteractionService(Runnable r)1082 public void runOnBindToTouchInteractionService(Runnable r) { 1083 mTISBindHelper.runOnBindToTouchInteractionService(r); 1084 } 1085 initUnfoldTransitionProgressProvider()1086 private void initUnfoldTransitionProgressProvider() { 1087 if (!enableUnfoldStateAnimation()) { 1088 final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig(); 1089 if (config.isEnabled()) { 1090 initRemotelyCalculatedUnfoldAnimation(config); 1091 } 1092 } else { 1093 ProxyUnfoldTransitionProvider provider = 1094 SystemUiProxy.INSTANCE.get(this).getUnfoldTransitionProvider(); 1095 if (provider != null) { 1096 new LauncherUnfoldTransitionController(this, provider); 1097 } 1098 } 1099 } 1100 1101 /** Receives animation progress from sysui process. */ initRemotelyCalculatedUnfoldAnimation(UnfoldTransitionConfig config)1102 private void initRemotelyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) { 1103 RemoteUnfoldSharedComponent unfoldComponent = 1104 UnfoldTransitionFactory.createRemoteUnfoldSharedComponent( 1105 /* context= */ this, 1106 config, 1107 getMainExecutor(), 1108 getMainThreadHandler(), 1109 /* backgroundExecutor= */ UI_HELPER_EXECUTOR, 1110 /* bgHandler= */ UI_HELPER_EXECUTOR.getHandler(), 1111 /* tracingTagPrefix= */ "launcher", 1112 getSystemService(DisplayManager.class) 1113 ); 1114 1115 final RemoteUnfoldTransitionReceiver remoteUnfoldTransitionProgressProvider = 1116 unfoldComponent.getRemoteTransitionProgress().orElseThrow( 1117 () -> new IllegalStateException( 1118 "Trying to create getRemoteTransitionProgress when the transition " 1119 + "is disabled")); 1120 mUnfoldTransitionProgressProvider = remoteUnfoldTransitionProgressProvider; 1121 1122 SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener( 1123 remoteUnfoldTransitionProgressProvider); 1124 1125 initUnfoldAnimationController(mUnfoldTransitionProgressProvider, 1126 unfoldComponent.getRotationChangeProvider()); 1127 } 1128 initUnfoldAnimationController(UnfoldTransitionProgressProvider progressProvider, @UnfoldMain RotationChangeProvider rotationChangeProvider)1129 private void initUnfoldAnimationController(UnfoldTransitionProgressProvider progressProvider, 1130 @UnfoldMain RotationChangeProvider rotationChangeProvider) { 1131 mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController( 1132 /* launcher= */ this, 1133 getWindowManager(), 1134 progressProvider, 1135 rotationChangeProvider 1136 ); 1137 } 1138 1139 @Override setTaskbarUIController(@ullable TaskbarUIController taskbarUIController)1140 public void setTaskbarUIController(@Nullable TaskbarUIController taskbarUIController) { 1141 mTaskbarUIController = (LauncherTaskbarUIController) taskbarUIController; 1142 } 1143 1144 @Override getTaskbarUIController()1145 public @Nullable LauncherTaskbarUIController getTaskbarUIController() { 1146 return mTaskbarUIController; 1147 } 1148 1149 /** Provides the translation X for the hotseat item. */ getHotseatItemTranslationX(ItemInfo itemInfo)1150 public int getHotseatItemTranslationX(ItemInfo itemInfo) { 1151 int translationX = 0; 1152 if (isBubbleBarEnabled() && mBubbleBarLocation != null) { 1153 boolean isBubblesOnLeft = mBubbleBarLocation.isOnLeft(isRtl(getResources())); 1154 translationX += mDeviceProfile 1155 .getHotseatTranslationXForNavBar(this, isBubblesOnLeft); 1156 } 1157 if (isBubbleBarEnabled() 1158 && mDeviceProfile.shouldAdjustHotseatForBubbleBar(asContext(), hasBubbles())) { 1159 translationX += (int) mDeviceProfile 1160 .getHotseatAdjustedTranslation(asContext(), itemInfo.cellX); 1161 } 1162 return translationX; 1163 } 1164 getSplitToWorkspaceController()1165 public SplitToWorkspaceController getSplitToWorkspaceController() { 1166 return mSplitToWorkspaceController; 1167 } 1168 1169 @Override handleSplitAnimationGoingToHome(StatsLogManager.EventEnum splitDismissReason)1170 protected void handleSplitAnimationGoingToHome(StatsLogManager.EventEnum splitDismissReason) { 1171 super.handleSplitAnimationGoingToHome(splitDismissReason); 1172 mSplitSelectStateController.getSplitAnimationController() 1173 .playPlaceholderDismissAnim(this, splitDismissReason); 1174 } 1175 1176 @Override dismissSplitSelection(StatsLogManager.LauncherEvent splitDismissEvent)1177 public void dismissSplitSelection(StatsLogManager.LauncherEvent splitDismissEvent) { 1178 super.dismissSplitSelection(splitDismissEvent); 1179 mSplitSelectStateController.getSplitAnimationController() 1180 .playPlaceholderDismissAnim(this, splitDismissEvent); 1181 } 1182 1183 @Override getActionsView()1184 public OverviewActionsView<?> getActionsView() { 1185 return mActionsView; 1186 } 1187 1188 @Override closeOpenViews(boolean animate)1189 protected void closeOpenViews(boolean animate) { 1190 super.closeOpenViews(animate); 1191 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY); 1192 } 1193 1194 @Override collectStateHandlers(List<StateHandler<LauncherState>> out)1195 public void collectStateHandlers(List<StateHandler<LauncherState>> out) { 1196 super.collectStateHandlers(out); 1197 out.add(getDepthController()); 1198 out.add(new RecentsViewStateController(this)); 1199 } 1200 getDepthController()1201 public DepthController getDepthController() { 1202 return mDepthController; 1203 } 1204 1205 @Nullable getUnfoldTransitionProgressProvider()1206 public UnfoldTransitionProgressProvider getUnfoldTransitionProgressProvider() { 1207 return mUnfoldTransitionProgressProvider; 1208 } 1209 1210 @Override supportsAdaptiveIconAnimation(View clickedView)1211 public boolean supportsAdaptiveIconAnimation(View clickedView) { 1212 return true; 1213 } 1214 1215 @Override getNormalOverviewScaleAndOffset()1216 public float[] getNormalOverviewScaleAndOffset() { 1217 return DisplayController.getNavigationMode(this).hasGestures 1218 ? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET}; 1219 } 1220 1221 @Override finishBindingItems(IntSet pagesBoundFirst)1222 public void finishBindingItems(IntSet pagesBoundFirst) { 1223 super.finishBindingItems(pagesBoundFirst); 1224 // Instantiate and initialize WellbeingModel now that its loading won't interfere with 1225 // populating workspace. 1226 // TODO: Find a better place for this 1227 WellbeingModel.INSTANCE.get(this); 1228 1229 if (mLauncherUnfoldAnimationController != null) { 1230 // This is needed in case items are rebound while the unfold animation is in progress. 1231 mLauncherUnfoldAnimationController.updateRegisteredViewsIfNeeded(); 1232 } 1233 } 1234 1235 @NonNull 1236 @Override getActivityLaunchOptions(View v, @Nullable ItemInfo item)1237 public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { 1238 ActivityOptionsWrapper activityOptions = mAppTransitionManager.getActivityLaunchOptions( 1239 v, item != null ? item : (ItemInfo) v.getTag()); 1240 if (mLastTouchUpTime > 0) { 1241 activityOptions.options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER, 1242 mLastTouchUpTime); 1243 } 1244 if (item != null && (item.animationType == DEFAULT_NO_ICON 1245 || item.animationType == VIEW_BACKGROUND)) { 1246 activityOptions.options.setSplashScreenStyle( 1247 SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR); 1248 } else { 1249 activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); 1250 } 1251 activityOptions.options.setLaunchDisplayId( 1252 (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId() 1253 : Display.DEFAULT_DISPLAY); 1254 activityOptions.options.setPendingIntentBackgroundActivityStartMode( 1255 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); 1256 return activityOptions; 1257 } 1258 1259 @Override makeDefaultActivityOptions(int splashScreenStyle)1260 public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) { 1261 RunnableList callbacks = new RunnableList(); 1262 ActivityOptions options = ActivityOptions.makeCustomAnimation(this, 0, 0); 1263 options.setSplashScreenStyle(splashScreenStyle); 1264 options.setPendingIntentBackgroundActivityStartMode( 1265 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); 1266 1267 IRemoteCallback endCallback = completeRunnableListCallback(callbacks, this); 1268 options.setOnAnimationAbortListener(endCallback); 1269 options.setOnAnimationFinishedListener(endCallback); 1270 return new ActivityOptionsWrapper(options, callbacks); 1271 } 1272 1273 @Override 1274 @BinderThread enterStageSplitFromRunningApp(boolean leftOrTop)1275 public void enterStageSplitFromRunningApp(boolean leftOrTop) { 1276 mSplitWithKeyboardShortcutController.enterStageSplit(leftOrTop); 1277 } 1278 1279 @Override onDisplayInfoChanged(Context context, DisplayController.Info info, int flags)1280 public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) { 1281 super.onDisplayInfoChanged(context, info, flags); 1282 // When changing screens, force moving to rest state similar to StatefulActivity.onStop, as 1283 // StatefulActivity isn't called consistently. 1284 if ((flags & CHANGE_ACTIVE_SCREEN) != 0) { 1285 // Do not animate moving to rest state, as it can clash with Launcher#onIdpChanged 1286 // where reapplyUi calls StateManager's reapplyState during the state change animation, 1287 // and cancel the state change unexpectedly. The screen will be off during screen 1288 // transition, hiding the unanimated transition. 1289 getStateManager().moveToRestState(/* isAnimated = */false); 1290 } 1291 1292 if ((flags & CHANGE_NAVIGATION_MODE) != 0) { 1293 getDragLayer().recreateControllers(); 1294 if (mActionsView != null) { 1295 mActionsView.updateVerticalMargin(info.getNavigationMode()); 1296 } 1297 } 1298 } 1299 1300 @Override onSaveInstanceState(Bundle outState)1301 protected void onSaveInstanceState(Bundle outState) { 1302 super.onSaveInstanceState(outState); 1303 1304 // If Launcher shuts downs during split select, we save some extra data in the recovery 1305 // bundle to allow graceful recovery. The normal LauncherState restore mechanism doesn't 1306 // work in this case because restoring straight to OverviewSplitSelect without staging data, 1307 // or before the tasks themselves have loaded into Overview, causes a crash. So we tell 1308 // Launcher to first restore into Overview state, wait for the relevant tasks and icons to 1309 // load in, and then proceed to OverviewSplitSelect. 1310 if (isInState(OVERVIEW_SPLIT_SELECT)) { 1311 // Launcher will restart in Overview and then transition to OverviewSplitSelect. 1312 outState.putIBinder(PENDING_SPLIT_SELECT_INFO, ObjectWrapper.wrap( 1313 new PendingSplitSelectInfo( 1314 mSplitSelectStateController.getInitialTaskId(), 1315 mSplitSelectStateController.getActiveSplitStagePosition(), 1316 mSplitSelectStateController.getSplitEvent()) 1317 )); 1318 outState.putInt(RUNTIME_STATE, OVERVIEW.ordinal); 1319 } 1320 } 1321 1322 /** 1323 * When Launcher restarts, it sometimes needs to recover to a split selection state. 1324 * This function checks if such a recovery is needed. 1325 * @return a boolean representing whether the launcher is waiting to recover to 1326 * OverviewSplitSelect state. 1327 */ hasPendingSplitSelectInfo()1328 public boolean hasPendingSplitSelectInfo() { 1329 return mPendingSplitSelectInfo != null; 1330 } 1331 1332 /** 1333 * See {@link #hasPendingSplitSelectInfo()} 1334 */ getPendingSplitSelectInfo()1335 public @Nullable PendingSplitSelectInfo getPendingSplitSelectInfo() { 1336 return mPendingSplitSelectInfo; 1337 } 1338 1339 /** 1340 * When the launcher has successfully recovered to OverviewSplitSelect state, this function 1341 * deletes the recovery data, returning it to a null state. 1342 */ finishSplitSelectRecovery()1343 public void finishSplitSelectRecovery() { 1344 mPendingSplitSelectInfo = null; 1345 } 1346 1347 /** 1348 * Sets flag whether a predictive back-to-home animation is in progress 1349 */ setPredictiveBackToHomeInProgress(boolean isInProgress)1350 public void setPredictiveBackToHomeInProgress(boolean isInProgress) { 1351 mIsPredictiveBackToHomeInProgress = isInProgress; 1352 mTISBindHelper.setPredictiveBackToHomeInProgress(isInProgress); 1353 } 1354 getPredictiveBackToHomeInProgress()1355 public boolean getPredictiveBackToHomeInProgress() { 1356 return mIsPredictiveBackToHomeInProgress; 1357 } 1358 1359 @Override areDesktopTasksVisible()1360 public boolean areDesktopTasksVisible() { 1361 return DesktopVisibilityController.INSTANCE.get(this) 1362 .isInDesktopModeAndNotInOverview(getDisplayId()); 1363 } 1364 1365 @Override dispatchDeviceProfileChanged()1366 public void dispatchDeviceProfileChanged() { 1367 super.dispatchDeviceProfileChanged(); 1368 Trace.instantForTrack(TRACE_TAG_APP, "QuickstepLauncher#DeviceProfileChanged", 1369 getDeviceProfile().toSmallString()); 1370 SystemUiProxy.INSTANCE.get(this).setLauncherAppIconSize(mDeviceProfile.iconSizePx); 1371 TaskbarManager taskbarManager = mTISBindHelper.getTaskbarManager(); 1372 if (taskbarManager != null) { 1373 taskbarManager.debugPrimaryTaskbar("QuickstepLauncher#onDeviceProfileChanged", 1374 true); 1375 } 1376 } 1377 1378 /** 1379 * Launches the given {@link SplitTask} in splitscreen. 1380 */ launchSplitTasks( @onNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition)1381 public void launchSplitTasks( 1382 @NonNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition) { 1383 mSplitSelectStateController.launchExistingSplitPair(null /* launchingTaskView */, 1384 splitTask.getTopLeftTask().key.id, 1385 splitTask.getBottomRightTask().key.id, 1386 SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT, 1387 /* callback= */ success -> mSplitSelectStateController.resetState(), 1388 /* freezeTaskList= */ false, 1389 splitTask.getSplitBounds().snapPosition, 1390 remoteTransition); 1391 } 1392 1393 /** 1394 * Launches two apps as an app pair. 1395 */ launchAppPair(AppPairIcon appPairIcon)1396 public void launchAppPair(AppPairIcon appPairIcon) { 1397 // Potentially show the Taskbar education once the app pair launch finishes 1398 mSplitSelectStateController.getAppPairsController().launchAppPair(appPairIcon, 1399 CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE, 1400 (success) -> { 1401 if (success && mTaskbarUIController != null) { 1402 mTaskbarUIController.showEduOnAppLaunch(); 1403 } 1404 }); 1405 } 1406 canStartHomeSafely()1407 public boolean canStartHomeSafely() { 1408 OverviewCommandHelper overviewCommandHelper = mTISBindHelper.getOverviewCommandHelper(); 1409 return overviewCommandHelper == null || overviewCommandHelper.canStartHomeSafely(); 1410 } 1411 1412 @Override isBubbleBarEnabled()1413 public boolean isBubbleBarEnabled() { 1414 return (mTaskbarUIController != null && mTaskbarUIController.isBubbleBarEnabled()); 1415 } 1416 1417 @Override hasBubbles()1418 public boolean hasBubbles() { 1419 return (mTaskbarUIController != null && mTaskbarUIController.hasBubbles()); 1420 } 1421 1422 @Override handleIncorrectSplitTargetSelection()1423 public boolean handleIncorrectSplitTargetSelection() { 1424 if (!mSplitSelectStateController.isSplitSelectActive()) { 1425 return false; 1426 } 1427 mSplitSelectStateController.getSplitInstructionsView().goBoing(); 1428 return true; 1429 } 1430 1431 @Override showShortcutBubble(ShortcutInfo info)1432 public void showShortcutBubble(ShortcutInfo info) { 1433 if (info == null) return; 1434 SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info); 1435 } 1436 1437 @Override showAppBubble(Intent intent, UserHandle user)1438 public void showAppBubble(Intent intent, UserHandle user) { 1439 if (intent == null || intent.getPackage() == null) return; 1440 SystemUiProxy.INSTANCE.get(this).showAppBubble(intent, user); 1441 } 1442 1443 /** Sets the location of the bubble bar */ setBubbleBarLocation(BubbleBarLocation bubbleBarLocation)1444 public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) { 1445 mBubbleBarLocation = bubbleBarLocation; 1446 } 1447 1448 /** 1449 * Similar to {@link #getFirstHomeElementForAppClose} but also matches all apps if its visible 1450 */ 1451 @Nullable getFirstVisibleElementForAppClose( @ullable StableViewInfo svi, String packageName, UserHandle user)1452 public View getFirstVisibleElementForAppClose( 1453 @Nullable StableViewInfo svi, String packageName, UserHandle user) { 1454 if (isInState(LauncherState.ALL_APPS)) { 1455 AllAppsRecyclerView activeRecyclerView = getAppsView().getActiveRecyclerView(); 1456 View v = null; 1457 if (svi != null) { 1458 // Preferred item match 1459 v = activeRecyclerView.findViewByPredicate(view -> 1460 view.isAggregatedVisible() 1461 && view.getTag() instanceof ItemInfo info && svi.matches(info)); 1462 } 1463 if (v == null) { 1464 // Package user match 1465 v = activeRecyclerView.findViewByPredicate(view -> 1466 view.isAggregatedVisible() && view.getTag() instanceof ItemInfo info 1467 && info.itemType == ITEM_TYPE_APPLICATION 1468 && info.user.equals(user) 1469 && TextUtils.equals(info.getTargetPackage(), packageName)); 1470 } 1471 1472 if (v != null && activeRecyclerView.computeVerticalScrollOffset() > 0) { 1473 RectF locationBounds = new RectF(); 1474 FloatingIconView.getLocationBoundsForView(this, v, false, locationBounds, 1475 new Rect()); 1476 if (locationBounds.top < getAppsView().getHeaderBottom()) { 1477 // Icon is covered by scrim, return null to play fallback animation. 1478 return null; 1479 } 1480 } 1481 return v; 1482 } 1483 1484 return getFirstHomeElementForAppClose(svi, packageName, user); 1485 } 1486 1487 @Override dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)1488 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 1489 super.dump(prefix, fd, writer, args); 1490 if (mDepthController != null) { 1491 mDepthController.dump(prefix, writer); 1492 } 1493 RecentsView recentsView = getOverviewPanel(); 1494 writer.println("\nQuickstepLauncher:"); 1495 writer.println(prefix + "\tmOrientationState: " + (recentsView == null ? "recentsNull" : 1496 recentsView.getPagedViewOrientedState())); 1497 if (recentsView != null) { 1498 recentsView.getSplitSelectController().dump(prefix, writer); 1499 } 1500 if (mAppTransitionManager != null) { 1501 mAppTransitionManager.dump(prefix + "\t" + RING_APPEAR_ANIMATION_PREFIX, writer); 1502 } 1503 if (mHotseatPredictionController != null) { 1504 mHotseatPredictionController.dump(prefix, writer); 1505 } 1506 PredictionRowView<?> predictionRowView = 1507 getAppsView().getFloatingHeaderView().findFixedRowByType( 1508 PredictionRowView.class); 1509 predictionRowView.dump(prefix, writer); 1510 } 1511 1512 @Override onCreateView(View parent, String name, Context context, AttributeSet attrs)1513 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { 1514 switch (name) { 1515 case "TextClock", "android.widget.TextClock" -> { 1516 TextClock tc = new TextClock(context, attrs); 1517 tc.setClockEventDelegate(AsyncClockEventDelegate.INSTANCE.get(this)); 1518 return tc; 1519 } 1520 case "AnalogClock", "android.widget.AnalogClock" -> { 1521 AnalogClock ac = new AnalogClock(context, attrs); 1522 ac.setClockEventDelegate(AsyncClockEventDelegate.INSTANCE.get(this)); 1523 return ac; 1524 } 1525 } 1526 return super.onCreateView(parent, name, context, attrs); 1527 } 1528 1529 @Override isRecentsViewVisible()1530 public boolean isRecentsViewVisible() { 1531 return getStateManager().getState().isRecentsViewVisible; 1532 } 1533 isCanShowAllAppsEducationView()1534 public boolean isCanShowAllAppsEducationView() { 1535 return mCanShowAllAppsEducationView; 1536 } 1537 setCanShowAllAppsEducationView(boolean canShowAllAppsEducationView)1538 public void setCanShowAllAppsEducationView(boolean canShowAllAppsEducationView) { 1539 mCanShowAllAppsEducationView = canShowAllAppsEducationView; 1540 } 1541 1542 @Override returnToHomescreen()1543 public void returnToHomescreen() { 1544 getStateManager().goToState(LauncherState.NORMAL); 1545 } 1546 } 1547