Loading core/java/android/view/WindowManagerPolicy.java +18 −9 Original line number Diff line number Diff line Loading @@ -436,6 +436,15 @@ public interface WindowManagerPolicy { void dismiss(); } /** * Holds the contents of a starting window. {@link #addSplashScreen} needs to wrap the * contents of the starting window into an class implementing this interface, which then will be * held by WM and passed into {@link #removeSplashScreen} when the starting window is no * longer needed. */ interface StartingSurface { } /** * Interface for calling back in to the window manager that is private * between it and the policy. Loading Loading @@ -738,17 +747,17 @@ public interface WindowManagerPolicy { * context to for resources. * * @return Optionally you can return the View that was used to create the * window, for easy removal in removeStartingWindow. * window, for easy removal in removeSplashScreen. * * @see #removeStartingWindow * @see #removeSplashScreen */ public View addStartingWindow(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig); public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig); /** * Called when the first window of an application has been displayed, while * {@link #addStartingWindow} has created a temporary initial window for * {@link #addSplashScreen} has created a temporary initial window for * that application. You should at this point remove the window from the * window manager. This is called without the window manager locked so * that you can call back into it. Loading @@ -759,11 +768,11 @@ public interface WindowManagerPolicy { * even if you previously returned one. * * @param appToken Token of the application that has started. * @param window Window View that was returned by createStartingWindow. * @param surface Surface that was returned by {@link #addSplashScreen}. * * @see #addStartingWindow * @see #addSplashScreen */ public void removeStartingWindow(IBinder appToken, View window); public void removeSplashScreen(IBinder appToken, StartingSurface surface); /** * Prepare for a window being added to the window manager. You can throw an Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +18 −18 Original line number Diff line number Diff line Loading @@ -251,9 +251,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean DEBUG_INPUT = false; static final boolean DEBUG_KEYGUARD = false; static final boolean DEBUG_LAYOUT = false; static final boolean DEBUG_STARTING_WINDOW = false; static final boolean DEBUG_SPLASH_SCREEN = false; static final boolean DEBUG_WAKEUP = false; static final boolean SHOW_STARTING_ANIMATIONS = true; static final boolean SHOW_SPLASH_SCREENS = true; // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key. // No longer recommended for desk docks; Loading Loading @@ -2794,10 +2794,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public View addStartingWindow(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig) { if (!SHOW_STARTING_ANIMATIONS) { public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig) { if (!SHOW_SPLASH_SCREENS) { return null; } if (packageName == null) { Loading @@ -2809,7 +2809,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { try { Context context = mContext; if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "addSplashScreen " + packageName + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme=" + Integer.toHexString(theme)); if (theme != context.getThemeResId() || labelRes != 0) { Loading @@ -2822,8 +2822,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (overrideConfig != null && !overrideConfig.equals(EMPTY)) { if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow: creating context based" + " on overrideConfig" + overrideConfig + " for starting window"); if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "addSplashScreen: creating context based" + " on overrideConfig" + overrideConfig + " for splash screen"); final Context overrideContext = context.createConfigurationContext(overrideConfig); overrideContext.setTheme(theme); final TypedArray typedArray = overrideContext.obtainStyledAttributes( Loading @@ -2833,7 +2833,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // We want to use the windowBackground for the override context if it is // available, otherwise we use the default one to make sure a themed starting // window is displayed for the app. if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow: apply overrideConfig" if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "addSplashScreen: apply overrideConfig" + overrideConfig + " to starting window resId=" + resId); context = overrideContext; } Loading Loading @@ -2895,19 +2895,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; } params.setTitle("Starting " + packageName); params.setTitle("Splash Screen " + packageName); wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); view = win.getDecorView(); if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Adding starting window for " if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for " + packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null)); wm.addView(view, params); // Only return the view if it was successfully added to the // window manager... which we can tell by it having a parent. return view.getParent() != null ? view : null; return view.getParent() != null ? new SplashScreenSurface(view) : null; } catch (WindowManager.BadTokenException e) { // ignore Log.w(TAG, appToken + " already running, starting window not displayed. " + Loading @@ -2929,13 +2929,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public void removeStartingWindow(IBinder appToken, View window) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing starting window for " + appToken + ": " + window + " Callers=" + Debug.getCallers(4)); public void removeSplashScreen(IBinder appToken, StartingSurface surface) { if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + appToken + ": " + surface + " Callers=" + Debug.getCallers(4)); if (window != null) { if (surface != null) { WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); wm.removeView(window); wm.removeView(((SplashScreenSurface) surface).view); } } Loading services/core/java/com/android/server/policy/SplashScreenSurface.java 0 → 100644 +38 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.server.policy; import android.view.View; import android.view.WindowManagerPolicy; import android.view.WindowManagerPolicy.StartingSurface; import com.android.internal.policy.DecorView; import com.android.internal.policy.PhoneWindow; /** * Holds the contents of a splash screen starting window, i.e. the {@link DecorView} of a * {@link PhoneWindow}. This is just a wrapper such that we can return it from * {@link WindowManagerPolicy#addSplashScreen}. */ class SplashScreenSurface implements StartingSurface { final View view; SplashScreenSurface(View view) { this.view = view; } } services/core/java/com/android/server/wm/AppWindowContainerController.java +128 −16 Original line number Diff line number Diff line Loading @@ -27,21 +27,21 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WIND import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.ADD_STARTING; import android.graphics.Bitmap; import android.os.Trace; import com.android.server.AttributeCache; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.os.Binder; import android.os.Debug; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Looper; import android.os.Trace; import android.util.Slog; import android.view.IApplicationToken; import android.view.WindowManagerPolicy.StartingSurface; import com.android.server.AttributeCache; /** * Controller for the app window token container. This is created by activity manager to link * activity records to the app window token container they use in window manager. Loading @@ -52,6 +52,7 @@ public class AppWindowContainerController extends WindowContainerController<AppWindowToken, AppWindowContainerListener> { private final IApplicationToken mToken; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Runnable mOnWindowsDrawn = () -> { if (mListener == null) { Loading Loading @@ -80,6 +81,94 @@ public class AppWindowContainerController mListener.onWindowsGone(); }; private final Runnable mAddStartingWindow = () -> { final StartingData startingData; final Configuration mergedOverrideConfiguration; synchronized (mWindowMap) { startingData = mContainer.startingData; mergedOverrideConfiguration = mContainer.getMergedOverrideConfiguration(); } if (startingData == null) { // Animation has been canceled... do nothing. return; } if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting " + this + ": pkg=" + mContainer.startingData.pkg); StartingSurface contents = null; try { contents = mService.mPolicy.addSplashScreen(mContainer.token, startingData.pkg, startingData.theme, startingData.compatInfo, startingData.nonLocalizedLabel, startingData.labelRes, startingData.icon, startingData.logo, startingData.windowFlags, mergedOverrideConfiguration); } catch (Exception e) { Slog.w(TAG_WM, "Exception when adding starting window", e); } if (contents != null) { boolean abort = false; synchronized(mWindowMap) { if (mContainer.removed || mContainer.startingData == null) { // If the window was successfully added, then // we need to remove it. if (mContainer.startingWindow != null) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Aborted starting " + mContainer + ": removed=" + mContainer.removed + " startingData=" + mContainer.startingData); mContainer.startingWindow = null; mContainer.startingData = null; abort = true; } } else { mContainer.startingSurface = contents; } if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM, "Added starting " + mContainer + ": startingWindow=" + mContainer.startingWindow + " startingView=" + mContainer.startingSurface); } if (abort) { try { mService.mPolicy.removeSplashScreen(mContainer.token, contents); } catch (Exception e) { Slog.w(TAG_WM, "Exception when removing starting window", e); } } } }; private final Runnable mRemoveStartingWindow = () -> { IBinder token = null; StartingSurface contents = null; synchronized (mWindowMap) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer + ": startingWindow=" + mContainer.startingWindow + " startingView=" + mContainer.startingSurface); if (mContainer.startingWindow != null) { contents = mContainer.startingSurface; token = mContainer.token; mContainer.startingData = null; mContainer.startingSurface = null; mContainer.startingWindow = null; mContainer.startingDisplayed = false; } } if (contents != null) { try { mService.mPolicy.removeSplashScreen(token, contents); } catch (Exception e) { Slog.w(TAG_WM, "Exception when removing starting window", e); } } }; public AppWindowContainerController(IApplicationToken token, AppWindowContainerListener listener, int taskId, int index, int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges, Loading Loading @@ -393,19 +482,42 @@ public class AppWindowContainerController if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData"); mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags); final Message m = mService.mH.obtainMessage(ADD_STARTING, mContainer); scheduleAddStartingWindow(); } return true; } void scheduleAddStartingWindow() { // Note: we really want to do sendMessageAtFrontOfQueue() because we // want to process the message ASAP, before any other queued // messages. if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING"); mService.mH.sendMessageAtFrontOfQueue(m); } return true; mHandler.postAtFrontOfQueue(mAddStartingWindow); } public void removeStartingWindow() { synchronized (mWindowMap) { mService.scheduleRemoveStartingWindowLocked(mContainer); if (mHandler.hasCallbacks(mRemoveStartingWindow)) { // Already scheduled. return; } if (mContainer.startingWindow == null) { if (mContainer.startingData != null) { // Starting window has not been added yet, but it is scheduled to be added. // Go ahead and cancel the request. if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Clearing startingData for token=" + mContainer); mContainer.startingData = null; } return; } if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1) + ": Schedule remove starting " + mContainer + " startingWindow=" + mContainer.startingWindow); mHandler.post(mRemoveStartingWindow); } } Loading Loading @@ -508,15 +620,15 @@ public class AppWindowContainerController void reportWindowsDrawn() { mService.mH.post(mOnWindowsDrawn); mHandler.post(mOnWindowsDrawn); } void reportWindowsVisible() { mService.mH.post(mOnWindowsVisible); mHandler.post(mOnWindowsVisible); } void reportWindowsGone() { mService.mH.post(mOnWindowsGone); mHandler.post(mOnWindowsGone); } /** Calls directly into activity manager so window manager lock shouldn't held. */ Loading services/core/java/com/android/server/wm/AppWindowToken.java +33 −32 Original line number Diff line number Diff line Loading @@ -29,9 +29,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.AppTransition.TRANSIT_UNSET; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; Loading @@ -47,22 +47,21 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.logWithStack; import android.os.Debug; import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; import android.annotation.NonNull; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; import android.os.Debug; import android.os.IBinder; import android.os.Message; import android.os.SystemClock; import android.util.Slog; import android.view.IApplicationToken; import android.view.View; import android.view.WindowManager; import android.view.WindowManagerPolicy.StartingSurface; import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; import java.util.ArrayDeque; Loading Loading @@ -138,7 +137,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // Information about an application starting window if displayed. StartingData startingData; WindowState startingWindow; View startingView; StartingSurface startingSurface; boolean startingDisplayed; boolean startingMoved; boolean firstWindowDrawn; Loading Loading @@ -213,8 +212,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // it from behind the starting window, so there is no need for it to also be doing its // own stuff. winAnimator.clearAnimation(); winAnimator.mService.mFinishedStarting.add(this); winAnimator.mService.mH.sendEmptyMessage(H.FINISHED_STARTING); if (getController() != null) { getController().removeStartingWindow(); } } updateReportedVisibilityLocked(); } Loading Loading @@ -439,8 +439,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } void onRemovedFromDisplay() { AppWindowToken startingToken = null; if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this); boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction); Loading @@ -461,6 +459,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: " + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4)); if (startingData != null && getController() != null) { getController().removeStartingWindow(); } final TaskStack stack = mTask.mStack; if (delayed && !isEmpty()) { // set the token aside because it has an active animation to be finished Loading @@ -477,9 +479,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } removed = true; if (startingData != null) { startingToken = this; } stopFreezingScreen(true, true); if (mService.mFocusedApp == this) { if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this); Loading @@ -491,9 +490,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (!delayed) { updateReportedVisibilityLocked(); } // Will only remove if startingToken non null. mService.scheduleRemoveStartingWindowLocked(startingToken); } void clearAnimatingFlags() { Loading Loading @@ -557,7 +553,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mAppStopped = true; destroySurfaces(); // Remove any starting window that was added for this app if they are still around. mTask.mService.scheduleRemoveStartingWindowLocked(this); if (getController() != null) { getController().removeStartingWindow(); } } /** Loading Loading @@ -667,16 +665,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // TODO: Something smells about the code below...Is there a better way? if (startingWindow == win) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win); mService.scheduleRemoveStartingWindowLocked(this); if (getController() != null) { getController().removeStartingWindow(); } } else if (mChildren.size() == 0 && startingData != null) { // If this is the last window and we had requested a starting transition window, // well there is no point now. if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingWindow"); startingData = null; } else if (mChildren.size() == 1 && startingView != null) { } else if (mChildren.size() == 1 && startingSurface != null) { // If this is the last window except for a starting transition window, // we need to get rid of the starting transition. mService.scheduleRemoveStartingWindowLocked(this); if (getController() != null) { getController().removeStartingWindow(); } } } Loading Loading @@ -1015,7 +1017,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } final WindowState tStartingWindow = fromToken.startingWindow; if (tStartingWindow != null && fromToken.startingView != null) { if (tStartingWindow != null && fromToken.startingSurface != null) { // In this case, the starting icon has already been displayed, so start // letting windows get shown immediately without any more transitions. mService.mSkipAppTransitionAnimation = true; Loading @@ -1027,13 +1029,13 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // Transfer the starting window over to the new token. startingData = fromToken.startingData; startingView = fromToken.startingView; startingSurface = fromToken.startingSurface; startingDisplayed = fromToken.startingDisplayed; fromToken.startingDisplayed = false; startingWindow = tStartingWindow; reportedVisible = fromToken.reportedVisible; fromToken.startingData = null; fromToken.startingView = null; fromToken.startingSurface = null; fromToken.startingWindow = null; fromToken.startingMoved = true; tStartingWindow.mToken = this; Loading Loading @@ -1080,10 +1082,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree startingData = fromToken.startingData; fromToken.startingData = null; fromToken.startingMoved = true; final Message m = mService.mH.obtainMessage(H.ADD_STARTING, this); // Note: we really want to do sendMessageAtFrontOfQueue() because we want to process the // message ASAP, before any other queued messages. mService.mH.sendMessageAtFrontOfQueue(m); if (getController() != null) { getController().scheduleAddStartingWindow(); } return true; } Loading Loading @@ -1421,10 +1422,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn); pw.print(" mIsExiting="); pw.println(mIsExiting); } if (startingWindow != null || startingView != null if (startingWindow != null || startingSurface != null || startingDisplayed || startingMoved) { pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); pw.print(" startingView="); pw.print(startingView); pw.print(" startingSurface="); pw.print(startingSurface); pw.print(" startingDisplayed="); pw.print(startingDisplayed); pw.print(" startingMoved="); pw.println(startingMoved); } Loading Loading
core/java/android/view/WindowManagerPolicy.java +18 −9 Original line number Diff line number Diff line Loading @@ -436,6 +436,15 @@ public interface WindowManagerPolicy { void dismiss(); } /** * Holds the contents of a starting window. {@link #addSplashScreen} needs to wrap the * contents of the starting window into an class implementing this interface, which then will be * held by WM and passed into {@link #removeSplashScreen} when the starting window is no * longer needed. */ interface StartingSurface { } /** * Interface for calling back in to the window manager that is private * between it and the policy. Loading Loading @@ -738,17 +747,17 @@ public interface WindowManagerPolicy { * context to for resources. * * @return Optionally you can return the View that was used to create the * window, for easy removal in removeStartingWindow. * window, for easy removal in removeSplashScreen. * * @see #removeStartingWindow * @see #removeSplashScreen */ public View addStartingWindow(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig); public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig); /** * Called when the first window of an application has been displayed, while * {@link #addStartingWindow} has created a temporary initial window for * {@link #addSplashScreen} has created a temporary initial window for * that application. You should at this point remove the window from the * window manager. This is called without the window manager locked so * that you can call back into it. Loading @@ -759,11 +768,11 @@ public interface WindowManagerPolicy { * even if you previously returned one. * * @param appToken Token of the application that has started. * @param window Window View that was returned by createStartingWindow. * @param surface Surface that was returned by {@link #addSplashScreen}. * * @see #addStartingWindow * @see #addSplashScreen */ public void removeStartingWindow(IBinder appToken, View window); public void removeSplashScreen(IBinder appToken, StartingSurface surface); /** * Prepare for a window being added to the window manager. You can throw an Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +18 −18 Original line number Diff line number Diff line Loading @@ -251,9 +251,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean DEBUG_INPUT = false; static final boolean DEBUG_KEYGUARD = false; static final boolean DEBUG_LAYOUT = false; static final boolean DEBUG_STARTING_WINDOW = false; static final boolean DEBUG_SPLASH_SCREEN = false; static final boolean DEBUG_WAKEUP = false; static final boolean SHOW_STARTING_ANIMATIONS = true; static final boolean SHOW_SPLASH_SCREENS = true; // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key. // No longer recommended for desk docks; Loading Loading @@ -2794,10 +2794,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public View addStartingWindow(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig) { if (!SHOW_STARTING_ANIMATIONS) { public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig) { if (!SHOW_SPLASH_SCREENS) { return null; } if (packageName == null) { Loading @@ -2809,7 +2809,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { try { Context context = mContext; if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "addSplashScreen " + packageName + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme=" + Integer.toHexString(theme)); if (theme != context.getThemeResId() || labelRes != 0) { Loading @@ -2822,8 +2822,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (overrideConfig != null && !overrideConfig.equals(EMPTY)) { if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow: creating context based" + " on overrideConfig" + overrideConfig + " for starting window"); if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "addSplashScreen: creating context based" + " on overrideConfig" + overrideConfig + " for splash screen"); final Context overrideContext = context.createConfigurationContext(overrideConfig); overrideContext.setTheme(theme); final TypedArray typedArray = overrideContext.obtainStyledAttributes( Loading @@ -2833,7 +2833,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // We want to use the windowBackground for the override context if it is // available, otherwise we use the default one to make sure a themed starting // window is displayed for the app. if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow: apply overrideConfig" if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "addSplashScreen: apply overrideConfig" + overrideConfig + " to starting window resId=" + resId); context = overrideContext; } Loading Loading @@ -2895,19 +2895,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; } params.setTitle("Starting " + packageName); params.setTitle("Splash Screen " + packageName); wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); view = win.getDecorView(); if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Adding starting window for " if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for " + packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null)); wm.addView(view, params); // Only return the view if it was successfully added to the // window manager... which we can tell by it having a parent. return view.getParent() != null ? view : null; return view.getParent() != null ? new SplashScreenSurface(view) : null; } catch (WindowManager.BadTokenException e) { // ignore Log.w(TAG, appToken + " already running, starting window not displayed. " + Loading @@ -2929,13 +2929,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public void removeStartingWindow(IBinder appToken, View window) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing starting window for " + appToken + ": " + window + " Callers=" + Debug.getCallers(4)); public void removeSplashScreen(IBinder appToken, StartingSurface surface) { if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + appToken + ": " + surface + " Callers=" + Debug.getCallers(4)); if (window != null) { if (surface != null) { WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); wm.removeView(window); wm.removeView(((SplashScreenSurface) surface).view); } } Loading
services/core/java/com/android/server/policy/SplashScreenSurface.java 0 → 100644 +38 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.server.policy; import android.view.View; import android.view.WindowManagerPolicy; import android.view.WindowManagerPolicy.StartingSurface; import com.android.internal.policy.DecorView; import com.android.internal.policy.PhoneWindow; /** * Holds the contents of a splash screen starting window, i.e. the {@link DecorView} of a * {@link PhoneWindow}. This is just a wrapper such that we can return it from * {@link WindowManagerPolicy#addSplashScreen}. */ class SplashScreenSurface implements StartingSurface { final View view; SplashScreenSurface(View view) { this.view = view; } }
services/core/java/com/android/server/wm/AppWindowContainerController.java +128 −16 Original line number Diff line number Diff line Loading @@ -27,21 +27,21 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WIND import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.ADD_STARTING; import android.graphics.Bitmap; import android.os.Trace; import com.android.server.AttributeCache; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.os.Binder; import android.os.Debug; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Looper; import android.os.Trace; import android.util.Slog; import android.view.IApplicationToken; import android.view.WindowManagerPolicy.StartingSurface; import com.android.server.AttributeCache; /** * Controller for the app window token container. This is created by activity manager to link * activity records to the app window token container they use in window manager. Loading @@ -52,6 +52,7 @@ public class AppWindowContainerController extends WindowContainerController<AppWindowToken, AppWindowContainerListener> { private final IApplicationToken mToken; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Runnable mOnWindowsDrawn = () -> { if (mListener == null) { Loading Loading @@ -80,6 +81,94 @@ public class AppWindowContainerController mListener.onWindowsGone(); }; private final Runnable mAddStartingWindow = () -> { final StartingData startingData; final Configuration mergedOverrideConfiguration; synchronized (mWindowMap) { startingData = mContainer.startingData; mergedOverrideConfiguration = mContainer.getMergedOverrideConfiguration(); } if (startingData == null) { // Animation has been canceled... do nothing. return; } if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting " + this + ": pkg=" + mContainer.startingData.pkg); StartingSurface contents = null; try { contents = mService.mPolicy.addSplashScreen(mContainer.token, startingData.pkg, startingData.theme, startingData.compatInfo, startingData.nonLocalizedLabel, startingData.labelRes, startingData.icon, startingData.logo, startingData.windowFlags, mergedOverrideConfiguration); } catch (Exception e) { Slog.w(TAG_WM, "Exception when adding starting window", e); } if (contents != null) { boolean abort = false; synchronized(mWindowMap) { if (mContainer.removed || mContainer.startingData == null) { // If the window was successfully added, then // we need to remove it. if (mContainer.startingWindow != null) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Aborted starting " + mContainer + ": removed=" + mContainer.removed + " startingData=" + mContainer.startingData); mContainer.startingWindow = null; mContainer.startingData = null; abort = true; } } else { mContainer.startingSurface = contents; } if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM, "Added starting " + mContainer + ": startingWindow=" + mContainer.startingWindow + " startingView=" + mContainer.startingSurface); } if (abort) { try { mService.mPolicy.removeSplashScreen(mContainer.token, contents); } catch (Exception e) { Slog.w(TAG_WM, "Exception when removing starting window", e); } } } }; private final Runnable mRemoveStartingWindow = () -> { IBinder token = null; StartingSurface contents = null; synchronized (mWindowMap) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer + ": startingWindow=" + mContainer.startingWindow + " startingView=" + mContainer.startingSurface); if (mContainer.startingWindow != null) { contents = mContainer.startingSurface; token = mContainer.token; mContainer.startingData = null; mContainer.startingSurface = null; mContainer.startingWindow = null; mContainer.startingDisplayed = false; } } if (contents != null) { try { mService.mPolicy.removeSplashScreen(token, contents); } catch (Exception e) { Slog.w(TAG_WM, "Exception when removing starting window", e); } } }; public AppWindowContainerController(IApplicationToken token, AppWindowContainerListener listener, int taskId, int index, int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges, Loading Loading @@ -393,19 +482,42 @@ public class AppWindowContainerController if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData"); mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags); final Message m = mService.mH.obtainMessage(ADD_STARTING, mContainer); scheduleAddStartingWindow(); } return true; } void scheduleAddStartingWindow() { // Note: we really want to do sendMessageAtFrontOfQueue() because we // want to process the message ASAP, before any other queued // messages. if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING"); mService.mH.sendMessageAtFrontOfQueue(m); } return true; mHandler.postAtFrontOfQueue(mAddStartingWindow); } public void removeStartingWindow() { synchronized (mWindowMap) { mService.scheduleRemoveStartingWindowLocked(mContainer); if (mHandler.hasCallbacks(mRemoveStartingWindow)) { // Already scheduled. return; } if (mContainer.startingWindow == null) { if (mContainer.startingData != null) { // Starting window has not been added yet, but it is scheduled to be added. // Go ahead and cancel the request. if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Clearing startingData for token=" + mContainer); mContainer.startingData = null; } return; } if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1) + ": Schedule remove starting " + mContainer + " startingWindow=" + mContainer.startingWindow); mHandler.post(mRemoveStartingWindow); } } Loading Loading @@ -508,15 +620,15 @@ public class AppWindowContainerController void reportWindowsDrawn() { mService.mH.post(mOnWindowsDrawn); mHandler.post(mOnWindowsDrawn); } void reportWindowsVisible() { mService.mH.post(mOnWindowsVisible); mHandler.post(mOnWindowsVisible); } void reportWindowsGone() { mService.mH.post(mOnWindowsGone); mHandler.post(mOnWindowsGone); } /** Calls directly into activity manager so window manager lock shouldn't held. */ Loading
services/core/java/com/android/server/wm/AppWindowToken.java +33 −32 Original line number Diff line number Diff line Loading @@ -29,9 +29,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.AppTransition.TRANSIT_UNSET; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; Loading @@ -47,22 +47,21 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.logWithStack; import android.os.Debug; import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; import android.annotation.NonNull; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; import android.os.Debug; import android.os.IBinder; import android.os.Message; import android.os.SystemClock; import android.util.Slog; import android.view.IApplicationToken; import android.view.View; import android.view.WindowManager; import android.view.WindowManagerPolicy.StartingSurface; import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; import java.util.ArrayDeque; Loading Loading @@ -138,7 +137,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // Information about an application starting window if displayed. StartingData startingData; WindowState startingWindow; View startingView; StartingSurface startingSurface; boolean startingDisplayed; boolean startingMoved; boolean firstWindowDrawn; Loading Loading @@ -213,8 +212,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // it from behind the starting window, so there is no need for it to also be doing its // own stuff. winAnimator.clearAnimation(); winAnimator.mService.mFinishedStarting.add(this); winAnimator.mService.mH.sendEmptyMessage(H.FINISHED_STARTING); if (getController() != null) { getController().removeStartingWindow(); } } updateReportedVisibilityLocked(); } Loading Loading @@ -439,8 +439,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } void onRemovedFromDisplay() { AppWindowToken startingToken = null; if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this); boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction); Loading @@ -461,6 +459,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: " + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4)); if (startingData != null && getController() != null) { getController().removeStartingWindow(); } final TaskStack stack = mTask.mStack; if (delayed && !isEmpty()) { // set the token aside because it has an active animation to be finished Loading @@ -477,9 +479,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } removed = true; if (startingData != null) { startingToken = this; } stopFreezingScreen(true, true); if (mService.mFocusedApp == this) { if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this); Loading @@ -491,9 +490,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (!delayed) { updateReportedVisibilityLocked(); } // Will only remove if startingToken non null. mService.scheduleRemoveStartingWindowLocked(startingToken); } void clearAnimatingFlags() { Loading Loading @@ -557,7 +553,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mAppStopped = true; destroySurfaces(); // Remove any starting window that was added for this app if they are still around. mTask.mService.scheduleRemoveStartingWindowLocked(this); if (getController() != null) { getController().removeStartingWindow(); } } /** Loading Loading @@ -667,16 +665,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // TODO: Something smells about the code below...Is there a better way? if (startingWindow == win) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win); mService.scheduleRemoveStartingWindowLocked(this); if (getController() != null) { getController().removeStartingWindow(); } } else if (mChildren.size() == 0 && startingData != null) { // If this is the last window and we had requested a starting transition window, // well there is no point now. if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingWindow"); startingData = null; } else if (mChildren.size() == 1 && startingView != null) { } else if (mChildren.size() == 1 && startingSurface != null) { // If this is the last window except for a starting transition window, // we need to get rid of the starting transition. mService.scheduleRemoveStartingWindowLocked(this); if (getController() != null) { getController().removeStartingWindow(); } } } Loading Loading @@ -1015,7 +1017,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } final WindowState tStartingWindow = fromToken.startingWindow; if (tStartingWindow != null && fromToken.startingView != null) { if (tStartingWindow != null && fromToken.startingSurface != null) { // In this case, the starting icon has already been displayed, so start // letting windows get shown immediately without any more transitions. mService.mSkipAppTransitionAnimation = true; Loading @@ -1027,13 +1029,13 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // Transfer the starting window over to the new token. startingData = fromToken.startingData; startingView = fromToken.startingView; startingSurface = fromToken.startingSurface; startingDisplayed = fromToken.startingDisplayed; fromToken.startingDisplayed = false; startingWindow = tStartingWindow; reportedVisible = fromToken.reportedVisible; fromToken.startingData = null; fromToken.startingView = null; fromToken.startingSurface = null; fromToken.startingWindow = null; fromToken.startingMoved = true; tStartingWindow.mToken = this; Loading Loading @@ -1080,10 +1082,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree startingData = fromToken.startingData; fromToken.startingData = null; fromToken.startingMoved = true; final Message m = mService.mH.obtainMessage(H.ADD_STARTING, this); // Note: we really want to do sendMessageAtFrontOfQueue() because we want to process the // message ASAP, before any other queued messages. mService.mH.sendMessageAtFrontOfQueue(m); if (getController() != null) { getController().scheduleAddStartingWindow(); } return true; } Loading Loading @@ -1421,10 +1422,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn); pw.print(" mIsExiting="); pw.println(mIsExiting); } if (startingWindow != null || startingView != null if (startingWindow != null || startingSurface != null || startingDisplayed || startingMoved) { pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); pw.print(" startingView="); pw.print(startingView); pw.print(" startingSurface="); pw.print(startingSurface); pw.print(" startingDisplayed="); pw.print(startingDisplayed); pw.print(" startingMoved="); pw.println(startingMoved); } Loading