Merge changes I2ff9bd44,I946e681e,If72df07b
* changes:
Handle content insets for snapshots
Always remove starting window in performShow
Initial implementation of snapshots
diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl
index 5672f6b..29260e9 100644
--- a/core/java/android/app/ActivityManager.aidl
+++ b/core/java/android/app/ActivityManager.aidl
@@ -26,4 +26,6 @@
/** @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 9037304..3170d0d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -26,6 +26,7 @@
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 @@
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 @@
};
}
+ /**
+ * 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 2ed9eab..21ae853 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -53,6 +53,7 @@
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 @@
/** 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 c0ebd2c..19edb5c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -48,6 +48,7 @@
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 556dc72..1363f05 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 aa7631d..e5a6ebd 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -22,6 +22,7 @@
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 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 dd85256..3748134 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -439,10 +439,15 @@
/**
* 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 @@
* @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 7791132..3587b89 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.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.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 @@
}
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 @@
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 ba31e3e..6ea51e5 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 @@
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
- t.notifyTaskDataLoaded(newThumbnailData.thumbnail, newIcon,
- newThumbnailData.thumbnailInfo);
+ t.notifyTaskDataLoaded(newThumbnailData, newIcon);
}
});
}
@@ -364,11 +363,9 @@
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 @@
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 53f713a..2f2e866 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 @@
/* 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 @@
}
/** 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 d0cdae5..18735ac 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 36d5f83..5f37349 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.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 @@
}
@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 58b929a..3ae51b0 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 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 @@
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 @@
mTaskViewRect.set(0, 0, width, height);
setLeftTopRightBottom(0, 0, width, height);
- updateThumbnailScale();
+ updateThumbnailMatrix();
}
@Override
@@ -174,19 +173,22 @@
}
/** 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 @@
/**
* 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 @@
(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 @@
* 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 6300400..a86abf6 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 @@
// 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 48a7e7c..74304f0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,258 +16,11 @@
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 android.Manifest;
-import android.Manifest.permission;
-import android.annotation.NonNull;
-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.TaskThumbnailInfo;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerInternal.SleepToken;
-import android.app.ActivityOptions;
-import android.app.ActivityThread;
-import android.app.AlertDialog;
-import android.app.AppGlobals;
-import android.app.AppOpsManager;
-import android.app.ApplicationErrorReport;
-import android.app.BroadcastOptions;
-import android.app.Dialog;
-import android.app.IActivityContainer;
-import android.app.IActivityContainerCallback;
-import android.app.IActivityController;
-import android.app.IAppTask;
-import android.app.IApplicationThread;
-import android.app.IInstrumentationWatcher;
-import android.app.INotificationManager;
-import android.app.IProcessObserver;
-import android.app.IServiceConnection;
-import android.app.IStopUserCallback;
-import android.app.ITaskStackListener;
-import android.app.IUiAutomationConnection;
-import android.app.IUidObserver;
-import android.app.IUserSwitchObserver;
-import android.app.Instrumentation;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.ProfilerInfo;
-import android.app.admin.DevicePolicyManager;
-import android.app.assist.AssistContent;
-import android.app.assist.AssistStructure;
-import android.app.backup.IBackupManager;
-import android.app.usage.UsageEvents;
-import android.app.usage.UsageStatsManagerInternal;
-import android.appwidget.AppWidgetManager;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ClipData;
-import android.content.ComponentCallbacks2;
-import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.IContentProvider;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ConfigurationInfo;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageManager;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.PathPermission;
-import android.content.pm.PermissionInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.content.res.CompatibilityInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.location.LocationManager;
-import android.net.Proxy;
-import android.net.ProxyInfo;
-import android.net.Uri;
-import android.os.BatteryStats;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.DropBoxManager;
-import android.os.Environment;
-import android.os.FactoryTest;
-import android.os.FileObserver;
-import android.os.FileUtils;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IPermissionController;
-import android.os.IProcessInfoService;
-import android.os.IProgressListener;
-import android.os.LocaleList;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.PersistableBundle;
-import android.os.PowerManager;
-import android.os.PowerManagerInternal;
-import android.os.Process;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ServiceManager;
-import android.os.ShellCallback;
-import android.os.StrictMode;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.Trace;
-import android.os.TransactionTooLargeException;
-import android.os.UpdateLock;
-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.provider.Downloads;
-import android.provider.Settings;
-import android.service.autofill.AutoFillService;
-import android.service.voice.IVoiceInteractionSession;
-import android.service.voice.VoiceInteractionManagerInternal;
-import android.service.voice.VoiceInteractionSession;
-import android.telecom.TelecomManager;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.text.style.SuggestionSpan;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.BootTimingsTraceLog;
-import android.util.DebugUtils;
-import android.util.DisplayMetrics;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.Pair;
-import android.util.PrintWriterPrinter;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.util.TimeUtils;
-import android.util.Xml;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.ref.WeakReference;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-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.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;
@@ -301,7 +54,6 @@
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;
@@ -367,7 +119,6 @@
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;
@@ -387,6 +138,256 @@
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;
+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;
+import android.app.INotificationManager;
+import android.app.IProcessObserver;
+import android.app.IServiceConnection;
+import android.app.IStopUserCallback;
+import android.app.ITaskStackListener;
+import android.app.IUiAutomationConnection;
+import android.app.IUidObserver;
+import android.app.IUserSwitchObserver;
+import android.app.Instrumentation;
+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;
+import android.app.backup.IBackupManager;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.appwidget.AppWidgetManager;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ClipData;
+import android.content.ComponentCallbacks2;
+import android.content.ComponentName;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.IContentProvider;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageManager;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PathPermission;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.content.res.CompatibilityInfo;
+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;
+import android.net.Proxy;
+import android.net.ProxyInfo;
+import android.net.Uri;
+import android.os.BatteryStats;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.DropBoxManager;
+import android.os.Environment;
+import android.os.FactoryTest;
+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;
+import android.os.LocaleList;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal;
+import android.os.Process;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.StrictMode;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.os.TransactionTooLargeException;
+import android.os.UpdateLock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.WorkSource;
+import android.os.storage.IStorageManager;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
+import android.provider.Downloads;
+import android.provider.Settings;
+import android.service.autofill.AutoFillService;
+import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.VoiceInteractionManagerInternal;
+import android.service.voice.VoiceInteractionSession;
+import android.telecom.TelecomManager;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.text.style.SuggestionSpan;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.BootTimingsTraceLog;
+import android.util.DebugUtils;
+import android.util.DisplayMetrics;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Pair;
+import android.util.PrintWriterPrinter;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.TimeUtils;
+import android.util.Xml;
+import android.view.Gravity;
+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;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.ref.WeakReference;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+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 dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
@@ -9654,6 +9655,25 @@
}
@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 @@
}
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 2963ad1..47c3e6f 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_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.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.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 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 @@
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 @@
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 ab65eb1..abcaa24 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 @@
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 @@
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 @@
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 @@
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 @@
}
}
+ 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 61e3ad5..f401863 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.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_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.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 @@
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 d0eac77..9e22c50 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.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.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 @@
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 0a312f0..4b2b184 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_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 @@
// 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 @@
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 @@
@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 @@
}
}
+ // 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 d421291..37d6c0b 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 @@
*/
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) {
- this.view = view;
+ 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));
+
+ 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 d2f604d..1eb74fa4 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_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 @@
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 @@
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 @@
}
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 @@
"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 @@
+ 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 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 @@
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 @@
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 @@
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 @@
}
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 f4fa220..10d1d8b 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 @@
// 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 @@
} 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 d86c4da..66267bd 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.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 @@
* @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 @@
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 @@
}
// 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 @@
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 @@
// 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 0000000..9d97a0c
--- /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 0000000..664e600
--- /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 7115b0f..fcc4c3c 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 {
- 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 final WindowManagerService mService;
+ protected final AppWindowToken mAppWindowToken;
+
+ 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 0000000..994a155
--- /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 0000000..4421d61
--- /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 0000000..c3e3141
--- /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 9c303f8..0e4d048 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 @@
}
}
+ /**
+ * @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 048affb..195d4c3 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.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.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.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.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 @@
final UnknownAppVisibilityController mUnknownAppVisibilityController =
new UnknownAppVisibilityController(this);
+ final TaskSnapshotController mTaskSnapshotController = new TaskSnapshotController(this);
boolean mIsTouchDevice;
@@ -1215,7 +1213,9 @@
+ 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 @@
+ " 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 @@
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 @@
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 @@
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 @@
* @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 @@
}
}
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 3daad43..608f056 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,7 +16,84 @@
package com.android.server.wm;
-import android.app.ActivityManager;
+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;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+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.FLAG_TURN_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+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_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;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static android.view.WindowManagerPolicy.TRANSIT_ENTER;
+import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
+import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+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_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_CONFIGURATION;
+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_INPUT_METHOD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+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_POWER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
+import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
+import static com.android.server.wm.WindowManagerService.localLOGV;
+import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
+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;
@@ -62,82 +139,6 @@
import java.util.LinkedList;
import java.util.function.Predicate;
-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.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
-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.FLAG_TURN_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-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_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static android.view.WindowManagerPolicy.TRANSIT_ENTER;
-import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
-import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
-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_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_CONFIGURATION;
-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_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
-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_POWER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
-import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
-import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
-import static com.android.server.wm.WindowManagerService.localLOGV;
-import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
-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;
-
/** 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 @@
// 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 @@
return false;
}
- if (ActivityManager.isLowRamDeviceStatic()) {
+ if (isLowRamDeviceStatic()) {
// Don't save surfaces on Svelte devices.
return false;
}
@@ -3713,6 +3715,12 @@
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 @@
}
}
- 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 4df1001..897d5b86 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 @@
}
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 @@
mService.mAppTransition.postAnimationCallback();
mService.mAppTransition.clear();
+ mService.mTaskSnapshotController.onTransitionStarting();
+
mService.mOpeningApps.clear();
mService.mClosingApps.clear();
mService.mUnknownAppVisibilityController.clear();
@@ -513,17 +519,14 @@
+ 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 0000000..5dff997
--- /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 c4fd722..12e7a15 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 @@
}
@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 be080f5..466bd67 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 @@
: 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 5e5ebd7..5ed5460 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.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