1 /* 2 * Copyright (C) 2020 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.server.wm; 18 19 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED; 20 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT; 21 import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; 22 import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; 23 import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; 24 import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; 25 import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN; 26 27 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 28 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 29 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.content.pm.ApplicationInfo; 33 import android.content.res.CompatibilityInfo; 34 import android.content.res.Configuration; 35 import android.os.SystemProperties; 36 import android.util.Slog; 37 import android.window.TaskSnapshot; 38 39 import com.android.server.policy.WindowManagerPolicy.StartingSurface; 40 41 import java.util.function.Supplier; 42 43 /** 44 * Managing to create and release a starting window surface. 45 */ 46 public class StartingSurfaceController { 47 private static final String TAG = TAG_WITH_CLASS_NAME 48 ? StartingSurfaceController.class.getSimpleName() : TAG_WM; 49 /** Set to {@code true} to enable shell starting surface drawer. */ 50 static final boolean DEBUG_ENABLE_SHELL_DRAWER = 51 SystemProperties.getBoolean("persist.debug.shell_starting_surface", true); 52 private final WindowManagerService mService; 53 private final SplashScreenExceptionList mSplashScreenExceptionsList; 54 StartingSurfaceController(WindowManagerService wm)55 public StartingSurfaceController(WindowManagerService wm) { 56 mService = wm; 57 mSplashScreenExceptionsList = new SplashScreenExceptionList(wm.mContext.getMainExecutor()); 58 } 59 createSplashScreenStartingSurface(ActivityRecord activity, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId)60 StartingSurface createSplashScreenStartingSurface(ActivityRecord activity, String packageName, 61 int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, 62 int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId) { 63 if (!DEBUG_ENABLE_SHELL_DRAWER) { 64 return mService.mPolicy.addSplashScreen(activity.token, activity.mUserId, packageName, 65 theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, 66 overrideConfig, displayId); 67 } 68 69 synchronized (mService.mGlobalLock) { 70 final Task task = activity.getTask(); 71 if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow( 72 task, activity, theme, null /* taskSnapshot */)) { 73 return new ShellStartingSurface(task); 74 } 75 } 76 return null; 77 } 78 79 /** 80 * @see SplashScreenExceptionList#isException(String, int, Supplier) 81 */ isExceptionApp(@onNull String packageName, int targetSdk, @Nullable Supplier<ApplicationInfo> infoProvider)82 boolean isExceptionApp(@NonNull String packageName, int targetSdk, 83 @Nullable Supplier<ApplicationInfo> infoProvider) { 84 return mSplashScreenExceptionsList.isException(packageName, targetSdk, infoProvider); 85 } 86 makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean useEmpty, boolean useLegacy)87 int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch, 88 boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, 89 boolean useEmpty, boolean useLegacy) { 90 int parameter = 0; 91 if (newTask) { 92 parameter |= TYPE_PARAMETER_NEW_TASK; 93 } 94 if (taskSwitch) { 95 parameter |= TYPE_PARAMETER_TASK_SWITCH; 96 } 97 if (processRunning) { 98 parameter |= TYPE_PARAMETER_PROCESS_RUNNING; 99 } 100 if (allowTaskSnapshot) { 101 parameter |= TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT; 102 } 103 if (activityCreated) { 104 parameter |= TYPE_PARAMETER_ACTIVITY_CREATED; 105 } 106 if (useEmpty) { 107 parameter |= TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN; 108 } 109 if (useLegacy) { 110 parameter |= TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; 111 } 112 return parameter; 113 } 114 createTaskSnapshotSurface(ActivityRecord activity, TaskSnapshot taskSnapshot)115 StartingSurface createTaskSnapshotSurface(ActivityRecord activity, TaskSnapshot taskSnapshot) { 116 final WindowState topFullscreenOpaqueWindow; 117 final Task task; 118 synchronized (mService.mGlobalLock) { 119 final WindowState mainWindow = activity.findMainWindow(); 120 task = activity.getTask(); 121 if (task == null) { 122 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity=" 123 + activity); 124 return null; 125 } 126 final ActivityRecord topFullscreenActivity = 127 activity.getTask().getTopFullscreenActivity(); 128 if (topFullscreenActivity == null) { 129 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task=" 130 + task); 131 return null; 132 } 133 topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow(); 134 if (mainWindow == null || topFullscreenOpaqueWindow == null) { 135 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity=" 136 + activity); 137 return null; 138 } 139 if (topFullscreenActivity.getWindowConfiguration().getRotation() 140 != taskSnapshot.getRotation() 141 // Use normal rotation to avoid flickering of IME window in old orientation. 142 && !taskSnapshot.hasImeSurface()) { 143 // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible 144 // that the activity will be updated to the same rotation as the snapshot. Since 145 // the transition is not started yet, fixed rotation transform needs to be applied 146 // earlier to make the snapshot show in a rotated container. 147 activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation( 148 topFullscreenActivity, false /* checkOpening */); 149 } 150 if (DEBUG_ENABLE_SHELL_DRAWER) { 151 mService.mAtmService.mTaskOrganizerController.addStartingWindow(task, 152 activity, 0 /* launchTheme */, taskSnapshot); 153 return new ShellStartingSurface(task); 154 } 155 } 156 return mService.mTaskSnapshotController.createStartingSurface(activity, taskSnapshot); 157 } 158 159 160 private final class ShellStartingSurface implements StartingSurface { 161 private final Task mTask; 162 ShellStartingSurface(Task task)163 ShellStartingSurface(Task task) { 164 mTask = task; 165 } 166 167 @Override remove(boolean animate)168 public void remove(boolean animate) { 169 synchronized (mService.mGlobalLock) { 170 mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask, animate); 171 } 172 } 173 } 174 } 175