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;
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;
/** Cancels the thumbnail transitions for the given task. */
void cancelTaskThumbnailTransition(int taskId);
+ /**
+ * @return a graphic buffer representing a screenshot of a task
+ */
+ GraphicBuffer 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
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
*/
/**
* 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();
}
/**
* @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.
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.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import android.app.ActivityManager;
+import android.app.ActivityManager.TaskThumbnailInfo;
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;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.GraphicBuffer;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
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;
import com.android.systemui.R;
import com.android.systemui.pip.tv.PipMenuActivity;
import com.android.systemui.pip.tv.PipOnboardingActivity;
+import com.android.systemui.recents.Constants;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.RecentsImpl;
}
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
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) {
+ GraphicBuffer graphicBuffer = null;
try {
- descriptor.close();
- } catch (IOException e) {
+ graphicBuffer = ActivityManager.getService().getTaskSnapshot(taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to retrieve snapshot", e);
+ }
+ if (graphicBuffer != null) {
+ thumbnailDataOut.thumbnail = Bitmap.createHardwareBitmap(graphicBuffer);
+ } else {
+ thumbnailDataOut.thumbnail = null;
+ }
+
+ // TODO: Retrieve screen orientation.
+ thumbnailDataOut.thumbnailInfo = new TaskThumbnailInfo();
+ thumbnailDataOut.thumbnailInfo.screenOrientation = ORIENTATION_PORTRAIT;
+ } 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.thumbnailInfo = taskThumbnail.thumbnailInfo;
}
- thumbnailDataOut.thumbnail = thumbnail;
- thumbnailDataOut.thumbnailInfo = taskThumbnail.thumbnailInfo;
}
/**
// 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 (mTaskViewRect.isEmpty() || mThumbnailInfo == null) {
// If we haven't measured or the thumbnail is invalid, skip the thumbnail drawing
// and only draw the background color
mThumbnailScale = 0f;
package com.android.server.am;
-import android.annotation.Nullable;
-import android.app.ActivityManagerInternal.PictureInPictureArguments;
-import android.app.ApplicationThreadConstants;
-import android.app.ContentProviderHolder;
-import android.app.IActivityManager;
-import android.app.RemoteAction;
-import android.app.WaitResult;
-import android.os.IDeviceIdentifiersPolicyService;
-
-import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.internal.telephony.TelephonyIntents;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
-import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.AssistUtils;
-import com.android.internal.app.DumpHeapActivity;
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.app.ProcessMap;
-import com.android.internal.app.SystemUserHomeActivity;
-import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.BatteryStatsImpl;
-import com.android.internal.os.IResultReceiver;
-import com.android.internal.os.ProcessCpuTracker;
-import com.android.internal.os.TransferPipe;
-import com.android.internal.os.Zygote;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.MemInfoReader;
-import com.android.internal.util.Preconditions;
-import com.android.server.AppOpsService;
-import com.android.server.AttributeCache;
-import com.android.server.DeviceIdleController;
-import com.android.server.IntentResolver;
-import com.android.server.LocalServices;
-import com.android.server.LockGuard;
-import com.android.server.ServiceThread;
-import com.android.server.SystemService;
-import com.android.server.SystemServiceManager;
-import com.android.server.Watchdog;
-import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.firewall.IntentFirewall;
-import com.android.server.pm.Installer;
-import com.android.server.pm.Installer.InstallerException;
-import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.vr.VrManagerInternal;
-import com.android.server.wm.WindowManagerService;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
+import static android.Manifest.permission.CHANGE_CONFIGURATION;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+import static android.Manifest.permission.READ_FRAME_BUFFER;
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+import static android.content.pm.PackageManager.GET_PROVIDERS;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
+import static android.os.Build.VERSION_CODES.N;
+import static android.os.Process.PROC_CHAR;
+import static android.os.Process.PROC_OUT_LONG;
+import static android.os.Process.PROC_PARENS;
+import static android.os.Process.PROC_SPACE_TERM;
+import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
+import static android.provider.Settings.Global.DEBUG_APP;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
+import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
+import static android.provider.Settings.System.FONT_SCALE;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKSCREEN;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_POWER;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESSES;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
+import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
+import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
+import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+import static com.android.server.am.ActivityStackSupervisor.RESTORE_FROM_RECENTS;
+import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
+import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
+import static com.android.server.wm.AppTransition.TRANSIT_NONE;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
import android.Manifest.permission;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.StackInfo;
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.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.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.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.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.UserManager;
import android.os.WorkSource;
import android.os.storage.IStorageManager;
-import android.os.storage.StorageManagerInternal;
import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
import android.provider.Downloads;
import android.provider.Settings;
import android.service.autofill.AutoFillService;
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.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.CountDownLatch;
import dalvik.system.VMRuntime;
-
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
-import static android.Manifest.permission.CHANGE_CONFIGURATION;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
-import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
-import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-import static android.content.pm.PackageManager.GET_PROVIDERS;
-import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
-import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
-import static android.os.Build.VERSION_CODES.N;
-import static android.os.Process.PROC_CHAR;
-import static android.os.Process.PROC_OUT_LONG;
-import static android.os.Process.PROC_PARENS;
-import static android.os.Process.PROC_SPACE_TERM;
-import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
-import static android.provider.Settings.Global.DEBUG_APP;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
-import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
-import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
-import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
-import static android.provider.Settings.System.FONT_SCALE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.internal.util.XmlUtils.readBooleanAttribute;
-import static com.android.internal.util.XmlUtils.readIntAttribute;
-import static com.android.internal.util.XmlUtils.readLongAttribute;
-import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
-import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeLongAttribute;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKSCREEN;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_OOM_ADJ;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_POWER;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESSES;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
-import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
-import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
-import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
-import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
-import static com.android.server.am.ActivityStackSupervisor.RESTORE_FROM_RECENTS;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
-import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
-import static com.android.server.wm.AppTransition.TRANSIT_NONE;
-import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
-import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
-import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
-
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
}
@Override
+ public GraphicBuffer 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,
}
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);
}
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;
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;
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;
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.
*/
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;
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;
}
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));
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();
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);
}
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) {
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,
}
}
+ 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.
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;
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;
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;
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);
}
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;
mWindowContainerController.cancelThumbnailTransition();
}
+ public GraphicBuffer getSnapshot() {
+ if (mWindowContainerController == null) {
+ return null;
+ }
+ return mWindowContainerController.getSnapshot();
+ }
+
void touchActiveTime() {
lastActiveTime = System.currentTimeMillis();
if (firstActiveTime == 0) {
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;
// 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. " +
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.
*
@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);
}
}
+ // 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) {
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;
*/
class SplashScreenSurface implements StartingSurface {
- final View view;
+ private static final String TAG = PhoneWindowManager.TAG;
+ private final View mView;
+ private final IBinder mAppToken;
+
+ SplashScreenSurface(View view, IBinder appToken) {
+ mView = view;
+ mAppToken = appToken;
+ }
+
+ @Override
+ public void remove() {
+ if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + mAppToken + ": "
+ + this + " Callers=" + Debug.getCallers(4));
- SplashScreenSurface(View view) {
- this.view = view;
+ final WindowManager wm = mView.getContext().getSystemService(WindowManager.class);
+ wm.removeView(mView);
}
}
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
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());
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) {
}
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
"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
+ 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);
}
}
};
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);
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.
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.
mHandler.postAtFrontOfQueue(mAddStartingWindow);
}
+ private boolean createSnapshot() {
+ final GraphicBuffer snapshot = mService.mTaskSnapshotController.getSnapshot(
+ mContainer.mTask);
+
+ if (snapshot == null) {
+ return false;
+ }
+
+ mContainer.startingData = new SnapshotStartingData(mService, mContainer, snapshot);
+ scheduleAddStartingWindow();
+ return true;
+ }
+
public void removeStartingWindow() {
synchronized (mWindowMap) {
if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
}
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);
}
// 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
} 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,
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;
* @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) {
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;
}
// 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;
return null;
}
- if (!includeFullDisplay) {
+ if (!mutableIncludeFullDisplay.value) {
// Constrain frame to the screen size.
if (!frame.intersect(0, 0, dw, dh)) {
frame.setEmpty();
// 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()?
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
package com.android.server.wm;
-import android.content.res.CompatibilityInfo;
+import android.view.WindowManagerPolicy.StartingSurface;
-final class StartingData {
- final String pkg;
- final int theme;
- final CompatibilityInfo compatInfo;
- final CharSequence nonLocalizedLabel;
- final int labelRes;
- final int icon;
- final int logo;
- final int windowFlags;
+/**
+ * Represents the model about how a starting window should be constructed.
+ */
+public abstract class StartingData {
+
+ protected final WindowManagerService mService;
+ protected final AppWindowToken mAppWindowToken;
- StartingData(String _pkg, int _theme, CompatibilityInfo _compatInfo,
- CharSequence _nonLocalizedLabel,
- int _labelRes, int _icon, int _logo, int _windowFlags) {
- pkg = _pkg;
- theme = _theme;
- compatInfo = _compatInfo;
- nonLocalizedLabel = _nonLocalizedLabel;
- labelRes = _labelRes;
- icon = _icon;
- logo = _logo;
- windowFlags = _windowFlags;
+ protected StartingData(WindowManagerService service, AppWindowToken appWindowToken) {
+ mService = service;
+ mAppWindowToken = appWindowToken;
}
+
+ /**
+ * Creates the actual starting window surface. DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING
+ * THIS METHOD.
+ *
+ * @return a class implementing {@link StartingSurface} for easy removal with
+ * {@link StartingSurface#remove}
+ */
+ abstract StartingSurface createStartingSurface();
}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.graphics.GraphicBuffer;
+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, GraphicBuffer> mCache = new ArrayMap<>();
+
+ void putSnapshot(Task task, GraphicBuffer snapshot) {
+ mCache.put(task, snapshot);
+ }
+
+ @Nullable GraphicBuffer getSnapshot(Task task) {
+ return mCache.get(task);
+ }
+}
--- /dev/null
+/*
+ * 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.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 GraphicBuffer graphicBuffer = snapshotTask(task);
+ if (graphicBuffer != null) {
+ mCache.putSnapshot(task, graphicBuffer);
+ }
+ }
+ }
+
+ @Nullable GraphicBuffer 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 GraphicBuffer 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 buffer;
+ }
+
+ /**
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+ }
+}
package com.android.server.wm;
import android.content.res.Configuration;
+import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.util.EventLog;
import android.util.Slog;
}
}
+ /**
+ * @return a graphic buffer representing a screenshot of a task
+ */
+ public GraphicBuffer 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 + "}";
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Matrix;
import android.graphics.Point;
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;
final UnknownAppVisibilityController mUnknownAppVisibilityController =
new UnknownAppVisibilityController(this);
+ final TaskSnapshotController mTaskSnapshotController = new TaskSnapshotController(this);
boolean mIsTouchDevice;
+ 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());
+ " 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 {
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(
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);
}
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) {
* @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);
}
}
return displayContent.screenshotApplications(appToken, width, height,
- includeFullDisplay, frameScale, config, wallpaperOnly);
+ includeFullDisplay, frameScale, config, wallpaperOnly, includeDecor, toAshmem);
}
/**
package com.android.server.wm;
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Matrix;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.Binder;
-import android.os.Debug;
-import android.os.IBinder;
-import android.os.PowerManager;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.os.WorkSource;
-import android.util.DisplayMetrics;
-import android.util.Slog;
-import android.util.TimeUtils;
-import android.view.DisplayInfo;
-import android.view.Gravity;
-import android.view.IApplicationToken;
-import android.view.IWindow;
-import android.view.IWindowFocusObserver;
-import android.view.IWindowId;
-import android.view.InputChannel;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.view.WindowInfo;
-import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
-
-import com.android.internal.util.ToBooleanFunction;
-import com.android.server.input.InputWindowHandle;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.LinkedList;
-import java.util.function.Predicate;
-
+import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.isLowRamDeviceStatic;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Matrix;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.Binder;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.util.TimeUtils;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+import android.view.IApplicationToken;
+import android.view.IWindow;
+import android.view.IWindowFocusObserver;
+import android.view.IWindowId;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.WindowInfo;
+import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
+
+import com.android.internal.util.ToBooleanFunction;
+import com.android.server.input.InputWindowHandle;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.function.Predicate;
+
/** A window in the window manager. */
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {
static final String TAG = TAG_WITH_CLASS_NAME ? "WindowState" : TAG_WM;
// 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;
return false;
}
- if (ActivityManager.isLowRamDeviceStatic()) {
+ if (isLowRamDeviceStatic()) {
// Don't save surfaces on Svelte devices.
return false;
}
}
final void performSurfacePlacement() {
- if (mDeferDepth > 0) {
+ performSurfacePlacement(false /* force */);
+ }
+
+ final void performSurfacePlacement(boolean force) {
+ if (mDeferDepth > 0 && !force) {
return;
}
int loopCount = 6;
mService.mAppTransition.postAnimationCallback();
mService.mAppTransition.clear();
+ mService.mTaskSnapshotController.onTransitionStarting();
+
mService.mOpeningApps.clear();
mService.mClosingApps.clear();
mService.mUnknownAppVisibilityController.clear();
+ 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 {
--- /dev/null
+/*
+ * 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());
+ }
+}
}
@Override
- public void removeSplashScreen(IBinder appToken, StartingSurface surface) {
-
- }
-
- @Override
public int prepareAddWindowLw(WindowState win,
WindowManager.LayoutParams attrs) {
return 0;
: 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);
package android.view;
+import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.Rect;
import com.android.internal.app.IAssistScreenshotReceiver;