A starting preview window is shown during activity starting. The feature is implemented in ActivityStack.startActivityLocked method.
Inframeworks/base/services/core/java/com/android/server/am/ActivityStack.java
2690 final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition, 2691 ActivityOptions options) { ............................... 2756 if (!isHomeStack() || numActivities() > 0) { 2757 // We want to show the starting preview window if we are 2758 // switching to a new task, or the next activity's process is 2759 // not currently running. ................................... 2797 if (r.mLaunchTaskBehind) { 2798 // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we 2799 // tell WindowManager that r is visible even though it is at the back of the stack. 2800 mWindowManager.setAppVisibility(r.appToken, true); 2801 ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); 2802 } else if (SHOW_APP_STARTING_PREVIEW && doShow) { // SHOW_APP_STARTING_PREVIEW is true by default 2803 // Figure out if we are transitioning from another activity that is 2804 // "has the same starting icon" as the next one. This allows the 2805 // window manager to keep the previous window it had previously 2806 // created, if it still had one. 2807 ActivityRecord prev = r.task.topRunningActivityWithStartingWindowLocked(); 2808 if (prev != null) { 2809 // We don't want to reuse the previous starting preview if: 2810 // (1) The current activity is in a different task. 2811 if (prev.task != r.task) { 2812 prev = null; 2813 } 2814 // (2) The current activity is already displayed. 2815 else if (prev.nowVisible) { 2816 prev = null; 2817 } 2818 } 2819 r.showStartingWindow(prev, showStartingIcon); 2820 VendorActivityStackCallback.callOnAppStartingPreview(mVendorCallbacks, r.intent, mService.mContext); 2821 } ......................... 2832 }
Inframeworks/base/services/core/java/com/android/server/am/ActivityRecord.java
1418 void showStartingWindow(ActivityRecord prev, boolean createIfNeeded) { 1419 final CompatibilityInfo compatInfo = 1420 service.compatibilityInfoForPackageLocked(info.applicationInfo); 1421 final boolean shown = service.mWindowManager.setAppStartingWindow( 1422 appToken, packageName, theme, compatInfo, nonLocalizedLabel, labelRes, icon, 1423 logo, windowFlags, prev != null ? prev.appToken : null, createIfNeeded); 1424 if (shown) { 1425 mStartingWindowState = STARTING_WINDOW_SHOWN; 1426 } 1427 }
Inframeworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
4201 public boolean setAppStartingWindow(IBinder token, String pkg, 4202 int theme, CompatibilityInfo compatInfo, 4203 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, 4204 int windowFlags, IBinder transferFrom, boolean createIfNeeded) { 4209 4210 synchronized(mWindowMap) { ................................. 4231 4232 // If this is a translucent window, then don't 4233 // show a starting window -- the current effect (a full-screen 4234 // opaque starting window that fades away to the real contents 4235 // when it is ready) does not work for this. 4238 if (theme != 0) { 4239 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, 4240 com.android.internal.R.styleable.Window, mCurrentUserId); 4241 if (ent == null) { 4242 // Whoops! App doesn't exist. Um. Okay. We'll just 4243 // pretend like we didn't see that. 4244 return false; 4245 } 4246 final boolean windowIsTranslucent = ent.array.getBoolean( 4247 com.android.internal.R.styleable.Window_windowIsTranslucent, false); 4248 final boolean windowIsFloating = ent.array.getBoolean( 4249 com.android.internal.R.styleable.Window_windowIsFloating, false); 4250 final boolean windowShowWallpaper = ent.array.getBoolean( 4251 com.android.internal.R.styleable.Window_windowShowWallpaper, false); 4252 final boolean windowDisableStarting = ent.array.getBoolean( 4253 com.android.internal.R.styleable.Window_windowDisablePreview, false); 4254 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent 4255 + " Floating=" + windowIsFloating 4256 + " ShowWallpaper=" + windowShowWallpaper); 4257 if (windowIsTranslucent) { 4258 return false; 4259 } 4260 if (windowIsFloating || windowDisableStarting) { 4261 return false; 4262 } 4263 if (windowShowWallpaper) { 4264 if (mWallpaperControllerLocked.getWallpaperTarget() == null) { 4265 // If this theme is requesting a wallpaper, and the wallpaper 4266 // is not currently visible, then this effectively serves as 4267 // an opaque window and our starting window transition animation 4268 // can still work. We just need to make sure the starting window 4269 // is also showing the wallpaper. 4270 windowFlags |= FLAG_SHOW_WALLPAPER; 4271 } else { 4272 return false; 4273 } 4274 } 4275 } ........................... 4287 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData"); 4288 wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel, 4289 labelRes, icon, logo, windowFlags); 4290 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken); 4291 // Note: we really want to do sendMessageAtFrontOfQueue() because we 4292 // want to process the message ASAP, before any other queued 4293 // messages. 4295 mH.sendMessageAtFrontOfQueue(m); 4296 } 4297 return true; 4298 }
8382 case ADD_STARTING: { 8395 try { 8396 final Configuration overrideConfig = wtoken != null && wtoken.mTask != null 8397 ? wtoken.mTask.mOverrideConfig : null; 8398 view = mPolicy.addStartingWindow(wtoken.token, sd.pkg, sd.theme, 8399 sd.compatInfo, sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo, 8400 sd.windowFlags, overrideConfig); 8401 } catch (Exception e) { 8402 Slog.w(TAG_WM, "Exception when adding starting window", e); 8403 } 8404 8439 } break;
In frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
static final boolean SHOW_STARTING_ANIMATIONS = true; // decide if we need show starting window
2190 public View addStartingWindow(IBinder appToken, String packageName, int theme, 2191 CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, 2192 int icon, int logo, int windowFlags) { // we can add a callback function here to skip adding starting window to WM 2193 if (!SHOW_STARTING_ANIMATIONS || VendorPhoneWindowManagerCallback.callSkipAddStartingWindow(mVendorCallbacks)) { 2194 return null; 2195 } 2202 2203 try { ........................... 2217 Window win = PolicyManager.makeNewWindow(context); 2218 final TypedArray ta = win.getWindowStyle(); 2219 2220 // performance_improve begin, skip starting window of some application to optimize performance. 2221 if (!packageName.equals(FIRE_LAUNCHER_PACKAGE) && ( 2222 ta.getBoolean( 2223 com.android.internal.R.styleable.Window_windowDisablePreview, false) 2224 || ta.getBoolean( 2225 com.android.internal.R.styleable.Window_windowShowWallpaper,false)) 2226 ) { 2227 return null; 2228 } 2229 // performance_improve end 2230 2231 Resources r = context.getResources(); 2232 win.setTitle(r.getText(labelRes, nonLocalizedLabel)); 2233 2234 win.setType( 2235 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); 2236 // Force the window flags: this is a fake window, so it is not really 2237 // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM 2238 // flag because we do know that the next window will take input 2239 // focus, so we want to get the IME window up on top of us right away. 2240 win.setFlags( 2241 windowFlags| 2242 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| 2243 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| 2244 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, 2245 windowFlags| 2246 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| 2247 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| 2248 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 2249 2250 win.setDefaultIcon(icon); 2251 win.setDefaultLogo(logo); 2252 2253 win.setLayout(WindowManager.LayoutParams.MATCH_PARENT, 2254 WindowManager.LayoutParams.MATCH_PARENT); 2255 2256 final WindowManager.LayoutParams params = win.getAttributes(); 2257 params.token = appToken; 2258 params.packageName = packageName; 2259 params.windowAnimations = win.getWindowStyle().getResourceId( 2260 com.android.internal.R.styleable.Window_windowAnimationStyle, 0); 2261 params.privateFlags |= 2262 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED; 2263 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 2264 2265 if (!compatInfo.supportsScreen()) { 2266 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; 2267 } 2268 2269 params.setTitle("Starting " + packageName); 2270 2271 wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); 2272 view = win.getDecorView(); 2273 2274 if (win.isFloating()) { 2275 // Whoops, there is no way to display an animation/preview 2276 // of such a thing! After all that work... let's skip it. 2277 // (Note that we must do this here because it is in 2278 // getDecorView() where the theme is evaluated... maybe 2279 // we should peek the floating attribute from the theme 2280 // earlier.) 2281 return null; 2282 } 2283 2288 2289 // fosmod_vendor_callbacks begin 2290 Rect contentRect; 2291 if ((windowFlags & FLAG_FULLSCREEN) != 0) { 2292 contentRect = new Rect(mStableFullscreenLeft, mStableFullscreenTop, 2293 mStableFullscreenRight, mStableFullscreenBottom); 2294 } else { 2295 contentRect = new Rect(mStableLeft, mStableTop, 2296 mStableRight, mStableBottom); 2297 } 2298 VendorPhoneWindowManagerCallback.callAddCustomStartingWindow( // a custom callback to add customized starting window instead of original one. 2299 mVendorCallbacks, 2300 view, 2301 context, 2302 packageName, 2303 mOrientationListener.getProposedRotation(), 2304 contentRect, 2305 new Rect( 2306 mRestrictedScreenLeft, 2307 mRestrictedScreenTop, 2308 mRestrictedScreenLeft + mRestrictedScreenWidth, 2309 mRestrictedScreenTop + mRestrictedOverscanScreenHeight 2310 ) 2311 ); 2312 // fosmod_vendor_callbacks end 2313 2314 wm.addView(view, params); 2315 2316 // Only return the view if it was successfully added to the 2317 // window manager... which we can tell by it having a parent. 2318 return view.getParent() != null ? view : null;