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 if (!topIsHome) { 75 if (!processRunning || newTask || (taskSwitch && !activityCreated)) { 76 return useEmptySplashScreen 77 ? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN 78 : legacySplashScreen 79 ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN 80 : STARTING_WINDOW_TYPE_SPLASH_SCREEN; 81 } 82 } 83 if (taskSwitch && allowTaskSnapshot) { 84 if (isSnapshotCompatible(windowInfo)) { 85 return STARTING_WINDOW_TYPE_SNAPSHOT; 86 } 87 if (!topIsHome) { 88 return STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; 89 } 90 } 91 return STARTING_WINDOW_TYPE_NONE; 92 } 93 94 95 /** 96 * Returns {@code true} if the task snapshot is compatible with this activity (at least the 97 * rotation must be the same). 98 */ isSnapshotCompatible(StartingWindowInfo windowInfo)99 private boolean isSnapshotCompatible(StartingWindowInfo windowInfo) { 100 final TaskSnapshot snapshot = windowInfo.taskSnapshot; 101 if (snapshot == null) { 102 if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { 103 Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId); 104 } 105 return false; 106 } 107 if (!snapshot.getTopActivityComponent().equals(windowInfo.taskInfo.topActivity)) { 108 if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { 109 Slog.d(TAG, "isSnapshotCompatible obsoleted snapshot " 110 + windowInfo.taskInfo.topActivity); 111 } 112 return false; 113 } 114 115 final int taskRotation = windowInfo.taskInfo.configuration 116 .windowConfiguration.getRotation(); 117 final int snapshotRotation = snapshot.getRotation(); 118 if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { 119 Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation 120 + " snapshot " + snapshotRotation); 121 } 122 return taskRotation == snapshotRotation; 123 } 124 } 125