1 /* 2 * Copyright (C) 2021 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 17 package com.android.wm.shell.startingsurface.phone; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 20 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; 21 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; 22 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE; 23 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; 24 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; 25 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED; 26 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT; 27 import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; 28 import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; 29 import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; 30 import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; 31 import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN; 32 33 import static com.android.wm.shell.startingsurface.StartingWindowController.DEBUG_SPLASH_SCREEN; 34 import static com.android.wm.shell.startingsurface.StartingWindowController.DEBUG_TASK_SNAPSHOT; 35 36 import android.util.Slog; 37 import android.window.StartingWindowInfo; 38 import android.window.TaskSnapshot; 39 40 import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; 41 42 /** 43 * Algorithm for determining the type of a new starting window on handheld devices. 44 * At the moment also used on Android Auto. 45 */ 46 public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgorithm { 47 private static final String TAG = PhoneStartingWindowTypeAlgorithm.class.getSimpleName(); 48 49 @Override getSuggestedWindowType(StartingWindowInfo windowInfo)50 public int getSuggestedWindowType(StartingWindowInfo windowInfo) { 51 final int parameter = windowInfo.startingWindowTypeParameter; 52 final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0; 53 final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0; 54 final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0; 55 final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0; 56 final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0; 57 final boolean useEmptySplashScreen = 58 (parameter & TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN) != 0; 59 final boolean legacySplashScreen = 60 ((parameter & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN) != 0); 61 final boolean topIsHome = windowInfo.taskInfo.topActivityType == ACTIVITY_TYPE_HOME; 62 63 if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { 64 Slog.d(TAG, "preferredStartingWindowType newTask:" + newTask 65 + " taskSwitch:" + taskSwitch 66 + " processRunning:" + processRunning 67 + " allowTaskSnapshot:" + allowTaskSnapshot 68 + " activityCreated:" + activityCreated 69 + " useEmptySplashScreen:" + useEmptySplashScreen 70 + " legacySplashScreen:" + legacySplashScreen 71 + " topIsHome:" + topIsHome); 72 } 73 74 final int visibleSplashScreenType = legacySplashScreen 75 ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN 76 : STARTING_WINDOW_TYPE_SPLASH_SCREEN; 77 78 if (!topIsHome) { 79 if (!processRunning) { 80 return useEmptySplashScreen 81 ? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN 82 : visibleSplashScreenType; 83 } 84 if (newTask) { 85 return useEmptySplashScreen 86 ? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN 87 : visibleSplashScreenType; 88 } 89 if (taskSwitch && !activityCreated) { 90 return visibleSplashScreenType; 91 } 92 } 93 if (taskSwitch && allowTaskSnapshot) { 94 if (isSnapshotCompatible(windowInfo)) { 95 return STARTING_WINDOW_TYPE_SNAPSHOT; 96 } 97 if (!topIsHome) { 98 return STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; 99 } 100 } 101 return STARTING_WINDOW_TYPE_NONE; 102 } 103 104 105 /** 106 * Returns {@code true} if the task snapshot is compatible with this activity (at least the 107 * rotation must be the same). 108 */ isSnapshotCompatible(StartingWindowInfo windowInfo)109 private boolean isSnapshotCompatible(StartingWindowInfo windowInfo) { 110 final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; 111 if (snapshot == null) { 112 if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { 113 Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId); 114 } 115 return false; 116 } 117 if (!snapshot.getTopActivityComponent().equals(windowInfo.taskInfo.topActivity)) { 118 if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { 119 Slog.d(TAG, "isSnapshotCompatible obsoleted snapshot " 120 + windowInfo.taskInfo.topActivity); 121 } 122 return false; 123 } 124 125 final int taskRotation = windowInfo.taskInfo.configuration 126 .windowConfiguration.getRotation(); 127 final int snapshotRotation = snapshot.getRotation(); 128 if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { 129 Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation 130 + " snapshot " + snapshotRotation); 131 } 132 return taskRotation == snapshotRotation; 133 } 134 } 135