diff options
| author | 2017-01-12 17:39:11 +0000 | |
|---|---|---|
| committer | 2017-01-12 17:39:15 +0000 | |
| commit | d96cc6e25081237d42a39d7e2ec48cbbc97988db (patch) | |
| tree | 27700bd808cdc72fb6b3d5900725c4f39e1ce5bb | |
| parent | fcd0a8bd2b429e5b066dab664ea2dd0f141f5153 (diff) | |
| parent | e2c77f903504766102fe545af40c3e4ebcb3adc7 (diff) | |
Merge changes I2ff9bd44,I946e681e,If72df07b
* changes:
Handle content insets for snapshots
Always remove starting window in performShow
Initial implementation of snapshots
38 files changed, 1315 insertions, 555 deletions
diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl index 5672f6bf84b1..29260e996663 100644 --- a/core/java/android/app/ActivityManager.aidl +++ b/core/java/android/app/ActivityManager.aidl @@ -26,4 +26,6 @@ parcelable ActivityManager.RunningTaskInfo; /** @hide */ parcelable ActivityManager.StackInfo; /** @hide */ -parcelable ActivityManager.TaskThumbnail;
\ No newline at end of file +parcelable ActivityManager.TaskThumbnail; +/** @hide */ +parcelable ActivityManager.TaskSnapshot;
\ No newline at end of file diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 90373043efc8..3170d0d97af0 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -26,6 +26,7 @@ import android.annotation.TestApi; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Canvas; +import android.graphics.GraphicBuffer; import android.graphics.Matrix; import android.graphics.Point; import android.os.BatteryStats; @@ -125,6 +126,16 @@ public class ActivityManager { private static volatile boolean sSystemReady = false; + /** + * System property to enable task snapshots. + * @hide + */ + public final static boolean ENABLE_TASK_SNAPSHOTS; + + static { + ENABLE_TASK_SNAPSHOTS = SystemProperties.getBoolean("persist.enable_task_snapshots", false); + } + static final class UidObserver extends IUidObserver.Stub { final OnUidImportanceListener mListener; @@ -2115,6 +2126,62 @@ public class ActivityManager { }; } + /** + * Represents a task snapshot. + * @hide + */ + public static class TaskSnapshot implements Parcelable { + + private final GraphicBuffer mSnapshot; + private final int mOrientation; + private final Rect mContentInsets; + + public TaskSnapshot(GraphicBuffer snapshot, int orientation, Rect contentInsets) { + mSnapshot = snapshot; + mOrientation = orientation; + mContentInsets = new Rect(contentInsets); + } + + private TaskSnapshot(Parcel source) { + mSnapshot = source.readParcelable(null /* classLoader */); + mOrientation = source.readInt(); + mContentInsets = source.readParcelable(null /* classLoader */); + } + + public GraphicBuffer getSnapshot() { + return mSnapshot; + } + + public int getOrientation() { + return mOrientation; + } + + public Rect getContentInsets() { + return mContentInsets; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mSnapshot, 0); + dest.writeInt(mOrientation); + dest.writeParcelable(mContentInsets, 0); + } + + public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() { + public TaskSnapshot createFromParcel(Parcel source) { + return new TaskSnapshot(source); + } + public TaskSnapshot[] newArray(int size) { + return new TaskSnapshot[size]; + } + }; + } + /** @hide */ public TaskThumbnail getTaskThumbnail(int id) throws SecurityException { try { diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 2ed9eab46277..21ae853918f6 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -53,6 +53,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.GraphicBuffer; import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; @@ -596,6 +597,11 @@ interface IActivityManager { /** Cancels the thumbnail transitions for the given task. */ void cancelTaskThumbnailTransition(int taskId); + /** + * @return a graphic buffer representing a screenshot of a task + */ + ActivityManager.TaskSnapshot getTaskSnapshot(int taskId); + // WARNING: when these transactions are updated, check if they are any callers on the native // side. If so, make sure they are using the correct transaction ids and arguments. // If a transaction which will also be used on the native side is being inserted, add it diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index c0ebd2c4b8e7..19edb5c830d6 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -48,6 +48,7 @@ import android.view.InputDevice; import android.view.IInputFilter; import android.view.AppTransitionAnimationSpec; import android.view.WindowContentFrameStats; +import android.view.WindowManager; /** * System private interface to the window manager. diff --git a/core/java/android/view/WindowManager.aidl b/core/java/android/view/WindowManager.aidl index 556dc72185a5..1363f05d3787 100644 --- a/core/java/android/view/WindowManager.aidl +++ b/core/java/android/view/WindowManager.aidl @@ -18,4 +18,5 @@ package android.view; parcelable WindowManager.LayoutParams; - +/** @hide */ +parcelable WindowManager.TaskSnapshot; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index aa7631de55a7..e5a6ebdfb9e0 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -22,6 +22,7 @@ import android.app.KeyguardManager; import android.app.Presentation; import android.content.Context; import android.content.pm.ActivityInfo; +import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.IBinder; @@ -1319,6 +1320,17 @@ public interface WindowManager extends ViewManager { public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00040000; /** + * Flag to indicate that this window is used as a task snapshot window. A task snapshot + * window is a starting window that gets shown with a screenshot from the previous state + * that is active until the app has drawn its first frame. + * + * <p>If this flag is set, SystemUI flags are ignored such that the real window behind can + * set the SystemUI flags. + * @hide + */ + public static final int PRIVATE_FLAG_TASK_SNAPSHOT = 0x00080000; + + /** * Control flags that are private to the platform. * @hide */ diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index dd852567360f..374813458c90 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -439,10 +439,15 @@ public interface WindowManagerPolicy { /** * 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. + * held by WM and released with {@link #remove} when no longer needed. */ interface StartingSurface { + + /** + * Removes the starting window surface. Do not hold the window manager lock when calling + * this method! + */ + void remove(); } /** @@ -746,35 +751,14 @@ public interface WindowManagerPolicy { * @param overrideConfig override configuration to consider when generating * context to for resources. * - * @return Optionally you can return the View that was used to create the - * window, for easy removal in removeSplashScreen. + * @return The starting surface. * - * @see #removeSplashScreen */ 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 #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. - * - * <p>Note: due to the nature of these functions not being called with the - * window manager locked, you must be prepared for this function to be - * called multiple times and/or an initial time with a null View window - * even if you previously returned one. - * - * @param appToken Token of the application that has started. - * @param surface Surface that was returned by {@link #addSplashScreen}. - * - * @see #addSplashScreen - */ - public void removeSplashScreen(IBinder appToken, StartingSurface surface); - - /** * Prepare for a window being added to the window manager. You can throw an * exception here to prevent the window being added, or do whatever setup * you need to keep track of the window. diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 779113216530..3587b89b73e0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -28,7 +28,7 @@ import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.IActivityManager; -import android.app.ITaskStackListener; +import android.app.KeyguardManager; import android.app.UiModeManager; import android.content.ComponentName; import android.content.ContentResolver; @@ -74,7 +74,6 @@ import android.view.WindowManager; import android.view.WindowManager.KeyboardShortcutsReceiver; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; -import android.app.KeyguardManager; import com.android.internal.app.AssistUtils; import com.android.internal.os.BackgroundThread; @@ -603,7 +602,7 @@ public class SystemServicesProxy { } getThumbnail(taskId, thumbnailData); - if (thumbnailData.thumbnail != null) { + if (thumbnailData.thumbnail != null && !ActivityManager.ENABLE_TASK_SNAPSHOTS) { thumbnailData.thumbnail.setHasAlpha(false); // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top // left pixel, then assume the whole thumbnail is transparent. Generally, proper @@ -627,25 +626,42 @@ public class SystemServicesProxy { return; } - ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId); - if (taskThumbnail == null) { - return; - } - - Bitmap thumbnail = taskThumbnail.mainThumbnail; - ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor; - if (thumbnail == null && descriptor != null) { - thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor(), - null, sBitmapOptions); - } - if (descriptor != null) { + if (ActivityManager.ENABLE_TASK_SNAPSHOTS) { + ActivityManager.TaskSnapshot snapshot = null; try { - descriptor.close(); - } catch (IOException e) { + snapshot = ActivityManager.getService().getTaskSnapshot(taskId); + } catch (RemoteException e) { + Log.w(TAG, "Failed to retrieve snapshot", e); + } + if (snapshot != null) { + thumbnailDataOut.thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot()); + thumbnailDataOut.orientation = snapshot.getOrientation(); + thumbnailDataOut.insets.set(snapshot.getContentInsets()); + } else { + thumbnailDataOut.thumbnail = null; + } + } else { + ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId); + if (taskThumbnail == null) { + return; + } + + Bitmap thumbnail = taskThumbnail.mainThumbnail; + ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor; + if (thumbnail == null && descriptor != null) { + thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor(), + null, sBitmapOptions); + } + if (descriptor != null) { + try { + descriptor.close(); + } catch (IOException e) { + } } + thumbnailDataOut.thumbnail = thumbnail; + thumbnailDataOut.orientation = taskThumbnail.thumbnailInfo.screenOrientation; + thumbnailDataOut.insets.setEmpty(); } - thumbnailDataOut.thumbnail = thumbnail; - thumbnailDataOut.thumbnailInfo = taskThumbnail.thumbnailInfo; } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java index ba31e3e835c0..6ea51e57ae42 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -220,8 +220,7 @@ class BackgroundTaskLoader implements Runnable { mMainThreadHandler.post(new Runnable() { @Override public void run() { - t.notifyTaskDataLoaded(newThumbnailData.thumbnail, newIcon, - newThumbnailData.thumbnailInfo); + t.notifyTaskDataLoaded(newThumbnailData, newIcon); } }); } @@ -364,11 +363,9 @@ public class RecentsTaskLoader { public void loadTaskData(Task t) { Drawable icon = mIconCache.getAndInvalidateIfModified(t.key); Bitmap thumbnail = null; - ActivityManager.TaskThumbnailInfo thumbnailInfo = null; ThumbnailData thumbnailData = mThumbnailCache.getAndInvalidateIfModified(t.key); if (thumbnailData != null) { thumbnail = thumbnailData.thumbnail; - thumbnailInfo = thumbnailData.thumbnailInfo; } // Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and @@ -378,8 +375,7 @@ public class RecentsTaskLoader { if (requiresLoad) { mLoadQueue.addTask(t); } - t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, icon, - thumbnailInfo); + t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnailData, icon); } /** Releases the task resource data back into the pool. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index 53f713a83cb0..2f2e866cd159 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -45,7 +45,7 @@ public class Task { /* Task callbacks */ public interface TaskCallbacks { /* Notifies when a task has been bound */ - public void onTaskDataLoaded(Task task, ActivityManager.TaskThumbnailInfo thumbnailInfo); + public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData); /* Notifies when a task has been unbound */ public void onTaskDataUnloaded(); /* Notifies when a task's stack id has changed. */ @@ -299,13 +299,12 @@ public class Task { } /** Notifies the callback listeners that this task has been loaded */ - public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon, - ActivityManager.TaskThumbnailInfo thumbnailInfo) { + public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) { this.icon = applicationIcon; - this.thumbnail = thumbnail; + this.thumbnail = thumbnailData != null ? thumbnailData.thumbnail : null; int callbackCount = mCallbacks.size(); for (int i = 0; i < callbackCount; i++) { - mCallbacks.get(i).onTaskDataLoaded(this, thumbnailInfo); + mCallbacks.get(i).onTaskDataLoaded(this, thumbnailData); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java index d0cdae56265d..18735ac6536c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java @@ -16,13 +16,14 @@ package com.android.systemui.recents.model; -import android.app.ActivityManager; import android.graphics.Bitmap; +import android.graphics.Rect; /** * Data for a single thumbnail. */ public class ThumbnailData { public Bitmap thumbnail; - public ActivityManager.TaskThumbnailInfo thumbnailInfo; + public int orientation; + public final Rect insets = new Rect(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 36d5f838a070..5f37349e860a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -57,6 +57,7 @@ import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.recents.model.ThumbnailData; import java.io.PrintWriter; import java.util.ArrayList; @@ -620,9 +621,9 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks } @Override - public void onTaskDataLoaded(Task task, ActivityManager.TaskThumbnailInfo thumbnailInfo) { + public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) { // Update each of the views to the new task data - mThumbnailView.onTaskDataLoaded(thumbnailInfo); + mThumbnailView.onTaskDataLoaded(thumbnailData); mHeaderView.onTaskDataLoaded(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java index 58b929ac690a..3ae51b0bde35 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -16,7 +16,6 @@ package com.android.systemui.recents.views; -import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; import android.graphics.Bitmap; @@ -37,7 +36,7 @@ import android.view.ViewDebug; import com.android.systemui.R; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; - +import com.android.systemui.recents.model.ThumbnailData; import java.io.PrintWriter; @@ -65,12 +64,12 @@ public class TaskViewThumbnail extends View { private float mFullscreenThumbnailScale; private boolean mSizeToFit = false; private boolean mOverlayHeaderOnThumbnailActionBar = true; - private ActivityManager.TaskThumbnailInfo mThumbnailInfo; + private ThumbnailData mThumbnailData; private int mCornerRadius; @ViewDebug.ExportedProperty(category="recents") private float mDimAlpha; - private Matrix mScaleMatrix = new Matrix(); + private Matrix mMatrix = new Matrix(); private Paint mDrawPaint = new Paint(); private Paint mLockedPaint = new Paint(); private Paint mBgFillPaint = new Paint(); @@ -125,7 +124,7 @@ public class TaskViewThumbnail extends View { mTaskViewRect.set(0, 0, width, height); setLeftTopRightBottom(0, 0, width, height); - updateThumbnailScale(); + updateThumbnailMatrix(); } @Override @@ -174,19 +173,22 @@ public class TaskViewThumbnail extends View { } /** Sets the thumbnail to a given bitmap. */ - void setThumbnail(Bitmap bm, ActivityManager.TaskThumbnailInfo thumbnailInfo) { - if (bm != null) { + void setThumbnail(ThumbnailData thumbnailData) { + if (thumbnailData != null && thumbnailData.thumbnail != null) { + Bitmap bm = thumbnailData.thumbnail; bm.prepareToDraw(); mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mDrawPaint.setShader(mBitmapShader); - mThumbnailRect.set(0, 0, bm.getWidth(), bm.getHeight()); - mThumbnailInfo = thumbnailInfo; - updateThumbnailScale(); + mThumbnailRect.set(0, 0, + bm.getWidth() - thumbnailData.insets.left - thumbnailData.insets.right, + bm.getHeight() - thumbnailData.insets.top - thumbnailData.insets.bottom); + mThumbnailData = thumbnailData; + updateThumbnailMatrix(); } else { mBitmapShader = null; mDrawPaint.setShader(null); mThumbnailRect.setEmpty(); - mThumbnailInfo = null; + mThumbnailData = null; } } @@ -233,21 +235,21 @@ public class TaskViewThumbnail extends View { /** * Updates the scale of the bitmap relative to this view. */ - public void updateThumbnailScale() { + public void updateThumbnailMatrix() { mThumbnailScale = 1f; - if (mBitmapShader != null) { + if (mBitmapShader != null && mThumbnailData != null) { // We consider this a stack task if it is not freeform (ie. has no bounds) or has been // dragged into the stack from the freeform workspace boolean isStackTask = !mTask.isFreeformTask() || mTask.bounds == null; - if (mTaskViewRect.isEmpty() || mThumbnailInfo == null || - mThumbnailInfo.taskWidth == 0 || mThumbnailInfo.taskHeight == 0) { - // If we haven't measured or the thumbnail is invalid, skip the thumbnail drawing - // and only draw the background color + int xOffset, yOffset = 0; + if (mTaskViewRect.isEmpty()) { + // If we haven't measured , skip the thumbnail drawing and only draw the background + // color mThumbnailScale = 0f; } else if (isStackTask && !mSizeToFit) { float invThumbnailScale = 1f / mFullscreenThumbnailScale; if (mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT) { - if (mThumbnailInfo.screenOrientation == Configuration.ORIENTATION_PORTRAIT) { + if (mThumbnailData.orientation == Configuration.ORIENTATION_PORTRAIT) { // If we are in the same orientation as the screenshot, just scale it to the // width of the task view mThumbnailScale = (float) mTaskViewRect.width() / mThumbnailRect.width(); @@ -268,8 +270,9 @@ public class TaskViewThumbnail extends View { (float) mTaskViewRect.width() / mThumbnailRect.width(), (float) mTaskViewRect.height() / mThumbnailRect.height()); } - mScaleMatrix.setScale(mThumbnailScale, mThumbnailScale); - mBitmapShader.setLocalMatrix(mScaleMatrix); + mMatrix.setTranslate(-mThumbnailData.insets.left, -mThumbnailData.insets.top); + mMatrix.postScale(mThumbnailScale, mThumbnailScale); + mBitmapShader.setLocalMatrix(mMatrix); } if (!mInvisible) { invalidate(); @@ -333,18 +336,14 @@ public class TaskViewThumbnail extends View { * Called when the bound task's data has loaded and this view should update to reflect the * changes. */ - void onTaskDataLoaded(ActivityManager.TaskThumbnailInfo thumbnailInfo) { - if (mTask.thumbnail != null) { - setThumbnail(mTask.thumbnail, thumbnailInfo); - } else { - setThumbnail(null, null); - } + void onTaskDataLoaded(ThumbnailData thumbnailData) { + setThumbnail(thumbnailData); } /** Unbinds the thumbnail view from the task */ void unbindFromTask() { mTask = null; - setThumbnail(null, null); + setThumbnail(null); } public void dump(String prefix, PrintWriter writer) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java index 630040098d10..a86abf629109 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java @@ -51,7 +51,7 @@ public class GridTaskView extends TaskView { // Show the full thumbnail and don't overlap with the header. mThumbnailView.setSizeToFit(true); mThumbnailView.setOverlayHeaderOnThumbnailActionBar(false); - mThumbnailView.updateThumbnailScale(); + mThumbnailView.updateThumbnailMatrix(); mThumbnailView.setTranslationY(mHeaderHeight); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 48a7e7cffa15..74304f033165 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -16,73 +16,142 @@ package com.android.server.am; -import android.annotation.Nullable; -import android.app.ActivityManagerInternal.PictureInPictureArguments; -import android.app.ApplicationThreadConstants; -import android.app.ContentProviderHolder; -import android.app.IActivityManager; -import android.app.RemoteAction; -import android.app.WaitResult; -import android.os.IDeviceIdentifiersPolicyService; - -import com.android.internal.policy.IKeyguardDismissCallback; -import com.android.internal.telephony.TelephonyIntents; -import com.google.android.collect.Lists; -import com.google.android.collect.Maps; -import com.android.internal.R; -import com.android.internal.annotations.GuardedBy; -import com.android.internal.app.AssistUtils; -import com.android.internal.app.DumpHeapActivity; -import com.android.internal.app.IAppOpsCallback; -import com.android.internal.app.IAppOpsService; -import com.android.internal.app.IVoiceInteractor; -import com.android.internal.app.ProcessMap; -import com.android.internal.app.SystemUserHomeActivity; -import com.android.internal.app.procstats.ProcessStats; -import com.android.internal.os.BackgroundThread; -import com.android.internal.os.BatteryStatsImpl; -import com.android.internal.os.IResultReceiver; -import com.android.internal.os.ProcessCpuTracker; -import com.android.internal.os.TransferPipe; -import com.android.internal.os.Zygote; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.FastPrintWriter; -import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.MemInfoReader; -import com.android.internal.util.Preconditions; -import com.android.server.AppOpsService; -import com.android.server.AttributeCache; -import com.android.server.DeviceIdleController; -import com.android.server.IntentResolver; -import com.android.server.LocalServices; -import com.android.server.LockGuard; -import com.android.server.ServiceThread; -import com.android.server.SystemService; -import com.android.server.SystemServiceManager; -import com.android.server.Watchdog; -import com.android.server.am.ActivityStack.ActivityState; -import com.android.server.firewall.IntentFirewall; -import com.android.server.pm.Installer; -import com.android.server.pm.Installer.InstallerException; -import com.android.server.statusbar.StatusBarManagerInternal; -import com.android.server.vr.VrManagerInternal; -import com.android.server.wm.WindowManagerService; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; +import static android.Manifest.permission.CHANGE_CONFIGURATION; +import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; +import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; +import static android.Manifest.permission.READ_FRAME_BUFFER; +import static android.Manifest.permission.START_TASKS_FROM_RECENTS; +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; +import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; +import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY; +import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; +import static android.content.pm.PackageManager.GET_PROVIDERS; +import static android.content.pm.PackageManager.MATCH_ANY_USER; +import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; +import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION; +import static android.os.Build.VERSION_CODES.N; +import static android.os.Process.PROC_CHAR; +import static android.os.Process.PROC_OUT_LONG; +import static android.os.Process.PROC_PARENS; +import static android.os.Process.PROC_SPACE_TERM; +import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES; +import static android.provider.Settings.Global.DEBUG_APP; +import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; +import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES; +import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL; +import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER; +import static android.provider.Settings.System.FONT_SCALE; +import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.internal.util.XmlUtils.readBooleanAttribute; +import static com.android.internal.util.XmlUtils.readIntAttribute; +import static com.android.internal.util.XmlUtils.readLongAttribute; +import static com.android.internal.util.XmlUtils.writeBooleanAttribute; +import static com.android.internal.util.XmlUtils.writeIntAttribute; +import static com.android.internal.util.XmlUtils.writeLongAttribute; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKSCREEN; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_OOM_ADJ; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_POWER; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESSES; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS; +import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME; +import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS; +import static com.android.server.am.ActivityStackSupervisor.ON_TOP; +import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; +import static com.android.server.am.ActivityStackSupervisor.RESTORE_FROM_RECENTS; +import static com.android.server.am.TaskRecord.INVALID_TASK_ID; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE; +import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN; +import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH; +import static com.android.server.wm.AppTransition.TRANSIT_NONE; +import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE; +import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN; +import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT; +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.Manifest; import android.Manifest.permission; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackId; import android.app.ActivityManager.StackInfo; +import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManager.TaskThumbnailInfo; import android.app.ActivityManagerInternal; +import android.app.ActivityManagerInternal.PictureInPictureArguments; import android.app.ActivityManagerInternal.SleepToken; import android.app.ActivityOptions; import android.app.ActivityThread; @@ -90,11 +159,14 @@ import android.app.AlertDialog; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.ApplicationErrorReport; +import android.app.ApplicationThreadConstants; import android.app.BroadcastOptions; +import android.app.ContentProviderHolder; import android.app.Dialog; import android.app.IActivityContainer; import android.app.IActivityContainerCallback; import android.app.IActivityController; +import android.app.IActivityManager; import android.app.IAppTask; import android.app.IApplicationThread; import android.app.IInstrumentationWatcher; @@ -111,6 +183,8 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.ProfilerInfo; +import android.app.RemoteAction; +import android.app.WaitResult; import android.app.admin.DevicePolicyManager; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; @@ -155,6 +229,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; +import android.graphics.GraphicBuffer; import android.graphics.Point; import android.graphics.Rect; import android.location.LocationManager; @@ -173,6 +248,7 @@ import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; +import android.os.IDeviceIdentifiersPolicyService; import android.os.IPermissionController; import android.os.IProcessInfoService; import android.os.IProgressListener; @@ -200,8 +276,8 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.os.storage.IStorageManager; -import android.os.storage.StorageManagerInternal; import android.os.storage.StorageManager; +import android.os.storage.StorageManagerInternal; import android.provider.Downloads; import android.provider.Settings; import android.service.autofill.AutoFillService; @@ -232,6 +308,54 @@ import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; +import com.google.android.collect.Lists; +import com.google.android.collect.Maps; + +import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.app.AssistUtils; +import com.android.internal.app.DumpHeapActivity; +import com.android.internal.app.IAppOpsCallback; +import com.android.internal.app.IAppOpsService; +import com.android.internal.app.IVoiceInteractor; +import com.android.internal.app.ProcessMap; +import com.android.internal.app.SystemUserHomeActivity; +import com.android.internal.app.procstats.ProcessStats; +import com.android.internal.os.BackgroundThread; +import com.android.internal.os.BatteryStatsImpl; +import com.android.internal.os.IResultReceiver; +import com.android.internal.os.ProcessCpuTracker; +import com.android.internal.os.TransferPipe; +import com.android.internal.os.Zygote; +import com.android.internal.policy.IKeyguardDismissCallback; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.MemInfoReader; +import com.android.internal.util.Preconditions; +import com.android.server.AppOpsService; +import com.android.server.AttributeCache; +import com.android.server.DeviceIdleController; +import com.android.server.IntentResolver; +import com.android.server.LocalServices; +import com.android.server.LockGuard; +import com.android.server.ServiceThread; +import com.android.server.SystemService; +import com.android.server.SystemServiceManager; +import com.android.server.Watchdog; +import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.firewall.IntentFirewall; +import com.android.server.pm.Installer; +import com.android.server.pm.Installer.InstallerException; +import com.android.server.statusbar.StatusBarManagerInternal; +import com.android.server.vr.VrManagerInternal; +import com.android.server.wm.WindowManagerService; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -255,138 +379,15 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.CountDownLatch; import dalvik.system.VMRuntime; - import libcore.io.IoUtils; import libcore.util.EmptyArray; -import static android.Manifest.permission.CHANGE_CONFIGURATION; -import static android.Manifest.permission.INTERACT_ACROSS_USERS; -import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; -import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; -import static android.Manifest.permission.START_TASKS_FROM_RECENTS; -import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; -import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; -import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY; -import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; -import static android.content.pm.PackageManager.GET_PROVIDERS; -import static android.content.pm.PackageManager.MATCH_ANY_USER; -import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; -import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; -import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; -import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; -import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION; -import static android.os.Build.VERSION_CODES.N; -import static android.os.Process.PROC_CHAR; -import static android.os.Process.PROC_OUT_LONG; -import static android.os.Process.PROC_PARENS; -import static android.os.Process.PROC_SPACE_TERM; -import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES; -import static android.provider.Settings.Global.DEBUG_APP; -import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; -import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES; -import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL; -import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER; -import static android.provider.Settings.System.FONT_SCALE; -import static android.view.Display.DEFAULT_DISPLAY; - -import static com.android.internal.util.XmlUtils.readBooleanAttribute; -import static com.android.internal.util.XmlUtils.readIntAttribute; -import static com.android.internal.util.XmlUtils.readLongAttribute; -import static com.android.internal.util.XmlUtils.writeBooleanAttribute; -import static com.android.internal.util.XmlUtils.writeIntAttribute; -import static com.android.internal.util.XmlUtils.writeLongAttribute; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKSCREEN; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_OOM_ADJ; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_POWER; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESSES; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND; -import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; -import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS; import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED; -import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME; -import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS; -import static com.android.server.am.ActivityStackSupervisor.ON_TOP; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; -import static com.android.server.am.ActivityStackSupervisor.RESTORE_FROM_RECENTS; -import static com.android.server.am.TaskRecord.INVALID_TASK_ID; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE; -import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN; -import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH; -import static com.android.server.wm.AppTransition.TRANSIT_NONE; -import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE; -import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN; -import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT; -import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; -import static org.xmlpull.v1.XmlPullParser.START_TAG; - public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { @@ -9654,6 +9655,25 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public TaskSnapshot getTaskSnapshot(int taskId) { + enforceCallingPermission(READ_FRAME_BUFFER, "getTaskSnapshot()"); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (this) { + final TaskRecord task = mStackSupervisor.anyTaskForIdLocked( + taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID); + if (task == null) { + Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found"); + return null; + } + return task.getSnapshot(); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override public Bitmap getTaskDescriptionIcon(String filePath, int userId) { if (userId != UserHandle.getCallingUserId()) { enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, @@ -9802,6 +9822,15 @@ public class ActivityManagerService extends IActivityManager.Stub } mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront", false /* forceNonResizable */); + + final ActivityRecord topActivity = task.getTopActivity(); + if (topActivity != null) { + + // We are reshowing a task, use a starting window to hide the initial draw delay + // so the transition can start earlier. + topActivity.showStartingWindow(null /* prev */, false /* newTask */, + true /* taskSwitch */); + } } finally { Binder.restoreCallingIdentity(origId); } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 2963ad1d54f6..47c3e6f80996 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS; import static android.app.ActivityManager.StackId; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; @@ -26,11 +27,11 @@ import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; +import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE; import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; -import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED; import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; @@ -103,6 +104,10 @@ import com.android.server.wm.AppWindowContainerController; import com.android.server.wm.AppWindowContainerListener; import com.android.server.wm.TaskWindowContainerController; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -113,10 +118,6 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - /** * An entry in the history stack, representing an activity. */ @@ -1204,6 +1205,14 @@ final class ActivityRecord implements AppWindowContainerListener { final Bitmap screenshotActivityLocked() { if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "screenshotActivityLocked: " + this); + + if (ENABLE_TASK_SNAPSHOTS) { + // No need to screenshot if snapshots are enabled. + if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, + "\tSnapshots are enabled, abort taking screenshot"); + return null; + } + if (noDisplay) { if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tNo display"); return null; @@ -1792,12 +1801,12 @@ final class ActivityRecord implements AppWindowContainerListener { pendingVoiceInteractionStart = false; } - void showStartingWindow(ActivityRecord prev, boolean createIfNeeded) { + void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) { final CompatibilityInfo compatInfo = service.compatibilityInfoForPackageLocked(info.applicationInfo); final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, - prev != null ? prev.appToken : null, createIfNeeded); + prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning()); if (shown) { mStartingWindowState = STARTING_WINDOW_SHOWN; } @@ -2089,6 +2098,14 @@ final class ActivityRecord implements AppWindowContainerListener { preserveWindowOnDeferredRelaunch = false; } + boolean isProcessRunning() { + ProcessRecord proc = app; + if (proc == null) { + proc = service.mProcessNames.get(processName, info.applicationInfo.uid); + } + return proc != null && proc.thread != null; + } + void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { out.attribute(null, ATTR_ID, String.valueOf(createTime)); out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid)); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index ab65eb126150..abcaa249744f 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2459,7 +2459,8 @@ final class ActivityStack extends ConfigurationContainer { next.hasBeenLaunched = true; } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null && mStackSupervisor.isFrontStack(lastStack)) { - next.showStartingWindow(null, true); + next.showStartingWindow(null /* prev */, false /* newTask */, + false /* taskSwitch */); } mStackSupervisor.startSpecificActivityLocked(next, true, false); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); @@ -2485,7 +2486,8 @@ final class ActivityStack extends ConfigurationContainer { next.hasBeenLaunched = true; } else { if (SHOW_APP_STARTING_PREVIEW) { - next.showStartingWindow(null, true); + next.showStartingWindow(null /* prev */, false /* newTask */, + false /* taskSwich */); } if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); } @@ -2686,17 +2688,6 @@ final class ActivityStack extends ConfigurationContainer { task.setFrontOfTask(); if (!isHomeOrRecentsStack() || numActivities() > 0) { - // We want to show the starting preview window if we are - // switching to a new task, or the next activity's process is - // not currently running. - boolean showStartingIcon = newTask; - ProcessRecord proc = r.app; - if (proc == null) { - proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid); - } - if (proc == null || proc.thread == null) { - showStartingIcon = true; - } if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: starting " + r); if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) { @@ -2756,7 +2747,7 @@ final class ActivityStack extends ConfigurationContainer { prev = null; } } - r.showStartingWindow(prev, showStartingIcon); + r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity)); } } else { // If this is the first activity, don't do any fancy animations, @@ -2765,6 +2756,11 @@ final class ActivityStack extends ConfigurationContainer { } } + private boolean isTaskSwitch(ActivityRecord r, + ActivityRecord topFocusedActivity) { + return topFocusedActivity != null && r.task != topFocusedActivity.task; + } + /** * Perform a reset of the given task, if needed as part of launching it. * Returns the new HistoryRecord at the top of the task. diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 61e3ad5ea052..f401863acf42 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -31,8 +31,8 @@ import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.app.ActivityManager.StackId.isStaticStack; import static android.app.ActivityManager.StackId.RECENTS_STACK_ID; +import static android.app.ActivityManager.StackId.isStaticStack; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; @@ -53,7 +53,6 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; import static android.view.Display.INVALID_DISPLAY; - import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; @@ -106,7 +105,6 @@ import android.hardware.power.V1_0.PowerHint; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; -import android.os.PowerManagerInternal; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -1509,6 +1507,11 @@ class ActivityStarter { mMovedToFront = true; } mOptions = null; + + // We are moving a task to the front, use starting window to hide initial drawn + // delay. + intentActivity.showStartingWindow(null /* prev */, false /* newTask */, + true /* taskSwitch */); } updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack); } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index d0eac775e320..9e22c505f9bf 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -21,6 +21,7 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.StackId; import android.app.ActivityManager.TaskDescription; +import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManager.TaskThumbnail; import android.app.ActivityManager.TaskThumbnailInfo; import android.app.ActivityOptions; @@ -34,6 +35,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.GraphicBuffer; import android.graphics.Point; import android.graphics.Rect; import android.os.Debug; @@ -545,6 +547,13 @@ final class TaskRecord extends ConfigurationContainer { mWindowContainerController.cancelThumbnailTransition(); } + public TaskSnapshot getSnapshot() { + if (mWindowContainerController == null) { + return null; + } + return mWindowContainerController.getSnapshot(); + } + void touchActiveTime() { lastActiveTime = System.currentTimeMillis(); if (firstActiveTime == 0) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 0a312f0ad7ee..4b2b184d1bbc 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -51,6 +51,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_ST import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT; @@ -2907,7 +2908,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 ? new SplashScreenSurface(view) : null; + return view.getParent() != null ? new SplashScreenSurface(view, appToken) : null; } catch (WindowManager.BadTokenException e) { // ignore Log.w(TAG, appToken + " already running, starting window not displayed. " + @@ -2927,18 +2928,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return null; } - /** {@inheritDoc} */ - @Override - 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 (surface != null) { - WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); - wm.removeView(((SplashScreenSurface) surface).view); - } - } - /** * Preflight adding a window to the system. * @@ -5185,7 +5174,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget) { - final boolean visible = win.isVisibleLw(); + final boolean visible = !win.isGoneForLayoutLw(); if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisible=" + visible); applyKeyguardPolicyLw(win, imeTarget); final int fl = PolicyControl.getWindowFlags(win, attrs); @@ -5202,8 +5191,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + // Don't allow snapshots to influence SystemUI visibility flags. + // TODO: Revisit this once SystemUI flags for snapshots are handled correctly boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type < FIRST_SYSTEM_WINDOW; + && attrs.type < FIRST_SYSTEM_WINDOW + && (attrs.privateFlags & PRIVATE_FLAG_TASK_SNAPSHOT) == 0; final int stackId = win.getStackId(); if (mTopFullscreenOpaqueWindowState == null && visible) { if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) { diff --git a/services/core/java/com/android/server/policy/SplashScreenSurface.java b/services/core/java/com/android/server/policy/SplashScreenSurface.java index d4212915c0a6..37d6c0b55d54 100644 --- a/services/core/java/com/android/server/policy/SplashScreenSurface.java +++ b/services/core/java/com/android/server/policy/SplashScreenSurface.java @@ -16,7 +16,13 @@ package com.android.server.policy; +import static com.android.server.policy.PhoneWindowManager.DEBUG_SPLASH_SCREEN; + +import android.os.Debug; +import android.os.IBinder; +import android.util.Slog; import android.view.View; +import android.view.WindowManager; import android.view.WindowManagerPolicy; import android.view.WindowManagerPolicy.StartingSurface; @@ -30,9 +36,21 @@ import com.android.internal.policy.PhoneWindow; */ class SplashScreenSurface implements StartingSurface { - final View view; + private static final String TAG = PhoneWindowManager.TAG; + private final View mView; + private final IBinder mAppToken; + + SplashScreenSurface(View view, IBinder appToken) { + mView = view; + mAppToken = appToken; + } + + @Override + public void remove() { + if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + mAppToken + ": " + + this + " Callers=" + Debug.getCallers(4)); - SplashScreenSurface(View view) { - this.view = view; + final WindowManager wm = mView.getContext().getSystemService(WindowManager.class); + wm.removeView(mView); } } diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index d2f604d67132..1eb74fa41f33 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -28,6 +28,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMEN import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.app.ActivityManager.TaskSnapshot; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; @@ -50,6 +51,10 @@ import com.android.server.AttributeCache; public class AppWindowContainerController extends WindowContainerController<AppWindowToken, AppWindowContainerListener> { + private static final int STARTING_WINDOW_TYPE_NONE = 0; + private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1; + private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2; + private final IApplicationToken mToken; private final Handler mHandler = new Handler(Looper.getMainLooper()); @@ -80,16 +85,39 @@ public class AppWindowContainerController mListener.onWindowsGone(); }; + private final Runnable mRemoveStartingWindow = () -> { + StartingSurface surface = null; + StartingData data = null; + synchronized (mWindowMap) { + if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer + + ": startingWindow=" + mContainer.startingWindow + + " startingView=" + mContainer.startingSurface); + if (mContainer.startingWindow != null) { + surface = mContainer.startingSurface; + data = mContainer.startingData; + mContainer.startingData = null; + mContainer.startingSurface = null; + mContainer.startingWindow = null; + mContainer.startingDisplayed = false; + } + } + if (data != null && surface != null) { + try { + surface.remove(); + } catch (Exception e) { + Slog.w(TAG_WM, "Exception when removing starting window", e); + } + } + }; + private final Runnable mAddStartingWindow = () -> { final StartingData startingData; - final Configuration mergedOverrideConfiguration; synchronized (mWindowMap) { if (mContainer == null) { return; } startingData = mContainer.startingData; - mergedOverrideConfiguration = mContainer.getMergedOverrideConfiguration(); } if (startingData == null) { @@ -98,20 +126,16 @@ public class AppWindowContainerController } if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting " - + this + ": pkg=" + mContainer.startingData.pkg); + + this + ": startingData=" + mContainer.startingData); - StartingSurface contents = null; + StartingSurface surface = 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); + surface = startingData.createStartingSurface(); } catch (Exception e) { Slog.w(TAG_WM, "Exception when adding starting window", e); } - if (contents != null) { + if (surface != null) { boolean abort = false; - synchronized(mWindowMap) { if (mContainer.removed || mContainer.startingData == null) { // If the window was successfully added, then @@ -121,12 +145,10 @@ public class AppWindowContainerController "Aborted starting " + mContainer + ": removed=" + mContainer.removed + " startingData=" + mContainer.startingData); - mContainer.startingWindow = null; - mContainer.startingData = null; abort = true; } } else { - mContainer.startingSurface = contents; + mContainer.startingSurface = surface; } if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM, "Added starting " + mContainer @@ -134,42 +156,11 @@ public class AppWindowContainerController + 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); + mRemoveStartingWindow.run(); if (mContainer == null) { return; } - 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); } } }; @@ -389,7 +380,7 @@ public class AppWindowContainerController public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, - IBinder transferFrom, boolean createIfNeeded) { + IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning) { synchronized(mWindowMap) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken + " pkg=" + pkg + " transferFrom=" + transferFrom); @@ -409,6 +400,12 @@ public class AppWindowContainerController return false; } + final int type = getStartingWindowType(newTask, taskSwitch, processRunning); + + if (type == STARTING_WINDOW_TYPE_SNAPSHOT) { + return createSnapshot(); + } + // If this is a translucent window, then don't show a starting window -- the current // effect (a full-screen opaque starting window that fades away to the real contents // when it is ready) does not work for this. @@ -458,22 +455,32 @@ public class AppWindowContainerController return true; } - // There is no existing starting window, and the caller doesn't - // want us to create one, so that's it! - if (!createIfNeeded) { + // There is no existing starting window, and we don't want to create a splash screen, so + // that's it! + if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) { return false; } if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData"); - mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel, - labelRes, icon, logo, windowFlags); + mContainer.startingData = new SplashScreenStartingData(mService, mContainer, pkg, theme, + compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, + mContainer.getMergedOverrideConfiguration()); scheduleAddStartingWindow(); } return true; } - void scheduleAddStartingWindow() { + private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning) { + if (newTask || !processRunning) { + return STARTING_WINDOW_TYPE_SPLASH_SCREEN; + } else if (taskSwitch) { + return STARTING_WINDOW_TYPE_SNAPSHOT; + } else { + return STARTING_WINDOW_TYPE_NONE; + } + } + void scheduleAddStartingWindow() { // Note: we really want to do sendMessageAtFrontOfQueue() because we // want to process the message ASAP, before any other queued // messages. @@ -481,6 +488,20 @@ public class AppWindowContainerController mHandler.postAtFrontOfQueue(mAddStartingWindow); } + private boolean createSnapshot() { + final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot( + mContainer.mTask); + + if (snapshot == null) { + return false; + } + + mContainer.startingData = new SnapshotStartingData(mService, mContainer, + snapshot.getSnapshot()); + scheduleAddStartingWindow(); + return true; + } + public void removeStartingWindow() { synchronized (mWindowMap) { if (mHandler.hasCallbacks(mRemoveStartingWindow)) { @@ -593,7 +614,7 @@ public class AppWindowContainerController } return dc.screenshotApplications(mToken.asBinder(), width, height, false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565, - false /* wallpaperOnly */); + false /* wallpaperOnly */, false /* includeDecor */, true /* toAshmem */); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index f4fa2206a22a..10d1d8b7c1c4 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -205,7 +205,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // We now have a good window to show, remove dead placeholders removeDeadWindows(); - if (startingData != null) { + if (startingWindow != null) { if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting " + win.mToken + ": first real window is shown, no animation"); // If this initial window is animating, stop it -- we will do an animation to reveal @@ -671,7 +671,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } 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"); + if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData"); startingData = null; } else if (mChildren.size() == 1 && startingSurface != null) { // If this is the last window except for a starting transition window, diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index d86c4dab54fb..66267bdb018c 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -106,6 +106,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; import android.util.DisplayMetrics; +import android.util.MutableBoolean; import android.util.Slog; import android.view.Display; import android.view.DisplayInfo; @@ -2102,10 +2103,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1 * @param config of the output bitmap * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot + * @param includeDecor whether to include window decors, like the status or navigation bar + * background of the window + * @param toAshmem whether to convert the resulting bitmap to ashmem; this should be set to + * true if the Bitmap is sent over binder, and false otherwise */ Bitmap screenshotApplications(IBinder appToken, int width, int height, boolean includeFullDisplay, float frameScale, Bitmap.Config config, - boolean wallpaperOnly) { + boolean wallpaperOnly, boolean includeDecor, boolean toAshmem) { int dw = mDisplayInfo.logicalWidth; int dh = mDisplayInfo.logicalHeight; if (dw == 0 || dh == 0) { @@ -2137,7 +2142,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final int aboveAppLayer = (mService.mPolicy.windowTypeToLayerLw(TYPE_APPLICATION) + 1) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; - + final MutableBoolean mutableIncludeFullDisplay = new MutableBoolean(includeFullDisplay); synchronized(mService.mWindowMap) { // Figure out the part of the screen that is actually the app. mScreenshotApplicationState.appWin = null; @@ -2194,7 +2199,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } // Don't include wallpaper in bounds calculation - if (!includeFullDisplay && !w.mIsWallpaper) { + if (includeDecor && !stackBounds.isEmpty()) { + frame.set(stackBounds); + } else if (includeDecor) { + mutableIncludeFullDisplay.value = true; + } else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) { final Rect wf = w.mFrame; final Rect cr = w.mContentInsets; int left = wf.left + cr.left; @@ -2252,7 +2261,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return null; } - if (!includeFullDisplay) { + if (!mutableIncludeFullDisplay.value) { // Constrain frame to the screen size. if (!frame.intersect(0, 0, dw, dh)) { frame.setEmpty(); @@ -2353,9 +2362,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // Create a copy of the screenshot that is immutable and backed in ashmem. // This greatly reduces the overhead of passing the bitmap between processes. - Bitmap ret = bm.createAshmemBitmap(config); - bm.recycle(); - return ret; + if (toAshmem) { + Bitmap ret = bm.createAshmemBitmap(config); + bm.recycle(); + return ret; + } else { + return bm; + } } // TODO: Can this use createRotationMatrix()? diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java new file mode 100644 index 000000000000..9d97a0c3f45e --- /dev/null +++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java @@ -0,0 +1,42 @@ +/* + * 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.wm; + +import android.graphics.GraphicBuffer; +import android.view.WindowManagerPolicy.StartingSurface; + +/** + * Represents starting data for snapshot starting windows. + */ +class SnapshotStartingData extends StartingData { + + private final WindowManagerService mService; + private final GraphicBuffer mSnapshot; + + SnapshotStartingData(WindowManagerService service, AppWindowToken appWindowToken, + GraphicBuffer snapshot) { + super(service, appWindowToken); + mService = service; + mSnapshot = snapshot; + } + + @Override + StartingSurface createStartingSurface() { + return mService.mTaskSnapshotController.createStartingSurface( + mAppWindowToken, mSnapshot); + } +} diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java new file mode 100644 index 000000000000..664e600faaf9 --- /dev/null +++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java @@ -0,0 +1,60 @@ +/* + * 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.wm; + +import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; +import android.view.WindowManagerPolicy.StartingSurface; + +/** + * Represents starting data for splash screens, i.e. "traditional" starting windows. + */ +class SplashScreenStartingData extends StartingData { + + private final String mPkg; + private final int mTheme; + private final CompatibilityInfo mCompatInfo; + private final CharSequence mNonLocalizedLabel; + private final int mLabelRes; + private final int mIcon; + private final int mLogo; + private final int mWindowFlags; + private final Configuration mMergedOverrideConfiguration; + + SplashScreenStartingData(WindowManagerService service, AppWindowToken appWindowToken, + String pkg, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, + int labelRes, int icon, int logo, int windowFlags, + Configuration mergedOverrideConfiguration) { + super(service, appWindowToken); + mPkg = pkg; + mTheme = theme; + mCompatInfo = compatInfo; + mNonLocalizedLabel = nonLocalizedLabel; + mLabelRes = labelRes; + mIcon = icon; + mLogo = logo; + mWindowFlags = windowFlags; + mMergedOverrideConfiguration = mergedOverrideConfiguration; + } + + @Override + StartingSurface createStartingSurface() { + return mService.mPolicy.addSplashScreen(mAppWindowToken.token, mPkg, mTheme, mCompatInfo, + mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags, + mMergedOverrideConfiguration); + } +} diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java index 7115b0fd02e5..fcc4c3c8302d 100644 --- a/services/core/java/com/android/server/wm/StartingData.java +++ b/services/core/java/com/android/server/wm/StartingData.java @@ -16,28 +16,27 @@ package com.android.server.wm; -import android.content.res.CompatibilityInfo; +import android.view.WindowManagerPolicy.StartingSurface; -final class StartingData { - final String pkg; - final int theme; - final CompatibilityInfo compatInfo; - final CharSequence nonLocalizedLabel; - final int labelRes; - final int icon; - final int logo; - final int windowFlags; +/** + * Represents the model about how a starting window should be constructed. + */ +public abstract class StartingData { + + protected final WindowManagerService mService; + protected final AppWindowToken mAppWindowToken; - StartingData(String _pkg, int _theme, CompatibilityInfo _compatInfo, - CharSequence _nonLocalizedLabel, - int _labelRes, int _icon, int _logo, int _windowFlags) { - pkg = _pkg; - theme = _theme; - compatInfo = _compatInfo; - nonLocalizedLabel = _nonLocalizedLabel; - labelRes = _labelRes; - icon = _icon; - logo = _logo; - windowFlags = _windowFlags; + protected StartingData(WindowManagerService service, AppWindowToken appWindowToken) { + mService = service; + mAppWindowToken = appWindowToken; } + + /** + * Creates the actual starting window surface. DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING + * THIS METHOD. + * + * @return a class implementing {@link StartingSurface} for easy removal with + * {@link StartingSurface#remove} + */ + abstract StartingSurface createStartingSurface(); }
\ No newline at end of file diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java new file mode 100644 index 000000000000..994a1552e7d8 --- /dev/null +++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java @@ -0,0 +1,39 @@ +/* + * 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.wm; + +import android.annotation.Nullable; +import android.app.ActivityManager.TaskSnapshot; +import android.util.ArrayMap; + +/** + * Caches snapshots. See {@link TaskSnapshotController}. + * <p> + * Access to this class should be guarded by the global window manager lock. + */ +class TaskSnapshotCache { + + private final ArrayMap<Task, TaskSnapshot> mCache = new ArrayMap<>(); + + void putSnapshot(Task task, TaskSnapshot snapshot) { + mCache.put(task, snapshot); + } + + @Nullable TaskSnapshot getSnapshot(Task task) { + return mCache.get(task); + } +} diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java new file mode 100644 index 000000000000..4421d618737a --- /dev/null +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -0,0 +1,134 @@ +/* + * 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.wm; + +import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS; +import static android.graphics.Bitmap.Config.ARGB_8888; +import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE; +import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER; +import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER; +import static android.graphics.PixelFormat.RGBA_8888; + +import android.annotation.Nullable; +import android.app.ActivityManager.StackId; +import android.app.ActivityManager.TaskSnapshot; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.GraphicBuffer; +import android.util.ArraySet; +import android.view.WindowManagerPolicy.StartingSurface; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * When an app token becomes invisible, we take a snapshot (bitmap) of the corresponding task and + * put it into our cache. Internally we use gralloc buffers to be able to draw them wherever we + * like without any copying. + * <p> + * System applications may retrieve a snapshot to represent the current state of a task, and draw + * them in their own process. + * <p> + * When we task becomes visible again, we show a starting window with the snapshot as the content to + * make app transitions more responsive. + * <p> + * To access this class, acquire the global window manager lock. + */ +class TaskSnapshotController { + + private final WindowManagerService mService; + private final TaskSnapshotCache mCache = new TaskSnapshotCache(); + + private final ArraySet<Task> mTmpTasks = new ArraySet<>(); + + TaskSnapshotController(WindowManagerService service) { + mService = service; + } + + void onTransitionStarting() { + if (!ENABLE_TASK_SNAPSHOTS) { + return; + } + + // We need to take a snapshot of the task if and only if all activities of the task are + // either closing or hidden. + getClosingTasks(mService.mClosingApps, mTmpTasks); + for (int i = mTmpTasks.size() - 1; i >= 0; i--) { + final Task task = mTmpTasks.valueAt(i); + if (!canSnapshotTask(task)) { + continue; + } + final TaskSnapshot snapshot = snapshotTask(task); + if (snapshot != null) { + mCache.putSnapshot(task, snapshot); + } + } + } + + @Nullable TaskSnapshot getSnapshot(Task task) { + return mCache.getSnapshot(task); + } + + /** + * Creates a starting surface for {@param token} with {@param snapshot}. DO NOT HOLD THE WINDOW + * MANAGER LOCK WHEN CALLING THIS METHOD! + */ + StartingSurface createStartingSurface(AppWindowToken token, + GraphicBuffer snapshot) { + return TaskSnapshotSurface.create(mService, token, snapshot); + } + + private TaskSnapshot snapshotTask(Task task) { + final AppWindowToken top = (AppWindowToken) task.getTop(); + if (top == null) { + return null; + } + final Bitmap bmp = top.mDisplayContent.screenshotApplications(top.token, -1, -1, false, + 1.0f, ARGB_8888, false, true, false); + if (bmp == null) { + return null; + } + // TODO: Already use a GraphicBuffer when snapshotting the content. + final GraphicBuffer buffer = GraphicBuffer.create(bmp.getWidth(), bmp.getHeight(), + RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_WRITE_NEVER | USAGE_SW_READ_NEVER); + final Canvas c = buffer.lockCanvas(); + c.drawBitmap(bmp, 0, 0, null); + buffer.unlockCanvasAndPost(c); + return new TaskSnapshot(buffer, top.getConfiguration().orientation, + top.findMainWindow().mStableInsets); + } + + /** + * Retrieves all closing tasks based on the list of closing apps during an app transition. + */ + @VisibleForTesting + void getClosingTasks(ArraySet<AppWindowToken> closingApps, ArraySet<Task> outClosingTasks) { + outClosingTasks.clear(); + for (int i = closingApps.size() - 1; i >= 0; i--) { + final AppWindowToken atoken = closingApps.valueAt(i); + + // If the task of the app is not visible anymore, it means no other app in that task + // is opening. Thus, the task is closing. + if (atoken.mTask != null && !atoken.mTask.isVisible()) { + outClosingTasks.add(closingApps.valueAt(i).mTask); + } + } + } + + private boolean canSnapshotTask(Task task) { + return !StackId.isHomeOrRecentsStack(task.mStack.mStackId); + } +} diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java new file mode 100644 index 000000000000..c3e314149c66 --- /dev/null +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -0,0 +1,202 @@ +/* + * 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.wm; + +import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.GraphicBuffer; +import android.graphics.Rect; +import android.os.Handler; +import android.os.Message; +import android.os.RemoteException; +import android.util.Slog; +import android.view.Display; +import android.view.IWindowSession; +import android.view.Surface; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; +import android.view.WindowManagerPolicy.StartingSurface; + +import com.android.internal.view.BaseIWindow; + +/** + * This class represents a starting window that shows a snapshot. + * <p> + * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING METHODS OF THIS CLASS! + */ +class TaskSnapshotSurface implements StartingSurface { + + private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM; + private static final int MSG_REPORT_DRAW = 0; + private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s"; + private final Window mWindow; + private final Surface mSurface; + private final IWindowSession mSession; + private final WindowManagerService mService; + private boolean mHasDrawn; + private boolean mReportNextDraw; + + static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token, + GraphicBuffer snapshot) { + + final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); + final Window window = new Window(); + final IWindowSession session = WindowManagerGlobal.getWindowSession(); + window.setSession(session); + final Surface surface = new Surface(); + final Rect tmpRect = new Rect(); + final Rect tmpFrame = new Rect(); + final Configuration tmpConfiguration = new Configuration(); + synchronized (service.mWindowMap) { + layoutParams.type = TYPE_APPLICATION_STARTING; + layoutParams.format = snapshot.getFormat(); + layoutParams.flags = FLAG_LAYOUT_INSET_DECOR + | FLAG_LAYOUT_IN_SCREEN + | FLAG_NOT_FOCUSABLE + | FLAG_NOT_TOUCHABLE + | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; + layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT; + layoutParams.token = token.token; + layoutParams.width = LayoutParams.MATCH_PARENT; + layoutParams.height = LayoutParams.MATCH_PARENT; + + // TODO: Inherit behavior whether to draw behind status bar/nav bar. + layoutParams.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; + layoutParams.setTitle(String.format(TITLE_FORMAT, token.mTask.mTaskId)); + } + try { + final int res = session.addToDisplay(window, window.mSeq, layoutParams, + View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect, + tmpRect, null); + if (res < 0) { + Slog.w(TAG, "Failed to add snapshot starting window res=" + res); + return null; + } + } catch (RemoteException e) { + // Local call. + } + final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window, + surface); + window.setOuter(snapshotSurface); + try { + session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame, + tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpConfiguration, + surface); + } catch (RemoteException e) { + // Local call. + } + snapshotSurface.drawSnapshot(snapshot); + return snapshotSurface; + } + + private TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface) { + mService = service; + mSession = WindowManagerGlobal.getWindowSession(); + mWindow = window; + mSurface = surface; + } + + @Override + public void remove() { + try { + mSession.remove(mWindow); + } catch (RemoteException e) { + // Local call. + } + } + + private void drawSnapshot(GraphicBuffer snapshot) { + + // TODO: Just wrap the buffer here without any copying. + final Canvas c = mSurface.lockHardwareCanvas(); + c.drawBitmap(Bitmap.createHardwareBitmap(snapshot), 0, 0, null); + mSurface.unlockCanvasAndPost(c); + final boolean reportNextDraw; + synchronized (mService.mWindowMap) { + mHasDrawn = true; + reportNextDraw = mReportNextDraw; + } + if (reportNextDraw) { + reportDrawn(); + } + } + + private void reportDrawn() { + synchronized (mService.mWindowMap) { + mReportNextDraw = false; + } + try { + mSession.finishDrawing(mWindow); + } catch (RemoteException e) { + // Local call. + } + } + + private static Handler sHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_REPORT_DRAW: + final boolean hasDrawn; + final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj; + synchronized (surface.mService.mWindowMap) { + hasDrawn = surface.mHasDrawn; + if (!hasDrawn) { + surface.mReportNextDraw = true; + } + } + if (hasDrawn) { + surface.reportDrawn(); + } + break; + } + } + }; + + private static class Window extends BaseIWindow { + + private TaskSnapshotSurface mOuter; + + public void setOuter(TaskSnapshotSurface outer) { + mOuter = outer; + } + + @Override + public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, + Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig, + Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar) { + if (reportDraw) { + sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget(); + } + } + } +} diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java index 9c303f811590..0e4d048ee15e 100644 --- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java +++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java @@ -16,7 +16,9 @@ package com.android.server.wm; +import android.app.ActivityManager.TaskSnapshot; import android.content.res.Configuration; +import android.graphics.GraphicBuffer; import android.graphics.Rect; import android.util.EventLog; import android.util.Slog; @@ -238,6 +240,19 @@ public class TaskWindowContainerController } } + /** + * @return a graphic buffer representing a screenshot of a task + */ + public TaskSnapshot getSnapshot() { + synchronized (mWindowMap) { + if (mContainer == null) { + Slog.w(TAG_WM, "getSnapshot: taskId " + mTaskId + " not found."); + return null; + } + return mService.mTaskSnapshotController.getSnapshot(mContainer); + } + } + @Override public String toString() { return "{TaskWindowContainerController taskId=" + mTaskId + "}"; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 048affb74728..195d4c31f566 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -16,6 +16,80 @@ package com.android.server.wm; +import static android.Manifest.permission.MANAGE_APP_TOKENS; +import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.StatusBarManager.DISABLE_MASK; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.DOCKED_INVALID; +import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; +import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; +import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; +import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; +import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT; +import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; +import static android.view.WindowManager.LayoutParams.TYPE_DRAG; +import static android.view.WindowManager.LayoutParams.TYPE_DREAM; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; +import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_TOAST; +import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY; +import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; +import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; +import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; +import static com.android.server.wm.AppTransition.TRANSIT_UNSET; +import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END; +import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; +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_BOOT; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; +import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; +import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS; +import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; +import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + import android.Manifest; import android.Manifest.permission; import android.animation.ValueAnimator; @@ -39,8 +113,8 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.database.ContentObserver; import android.graphics.Bitmap; -import android.graphics.PixelFormat; import android.graphics.Matrix; +import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; @@ -88,7 +162,6 @@ import android.view.Choreographer; import android.view.Display; import android.view.DisplayInfo; import android.view.Gravity; -import android.view.PointerIcon; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IDockedStackListener; import android.view.IInputFilter; @@ -107,6 +180,7 @@ import android.view.InputEventReceiver; import android.view.KeyEvent; import android.view.MagnificationSpec; import android.view.MotionEvent; +import android.view.PointerIcon; import android.view.Surface; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; @@ -161,83 +235,6 @@ import java.util.Date; import java.util.HashMap; import java.util.List; -import static android.Manifest.permission.MANAGE_APP_TOKENS; -import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; -import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.app.StatusBarManager.DISABLE_MASK; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManager.DOCKED_INVALID; -import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; -import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; -import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; -import static android.view.WindowManager.LayoutParams.FLAG_SECURE; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; -import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; -import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; -import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; -import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; -import static android.view.WindowManager.LayoutParams.TYPE_DRAG; -import static android.view.WindowManager.LayoutParams.TYPE_DREAM; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; -import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; -import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; -import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; -import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; -import static android.view.WindowManager.LayoutParams.TYPE_TOAST; -import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; -import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY; -import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; -import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; -import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.EventLogTags.WM_TASK_CREATED; -import static com.android.server.wm.AppTransition.TRANSIT_UNSET; -import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END; -import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START; -import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; -import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; -import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; -import static com.android.server.wm.WindowContainer.POSITION_TOP; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; -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_BOOT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { @@ -580,6 +577,7 @@ public class WindowManagerService extends IWindowManager.Stub final UnknownAppVisibilityController mUnknownAppVisibilityController = new UnknownAppVisibilityController(this); + final TaskSnapshotController mTaskSnapshotController = new TaskSnapshotController(this); boolean mIsTouchDevice; @@ -1215,7 +1213,9 @@ public class WindowManagerService extends IWindowManager.Stub + token + ". Aborting."); return WindowManagerGlobal.ADD_APP_EXITING; } - if (rootType == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) { + if (rootType == TYPE_APPLICATION_STARTING + && (attrs.privateFlags & PRIVATE_FLAG_TASK_SNAPSHOT) == 0 + && atoken.firstWindowDrawn) { // No need for this guy! if (DEBUG_STARTING_WINDOW || localLOGV) Slog.v( TAG_WM, "**** NO NEED TO START: " + attrs.getTitle()); @@ -1966,7 +1966,8 @@ public class WindowManagerService extends IWindowManager.Stub + " newVis=" + viewVisibility, stack); } if (viewVisibility == View.VISIBLE && - (win.mAppToken == null || !win.mAppToken.clientHidden)) { + (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING + || !win.mAppToken.clientHidden)) { result = relayoutVisibleWindow(outConfig, result, win, winAnimator, attrChanges, oldVisibility); try { @@ -2073,7 +2074,10 @@ public class WindowManagerService extends IWindowManager.Stub win.setDisplayLayoutNeeded(); win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; configChanged = updateOrientationFromAppTokensLocked(false, displayId); - mWindowPlacerLocked.performSurfacePlacement(); + + // We may be deferring layout passes at the moment, but since the client is interested + // in the new out values right now we need to force a layout. + mWindowPlacerLocked.performSurfacePlacement(true /* force */); if (toBeDisplayed && win.mIsWallpaper) { DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo(); dc.mWallpaperController.updateWallpaperOffset( @@ -3858,7 +3862,8 @@ public class WindowManagerService extends IWindowManager.Stub Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper"); return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */, -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */, - Bitmap.Config.ARGB_8888, true /* wallpaperOnly */); + Bitmap.Config.ARGB_8888, true /* wallpaperOnly */, false /* includeDecor */, + true /* toAshmem */); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } @@ -3879,7 +3884,8 @@ public class WindowManagerService extends IWindowManager.Stub FgThread.getHandler().post(() -> { Bitmap bm = screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */, -1 /* height */, true /* includeFullDisplay */, - 1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */); + 1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */, + false /* includeDecor */, true /* toAshmem */); try { receiver.send(bm); } catch (RemoteException e) { @@ -3900,10 +3906,14 @@ public class WindowManagerService extends IWindowManager.Stub * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1 * @param config of the output bitmap * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot + * @param includeDecor whether to include window decors, like the status or navigation bar + * background of the window + * @param toAshmem whether to convert the resulting bitmap to ashmem; this should be set to + * true if the Bitmap is sent over binder, and false otherwise */ private Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height, boolean includeFullDisplay, float frameScale, Bitmap.Config config, - boolean wallpaperOnly) { + boolean wallpaperOnly, boolean includeDecor, boolean toAshmem) { final DisplayContent displayContent; synchronized(mWindowMap) { displayContent = mRoot.getDisplayContentOrCreate(displayId); @@ -3914,7 +3924,7 @@ public class WindowManagerService extends IWindowManager.Stub } } return displayContent.screenshotApplications(appToken, width, height, - includeFullDisplay, frameScale, config, wallpaperOnly); + includeFullDisplay, frameScale, config, wallpaperOnly, includeDecor, toAshmem); } /** diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 3daad4373d06..608f056dc13c 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -16,55 +16,11 @@ package com.android.server.wm; -import android.app.ActivityManager; -import android.app.AppOpsManager; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Matrix; -import android.graphics.PixelFormat; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.Region; -import android.os.Binder; -import android.os.Debug; -import android.os.IBinder; -import android.os.PowerManager; -import android.os.RemoteCallbackList; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.Trace; -import android.os.UserHandle; -import android.os.WorkSource; -import android.util.DisplayMetrics; -import android.util.Slog; -import android.util.TimeUtils; -import android.view.DisplayInfo; -import android.view.Gravity; -import android.view.IApplicationToken; -import android.view.IWindow; -import android.view.IWindowFocusObserver; -import android.view.IWindowId; -import android.view.InputChannel; -import android.view.InputEvent; -import android.view.InputEventReceiver; -import android.view.View; -import android.view.ViewTreeObserver; -import android.view.WindowInfo; -import android.view.WindowManager; -import android.view.WindowManagerPolicy; - -import com.android.internal.util.ToBooleanFunction; -import com.android.server.input.InputWindowHandle; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.function.Predicate; - +import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS; import static android.app.ActivityManager.StackId; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.isLowRamDeviceStatic; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; @@ -96,8 +52,8 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; +import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; @@ -138,6 +94,51 @@ import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING; import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Matrix; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.Region; +import android.os.Binder; +import android.os.Debug; +import android.os.IBinder; +import android.os.PowerManager; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.Trace; +import android.os.UserHandle; +import android.os.WorkSource; +import android.util.DisplayMetrics; +import android.util.Slog; +import android.util.TimeUtils; +import android.view.DisplayInfo; +import android.view.Gravity; +import android.view.IApplicationToken; +import android.view.IWindow; +import android.view.IWindowFocusObserver; +import android.view.IWindowId; +import android.view.InputChannel; +import android.view.InputEvent; +import android.view.InputEventReceiver; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowInfo; +import android.view.WindowManager; +import android.view.WindowManagerPolicy; + +import com.android.internal.util.ToBooleanFunction; +import com.android.server.input.InputWindowHandle; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.function.Predicate; + /** A window in the window manager. */ class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState { static final String TAG = TAG_WITH_CLASS_NAME ? "WindowState" : TAG_WM; @@ -152,7 +153,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // to capture touch events in that area. static final int RESIZE_HANDLE_WIDTH_IN_DP = 30; - private static final boolean DEBUG_DISABLE_SAVING_SURFACES = false; + private static final boolean DEBUG_DISABLE_SAVING_SURFACES = false || + ENABLE_TASK_SNAPSHOTS; final WindowManagerService mService; final WindowManagerPolicy mPolicy; @@ -2652,7 +2654,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return false; } - if (ActivityManager.isLowRamDeviceStatic()) { + if (isLowRamDeviceStatic()) { // Don't save surfaces on Svelte devices. return false; } @@ -3713,6 +3715,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP logPerformShow("performShow on "); + final int drawState = mWinAnimator.mDrawState; + if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) + && mAttrs.type != TYPE_APPLICATION_STARTING && mAppToken != null) { + mAppToken.onFirstWindowDrawn(this, mWinAnimator); + } + if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) { return false; } @@ -3747,10 +3755,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - if (mAttrs.type != TYPE_APPLICATION_STARTING && mAppToken != null) { - mAppToken.onFirstWindowDrawn(this, mWinAnimator); - } - if (mAttrs.type == TYPE_INPUT_METHOD) { getDisplayContent().mDividerControllerLocked.resetImeHideRequested(); } diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 4df100105bcb..897d5b86d3d9 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -117,7 +117,11 @@ class WindowSurfacePlacer { } final void performSurfacePlacement() { - if (mDeferDepth > 0) { + performSurfacePlacement(false /* force */); + } + + final void performSurfacePlacement(boolean force) { + if (mDeferDepth > 0 && !force) { return; } int loopCount = 6; @@ -343,6 +347,8 @@ class WindowSurfacePlacer { mService.mAppTransition.postAnimationCallback(); mService.mAppTransition.clear(); + mService.mTaskSnapshotController.onTransitionStarting(); + mService.mOpeningApps.clear(); mService.mClosingApps.clear(); mService.mUnknownAppVisibilityController.clear(); @@ -513,17 +519,14 @@ class WindowSurfacePlacer { + wtoken.startingMoved + " isRelaunching()=" + wtoken.isRelaunching()); - if (wtoken.isRelaunching()) { - return false; - } - final boolean drawnBeforeRestoring = wtoken.allDrawn; wtoken.restoreSavedSurfaceForInterestingWindows(); - if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) { + final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching(); + if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) { return false; } - if (wtoken.allDrawn) { + if (allDrawn) { reason = drawnBeforeRestoring ? APP_TRANSITION_WINDOWS_DRAWN : APP_TRANSITION_SAVED_SURFACE; } else { diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java new file mode 100644 index 000000000000..5dff9973f734 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java @@ -0,0 +1,71 @@ +/* + * 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.wm; + +import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; +import static com.android.server.wm.AppTransition.TRANSIT_UNSET; +import static junit.framework.Assert.assertEquals; + +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.util.ArraySet; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test class for {@link TaskSnapshotController}. + * + * runtest frameworks-services -c com.android.server.wm.TaskSnapshotControllerTest + */ +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class TaskSnapshotControllerTest extends WindowTestsBase { + + @Test + public void testGetClosingApps_closing() throws Exception { + final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, + "closingWindow"); + closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, + true /* performLayout */, false /* isVoiceInteraction */); + final ArraySet<AppWindowToken> closingApps = new ArraySet<>(); + closingApps.add(closingWindow.mAppToken); + final ArraySet<Task> closingTasks = new ArraySet<>(); + sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks); + assertEquals(1, closingTasks.size()); + assertEquals(closingWindow.mAppToken.mTask, closingTasks.valueAt(0)); + } + + @Test + public void testGetClosingApps_notClosing() throws Exception { + final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, + "closingWindow"); + final WindowState openingWindow = createAppWindow(closingWindow.getTask(), + FIRST_APPLICATION_WINDOW, "openingWindow"); + closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, + true /* performLayout */, false /* isVoiceInteraction */); + openingWindow.mAppToken.setVisibility(null, true /* visible */, TRANSIT_UNSET, + true /* performLayout */, false /* isVoiceInteraction */); + final ArraySet<AppWindowToken> closingApps = new ArraySet<>(); + closingApps.add(closingWindow.mAppToken); + final ArraySet<Task> closingTasks = new ArraySet<>(); + sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks); + assertEquals(0, closingTasks.size()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index c4fd7221d3f4..12e7a15d2cbb 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -313,11 +313,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public void removeSplashScreen(IBinder appToken, StartingSurface surface) { - - } - - @Override public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { return 0; diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java index be080f56fb10..466bd6700f16 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java @@ -119,6 +119,12 @@ class WindowTestsBase { : createWindow(parent, type, parent.mToken, name); } + WindowState createAppWindow(Task task, int type, String name) { + final AppWindowToken token = new TestAppWindowToken(sDisplayContent); + task.addChild(token, 0); + return createWindow(null, type, token, name); + } + WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) { final WindowToken token = createWindowToken(dc, type); return createWindow(parent, type, token, name); diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 5e5ebd7e6488..5ed5460f8c4f 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -16,18 +16,10 @@ package android.view; -import android.graphics.Point; -import android.graphics.Rect; -import com.android.internal.app.IAssistScreenshotReceiver; -import com.android.internal.os.IResultReceiver; -import com.android.internal.policy.IKeyguardDismissCallback; -import com.android.internal.policy.IShortcutService; -import com.android.internal.view.IInputContext; -import com.android.internal.view.IInputMethodClient; - -import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.Point; +import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.os.IRemoteCallback; @@ -35,7 +27,12 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.DisplayMetrics; -import java.lang.Override; +import com.android.internal.app.IAssistScreenshotReceiver; +import com.android.internal.os.IResultReceiver; +import com.android.internal.policy.IKeyguardDismissCallback; +import com.android.internal.policy.IShortcutService; +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethodClient; /** * Basic implementation of {@link IWindowManager} so that {@link Display} (and |