From ad24f96def42016049de05220593aa049b136def Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 25 Aug 2016 12:12:33 -0700 Subject: [PATCH] Only use saved surface if started by launcher or moved to front Restrict saved surface to launcher start (ACTION_MAIN&CATEGORY_ LAUNCHER), or there is no intent at all (eg. task being brought to front). If the intent is something else, likely the app is going to show some specific page or view, instead of what's left last time. This solves problems like the launcher shortcuts on DeckClock, each of them is a different intent and will show one specific view regardless of last states. Another example is Chrome tab opened directly by action VIEW to open some URL. (Note that this doesn't solve the problem with Chrome homescreen shortcuts, it will still start with saved surface (if Chrome is already open). This is because the shortcut is a trampoline activity that starts the real chrome tab activity, but when the trampoline is started, the whole task is already brought to front, and ChromeTab could become visible with the task before we actually start it.) bug:27747315 Change-Id: Id3e61c61ef516b0edc1f174320f02661222f226b --- core/java/android/view/IWindowManager.aidl | 2 +- .../java/com/android/server/am/ActivityRecord.java | 8 ++++++++ .../java/com/android/server/am/ActivityStack.java | 14 +++++++++++++- .../java/com/android/server/wm/AppWindowToken.java | 8 ++++++-- .../android/server/wm/WindowManagerService.java | 4 ++-- .../src/android/view/IWindowManagerImpl.java | 3 ++- 6 files changed, 32 insertions(+), 7 deletions(-) diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 7de7d8aa22522..d2a37211cf2ce 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -176,7 +176,7 @@ interface IWindowManager in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded); void setAppVisibility(IBinder token, boolean visible); - void notifyAppResumed(IBinder token, boolean wasStopped); + void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface); void notifyAppStopped(IBinder token); void startAppFreezingScreen(IBinder token, int configChanges); void stopAppFreezingScreen(IBinder token, boolean force); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index cfb34b34c0865..03effe761d771 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -745,6 +745,14 @@ final class ActivityRecord { && intent.getType() == null; } + static boolean isMainIntent(Intent intent) { + return Intent.ACTION_MAIN.equals(intent.getAction()) + && intent.hasCategory(Intent.CATEGORY_LAUNCHER) + && intent.getCategories().size() == 1 + && intent.getData() == null + && intent.getType() == null; + } + private boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) { if (uid == Process.myUid() || uid == 0) { // System process can launch home activity. diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index fbd0ab566372e..dacbcc62c9b00 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2553,13 +2553,25 @@ final class ActivityStack { } } + boolean allowSavedSurface = true; if (next.newIntents != null) { + // Restrict saved surface to launcher start, or there is no intent at all + // (eg. task being brought to front). If the intent is something else, + // likely the app is going to show some specific page or view, instead of + // what's left last time. + for (int i = next.newIntents.size() - 1; i >= 0; i--) { + final Intent intent = next.newIntents.get(i); + if (!ActivityRecord.isMainIntent(intent)) { + allowSavedSurface = false; + break; + } + } next.app.thread.scheduleNewIntent(next.newIntents, next.appToken); } // Well the app will no longer be stopped. // Clear app token stopped state in window manager if needed. - mWindowManager.notifyAppResumed(next.appToken, next.stopped); + mWindowManager.notifyAppResumed(next.appToken, next.stopped, allowSavedSurface); EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId, System.identityHashCode(next), next.task.taskId, next.shortComponentName); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index e62d810e9d4fc..4b1cde7e0a8f2 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -597,12 +597,16 @@ class AppWindowToken extends WindowToken { * Notify that the app is now resumed, and it was not stopped before, perform a clean * up of the surfaces */ - void notifyAppResumed(boolean wasStopped) { - if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped + " " + this); + void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) { + if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped + + " allowSavedSurface=" + allowSavedSurface + " " + this); mAppStopped = false; if (!wasStopped) { destroySurfaces(true /*cleanupOnResume*/); } + if (!allowSavedSurface) { + destroySavedSurfaces(); + } } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 3819ebf9997fd..8389a86c7df57 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3580,7 +3580,7 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void notifyAppResumed(IBinder token, boolean wasStopped) { + public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "notifyAppResumed()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); @@ -3593,7 +3593,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token); return; } - wtoken.notifyAppResumed(wasStopped); + wtoken.notifyAppResumed(wasStopped, allowSavedSurface); } } diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 1cfb030ae2180..8b165bde22ac7 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -351,7 +351,8 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void notifyAppResumed(IBinder token, boolean wasStopped) throws RemoteException { + public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) + throws RemoteException { // TODO Auto-generated method stub }