Merge "Fixing some drag and drop issues."
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index d45bc5d..ba93b2a 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -166,7 +166,7 @@
" am stack info <STACK_ID>\n" +
" am task lock <TASK_ID>\n" +
" am task lock stop\n" +
- " am task resizeable <TASK_ID> [true|false]\n" +
+ " am task resizeable <TASK_ID> [0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)]\n" +
" am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
" am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
" am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
@@ -323,7 +323,8 @@
"\n" +
"am task lock stop: end the current task lock.\n" +
"\n" +
- "am task resizeable: change if <TASK_ID> is resizeable (true) or not (false).\n" +
+ "am task resizeable: change resizeable mode of <TASK_ID>.\n" +
+ " 0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)\n" +
"\n" +
"am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.\n" +
" Forces the task to be resizeable and creates a stack if no existing stack\n" +
@@ -1985,10 +1986,10 @@
final String taskIdStr = nextArgRequired();
final int taskId = Integer.valueOf(taskIdStr);
final String resizeableStr = nextArgRequired();
- final boolean resizeable = Boolean.valueOf(resizeableStr);
+ final int resizeableMode = Integer.valueOf(resizeableStr);
try {
- mAm.setTaskResizeable(taskId, resizeable);
+ mAm.setTaskResizeable(taskId, resizeableMode);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index cd5797e..138ff6d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2587,9 +2587,9 @@
case SET_TASK_RESIZEABLE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- int taskId = data.readInt();
- boolean resizeable = (data.readInt() == 1) ? true : false;
- setTaskResizeable(taskId, resizeable);
+ final int taskId = data.readInt();
+ final int resizeableMode = data.readInt();
+ setTaskResizeable(taskId, resizeableMode);
reply.writeNoException();
return true;
}
@@ -6307,12 +6307,12 @@
}
@Override
- public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException {
+ public void setTaskResizeable(int taskId, int resizeableMode) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(taskId);
- data.writeInt(resizeable ? 1 : 0);
+ data.writeInt(resizeableMode);
mRemote.transact(SET_TASK_RESIZEABLE_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5b3ffe0..cefbb80 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -530,7 +530,7 @@
public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException;
- public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
+ public void setTaskResizeable(int taskId, int resizeableMode) throws RemoteException;
public void resizeTask(int taskId, Rect bounds, int resizeMode) throws RemoteException;
public Rect getTaskBounds(int taskId) throws RemoteException;
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 91a8e0a..10b8a30 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -785,7 +785,12 @@
}
/** @hide */
- public static final String resizeModeToString(int mode) {
+ public static boolean isResizeableMode(int mode) {
+ return mode == RESIZE_MODE_RESIZEABLE || mode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+ }
+
+ /** @hide */
+ public static String resizeModeToString(int mode) {
switch (mode) {
case RESIZE_MODE_UNRESIZEABLE:
return "RESIZE_MODE_UNRESIZEABLE";
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index b045c17..27ea92d 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -101,15 +101,16 @@
* @param taskBounds Bounds to use when creating a new Task with the input task Id if
* the task doesn't exist yet.
* @param configuration Configuration that is being used with this task.
- * @param cropWindowsToStack True if the app windows should be cropped to the stack bounds.
+ * @param taskResizeMode The resize mode of the task.
* @param alwaysFocusable True if the app windows are always focusable regardless of the stack
* they are in.
+ * @param homeTask True if this is the task.
*/
void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack,
- boolean alwaysFocusable);
+ in Rect taskBounds, in Configuration configuration, int taskResizeMode,
+ boolean alwaysFocusable, boolean homeTask);
/**
*
* @param token The token we are adding to the input task Id.
@@ -119,9 +120,11 @@
* @param taskBounds Bounds to use when creating a new Task with the input task Id if
* the task doesn't exist yet.
* @param config Configuration that is being used with this task.
+ * @param taskResizeMode The resize mode of the task.
+ * @param homeTask True if this is the task.
*/
- void setAppTask(
- IBinder token, int taskId, int stackId, in Rect taskBounds, in Configuration config);
+ void setAppTask(IBinder token, int taskId, int stackId, in Rect taskBounds,
+ in Configuration config, int taskResizeMode, boolean homeTask);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
index eb90b75..bae334b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -17,7 +17,10 @@
package com.android.documentsui;
import static com.android.documentsui.Shared.DEBUG;
+import static com.android.internal.util.Preconditions.checkArgument;
+import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
@@ -25,9 +28,16 @@
import android.provider.DocumentsContract;
import android.util.Log;
+import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperationService.OpType;
import com.android.internal.logging.MetricsLogger;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
/** @hide */
public final class Metrics {
private static final String TAG = "Metrics";
@@ -37,6 +47,7 @@
private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
private static final String AUTHORITY_STORAGE = "com.android.externalstorage.documents";
private static final String AUTHORITY_DOWNLOADS = "com.android.providers.downloads.documents";
+ private static final String AUTHORITY_MTP = "com.android.mtp.documents";
// These strings have to be whitelisted in tron. Do not change them.
private static final String COUNT_LAUNCH_ACTION = "docsui_launch_action";
@@ -47,11 +58,16 @@
private static final String COUNT_BROWSE_ROOT = "docsui_browse_root";
private static final String COUNT_MANAGE_ROOT = "docsui_manage_root";
private static final String COUNT_MULTI_WINDOW = "docsui_multi_window";
+ private static final String COUNT_FILEOP_SYSTEM = "docsui_fileop_system";
+ private static final String COUNT_FILEOP_EXTERNAL = "docsui_fileop_external";
+ private static final String COUNT_FILEOP_CANCELED = "docsui_fileop_canceled";
// Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
// root that is not explicitly recognized by the Metrics code (see {@link
// #getSanitizedRootIndex}). Apps are also bucketed in this histogram using negative indices
// (see below).
+ // Do not change or rearrange these values, that will break historical data. Only add to the end
+ // of the list.
private static final int ROOT_NONE = 0;
private static final int ROOT_OTHER = 1;
private static final int ROOT_AUDIO = 2;
@@ -61,10 +77,27 @@
private static final int ROOT_IMAGES = 6;
private static final int ROOT_RECENTS = 7;
private static final int ROOT_VIDEOS = 8;
+ private static final int ROOT_MTP = 9;
// Apps aren't really "roots", but they are treated as such in the roots fragment UI and so they
// are logged analogously to roots. Use negative numbers to identify apps.
private static final int ROOT_THIRD_PARTY_APP = -1;
+ @IntDef(flag = true, value = {
+ ROOT_NONE,
+ ROOT_OTHER,
+ ROOT_AUDIO,
+ ROOT_DEVICE_STORAGE,
+ ROOT_DOWNLOADS,
+ ROOT_HOME,
+ ROOT_IMAGES,
+ ROOT_RECENTS,
+ ROOT_VIDEOS,
+ ROOT_MTP,
+ ROOT_THIRD_PARTY_APP
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Root {}
+
// Indices for bucketing mime types.
private static final int MIME_OTHER = -2; // anything not enumerated below
private static final int MIME_NONE = -1; // null mime
@@ -77,6 +110,66 @@
private static final int MIME_TEXT = 6; // text/*
private static final int MIME_VIDEO = 7; // video/*
+ @IntDef(flag = true, value = {
+ MIME_OTHER,
+ MIME_NONE,
+ MIME_ANY,
+ MIME_APPLICATION,
+ MIME_AUDIO,
+ MIME_IMAGE,
+ MIME_MESSAGE,
+ MIME_MULTIPART,
+ MIME_TEXT,
+ MIME_VIDEO
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Mime {}
+
+ // Codes representing different kinds of file operations. These are used for bucketing
+ // operations in the COUNT_FILEOP_{SYSTEM|EXTERNAL} histograms.
+ private static final int FILEOP_OTHER = 0; // any file operation not listed below
+ private static final int FILEOP_COPY_INTRA_PROVIDER = 1; // Copy within a provider
+ private static final int FILEOP_COPY_SYSTEM_PROVIDER = 2; // Copy to a system provider.
+ private static final int FILEOP_COPY_EXTERNAL_PROVIDER = 3; // Copy to a 3rd-party provider.
+ private static final int FILEOP_MOVE_INTRA_PROVIDER = 4; // Move within a provider.
+ private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 5; // Move to a system provider.
+ private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 6; // Move to a 3rd-party provider.
+ private static final int FILEOP_DELETE = 7;
+ private static final int FILEOP_OTHER_ERROR = -1;
+ private static final int FILEOP_COPY_ERROR = -2;
+ private static final int FILEOP_MOVE_ERROR = -3;
+ private static final int FILEOP_DELETE_ERROR = -4;
+
+ @IntDef(flag = true, value = {
+ FILEOP_OTHER,
+ FILEOP_COPY_INTRA_PROVIDER,
+ FILEOP_COPY_SYSTEM_PROVIDER,
+ FILEOP_COPY_EXTERNAL_PROVIDER,
+ FILEOP_MOVE_INTRA_PROVIDER,
+ FILEOP_MOVE_SYSTEM_PROVIDER,
+ FILEOP_MOVE_EXTERNAL_PROVIDER,
+ FILEOP_DELETE,
+ FILEOP_OTHER_ERROR,
+ FILEOP_COPY_ERROR,
+ FILEOP_MOVE_ERROR,
+ FILEOP_DELETE_ERROR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FileOp {}
+
+ // Codes representing different provider types. Used for sorting file operations when logging.
+ private static final int PROVIDER_INTRA = 0;
+ private static final int PROVIDER_SYSTEM = 1;
+ private static final int PROVIDER_EXTERNAL = 2;
+
+ @IntDef(flag = true, value = {
+ PROVIDER_INTRA,
+ PROVIDER_SYSTEM,
+ PROVIDER_EXTERNAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Provider {}
+
/**
* Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
*
@@ -140,6 +233,99 @@
}
/**
+ * Logs file operation stats. Call this when a file operation has completed. The given
+ * DocumentInfo is only used to distinguish broad categories of actions (e.g. copying from one
+ * provider to another vs copying within a given provider). No PII is logged.
+ *
+ * @param context
+ * @param operationType
+ * @param srcs
+ * @param dst
+ */
+ public static void logFileOperation(
+ Context context,
+ @OpType int operationType,
+ List<DocumentInfo> srcs,
+ @Nullable DocumentInfo dst) {
+ ProviderCounts counts = countProviders(srcs, dst);
+
+ if (counts.intraProvider > 0) {
+ logIntraProviderFileOps(context, dst.authority, operationType);
+ }
+ if (counts.systemProvider > 0) {
+ // Log file operations on system providers.
+ logInterProviderFileOps(context, COUNT_FILEOP_SYSTEM, dst, operationType);
+ }
+ if (counts.externalProvider > 0) {
+ // Log file operations on external providers.
+ logInterProviderFileOps(context, COUNT_FILEOP_EXTERNAL, dst, operationType);
+ }
+ }
+
+ /**
+ * Logs some kind of file operation error. Call this when a file operation (e.g. copy, delete)
+ * fails.
+ *
+ * @param context
+ * @param operationType
+ * @param failedFiles
+ */
+ public static void logFileOperationErrors(Context context, @OpType int operationType,
+ List<DocumentInfo> failedFiles) {
+ ProviderCounts counts = countProviders(failedFiles, null);
+
+ @FileOp int opCode = FILEOP_OTHER_ERROR;
+ switch (operationType) {
+ case FileOperationService.OPERATION_COPY:
+ opCode = FILEOP_COPY_ERROR;
+ break;
+ case FileOperationService.OPERATION_DELETE:
+ opCode = FILEOP_DELETE_ERROR;
+ break;
+ case FileOperationService.OPERATION_MOVE:
+ opCode = FILEOP_MOVE_ERROR;
+ break;
+ }
+ if (counts.systemProvider > 0) {
+ logHistogram(context, COUNT_FILEOP_SYSTEM, opCode);
+ }
+ if (counts.externalProvider > 0) {
+ logHistogram(context, COUNT_FILEOP_EXTERNAL, opCode);
+ }
+ }
+
+ /**
+ * Log the cancellation of a file operation. Call this when a Job is canceled.
+ * @param context
+ * @param operationType
+ */
+ public static void logFileOperationCancelled(Context context, @OpType int operationType) {
+ logHistogram(context, COUNT_FILEOP_CANCELED, operationType);
+ }
+
+ private static void logInterProviderFileOps(
+ Context context,
+ String histogram,
+ DocumentInfo dst,
+ @OpType int operationType) {
+ if (operationType == FileOperationService.OPERATION_DELETE) {
+ logHistogram(context, histogram, FILEOP_DELETE);
+ } else {
+ checkArgument(dst != null);
+ @Provider int providerType =
+ isSystemProvider(dst.authority) ? PROVIDER_SYSTEM : PROVIDER_EXTERNAL;
+ logHistogram(context, histogram, getOpCode(operationType, providerType));
+ }
+ }
+
+ private static void logIntraProviderFileOps(
+ Context context, String authority, @OpType int operationType) {
+ // Find the right histogram to log to, then log the operation.
+ String histogram = isSystemProvider(authority) ? COUNT_FILEOP_SYSTEM : COUNT_FILEOP_EXTERNAL;
+ logHistogram(context, histogram, getOpCode(operationType, PROVIDER_INTRA));
+ }
+
+ /**
* Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
*
* @param context
@@ -167,7 +353,7 @@
* small set of hard-coded roots (ones provided by the system). Other roots are all grouped into
* a single ROOT_OTHER bucket.
*/
- private static int sanitizeRoot(Uri uri) {
+ private static @Root int sanitizeRoot(Uri uri) {
if (LauncherActivity.isLaunchUri(uri)) {
return ROOT_NONE;
}
@@ -192,13 +378,15 @@
}
case AUTHORITY_DOWNLOADS:
return ROOT_DOWNLOADS;
+ case AUTHORITY_MTP:
+ return ROOT_MTP;
default:
return ROOT_OTHER;
}
}
/** @see #sanitizeRoot(Uri) */
- private static int sanitizeRoot(RootInfo root) {
+ private static @Root int sanitizeRoot(RootInfo root) {
if (root.isRecents()) {
// Recents root is special and only identifiable via this method call. Other roots are
// identified by URI.
@@ -209,7 +397,7 @@
}
/** @see #sanitizeRoot(Uri) */
- private static int sanitizeRoot(ResolveInfo info) {
+ private static @Root int sanitizeRoot(ResolveInfo info) {
// Log all apps under a single bucket in the roots histogram.
return ROOT_THIRD_PARTY_APP;
}
@@ -221,7 +409,7 @@
* @param mimeType
* @return
*/
- private static int sanitizeMime(String mimeType) {
+ private static @Mime int sanitizeMime(String mimeType) {
if (mimeType == null) {
return MIME_NONE;
} else if ("*/*".equals(mimeType)) {
@@ -248,4 +436,75 @@
// Bucket all other types into one bucket.
return MIME_OTHER;
}
+
+ private static boolean isSystemProvider(String authority) {
+ switch (authority) {
+ case AUTHORITY_MEDIA:
+ case AUTHORITY_STORAGE:
+ case AUTHORITY_DOWNLOADS:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * @param operation
+ * @param providerType
+ * @return An opcode, suitable for use as histogram bucket, for the given operation/provider
+ * combination.
+ */
+ private static @FileOp int getOpCode(@OpType int operation, @Provider int providerType) {
+ switch (operation) {
+ case FileOperationService.OPERATION_COPY:
+ switch (providerType) {
+ case PROVIDER_INTRA:
+ return FILEOP_COPY_INTRA_PROVIDER;
+ case PROVIDER_SYSTEM:
+ return FILEOP_COPY_SYSTEM_PROVIDER;
+ case PROVIDER_EXTERNAL:
+ return FILEOP_COPY_EXTERNAL_PROVIDER;
+ }
+ case FileOperationService.OPERATION_MOVE:
+ switch (providerType) {
+ case PROVIDER_INTRA:
+ return FILEOP_MOVE_INTRA_PROVIDER;
+ case PROVIDER_SYSTEM:
+ return FILEOP_MOVE_SYSTEM_PROVIDER;
+ case PROVIDER_EXTERNAL:
+ return FILEOP_MOVE_EXTERNAL_PROVIDER;
+ }
+ case FileOperationService.OPERATION_DELETE:
+ return FILEOP_DELETE;
+ default:
+ Log.w(TAG, "Unrecognized operation type when logging a file operation");
+ return FILEOP_OTHER;
+ }
+ }
+
+ /**
+ * Count the given src documents and provide a tally of how many come from the same provider as
+ * the dst document (if a dst is provided), how many come from system providers, and how many
+ * come from external 3rd-party providers.
+ */
+ private static ProviderCounts countProviders(
+ List<DocumentInfo> srcs, @Nullable DocumentInfo dst) {
+ ProviderCounts counts = new ProviderCounts();
+ for (DocumentInfo doc: srcs) {
+ if (dst != null && doc.authority.equals(dst.authority)) {
+ counts.intraProvider++;
+ } else if (isSystemProvider(doc.authority)){
+ counts.systemProvider++;
+ } else {
+ counts.externalProvider++;
+ }
+ }
+ return counts;
+ }
+
+ private static class ProviderCounts {
+ int intraProvider;
+ int systemProvider;
+ int externalProvider;
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index e5e66f8..7c08ba7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -50,6 +50,7 @@
import android.util.Log;
import android.webkit.MimeTypeMap;
+import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
@@ -214,10 +215,9 @@
mBatchSize = calculateSize(mSrcs);
DocumentInfo srcInfo;
- DocumentInfo dstInfo;
+ DocumentInfo dstInfo = stack.peek();
for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) {
srcInfo = mSrcs.get(i);
- dstInfo = stack.peek();
// Guard unsupported recursive operation.
if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
@@ -232,6 +232,7 @@
processDocument(srcInfo, null, dstInfo);
}
+ Metrics.logFileOperation(service, operationType, mSrcs, dstInfo);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
index 24eb987..11c3a29 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
@@ -25,6 +25,7 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
@@ -90,6 +91,7 @@
onFileFailed(doc);
}
}
+ Metrics.logFileOperation(service, operationType, mSrcs, null);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index 7b8011a..f2c8763 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -41,6 +41,7 @@
import android.util.Log;
import com.android.documentsui.FilesActivity;
+import com.android.documentsui.Metrics;
import com.android.documentsui.OperationDialogFragment;
import com.android.documentsui.R;
import com.android.documentsui.Shared;
@@ -114,6 +115,7 @@
// ensure the service is shut down and notifications
// shown/closed.
Log.e(TAG, "Operation failed due to an exception.", e);
+ Metrics.logFileOperationErrors(service, operationType, failedFiles);
} finally {
listener.onFinished(this);
}
@@ -150,6 +152,7 @@
final void cancel() {
mCanceled = true;
+ Metrics.logFileOperationCancelled(service, operationType);
}
final boolean isCanceled() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 7135836..1c9d937 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -190,7 +190,8 @@
FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
break;
case MODE_WAKE_AND_UNLOCK_PULSING:
- mPhoneStatusBar.updateMediaMetaData(false /* metaDataChanged */);
+ mPhoneStatusBar.updateMediaMetaData(false /* metaDataChanged */,
+ true /* allowEnterAnimation */);
// Fall through.
case MODE_WAKE_AND_UNLOCK:
mStatusBarWindowManager.setStatusBarFocusable(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 0a03a98..2b961fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -26,6 +26,7 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.Context;
@@ -66,6 +67,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
@@ -242,6 +244,11 @@
* Prudently disable QS and notifications. */
private static final boolean ONLY_CORE_APPS;
+ /** If true, the lockscreen will show a distinct wallpaper */
+ private static final boolean ENABLE_LOCKSCREEN_WALLPAPER =
+ !ActivityManager.isLowRamDeviceStatic()
+ && SystemProperties.getBoolean("debug.lockscreen_wallpaper", false);
+
/* If true, the device supports freeform window management.
* This affects the status bar UI. */
private static final boolean FREEFORM_WINDOW_MANAGEMENT;
@@ -459,7 +466,7 @@
if (state != null) {
if (!isPlaybackActive(state.getState())) {
clearCurrentMediaNotification();
- updateMediaMetaData(true);
+ updateMediaMetaData(true, true);
}
}
}
@@ -469,7 +476,7 @@
super.onMetadataChanged(metadata);
if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
mMediaMetadata = metadata;
- updateMediaMetaData(true);
+ updateMediaMetaData(true, true);
}
};
@@ -1313,7 +1320,7 @@
}
if (key.equals(mMediaNotificationKey)) {
clearCurrentMediaNotification();
- updateMediaMetaData(true);
+ updateMediaMetaData(true, true);
}
if (deferRemoval) {
mLatestRankingMap = ranking;
@@ -1704,7 +1711,7 @@
if (metaDataChanged) {
updateNotifications();
}
- updateMediaMetaData(metaDataChanged);
+ updateMediaMetaData(metaDataChanged, true);
}
private int getMediaControllerPlaybackState(MediaController controller) {
@@ -1763,7 +1770,7 @@
/**
* Refresh or remove lockscreen artwork from media metadata.
*/
- public void updateMediaMetaData(boolean metaDataChanged) {
+ public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) return;
if (mBackdrop == null) return; // called too early
@@ -1788,6 +1795,12 @@
// might still be null
}
}
+ if (ENABLE_LOCKSCREEN_WALLPAPER && artworkBitmap == null) {
+ // TODO: use real lockscreen wallpaper.
+ WallpaperManager wallpaperManager = mContext
+ .getSystemService(WallpaperManager.class);
+ artworkBitmap = wallpaperManager.getBitmap();
+ }
final boolean hasArtwork = artworkBitmap != null;
@@ -1797,7 +1810,12 @@
// time to show some art!
if (mBackdrop.getVisibility() != View.VISIBLE) {
mBackdrop.setVisibility(View.VISIBLE);
- mBackdrop.animate().alpha(1f);
+ if (allowEnterAnimation) {
+ mBackdrop.animate().alpha(1f);
+ } else {
+ mBackdrop.animate().cancel();
+ mBackdrop.setAlpha(1f);
+ }
metaDataChanged = true;
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
@@ -3021,6 +3039,10 @@
else if (Intent.ACTION_SCREEN_ON.equals(action)) {
notifyNavigationBarScreenOn(true);
}
+ else if (ENABLE_LOCKSCREEN_WALLPAPER
+ && Intent.ACTION_WALLPAPER_CHANGED.equals(action)) {
+ updateMediaMetaData(true, true);
+ }
}
};
@@ -3042,7 +3064,7 @@
}
} else if (ACTION_FAKE_ARTWORK.equals(action)) {
if (DEBUG_MEDIA_FAKE_ARTWORK) {
- updateMediaMetaData(true);
+ updateMediaMetaData(true, true);
}
}
}
@@ -3106,7 +3128,7 @@
resetUserSetupObserver();
setControllerUsers();
clearCurrentMediaNotification();
- updateMediaMetaData(true);
+ updateMediaMetaData(true, false);
}
private void setControllerUsers() {
@@ -3525,7 +3547,7 @@
runLaunchTransitionEndRunnable();
mLaunchTransitionFadingAway = false;
mScrimController.forceHideScrims(false /* hide */);
- updateMediaMetaData(true /* metaDataChanged */);
+ updateMediaMetaData(true /* metaDataChanged */, true);
}
public boolean isCollapsing() {
@@ -3560,7 +3582,7 @@
beforeFading.run();
}
mScrimController.forceHideScrims(true /* hide */);
- updateMediaMetaData(false);
+ updateMediaMetaData(false, true);
mNotificationPanel.setAlpha(1);
mNotificationPanel.animate()
.alpha(0)
@@ -3762,7 +3784,7 @@
updateStackScrollerState(goingToFullShade, fromShadeLocked);
updateNotifications();
checkBarModes();
- updateMediaMetaData(false);
+ updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
mStatusBarKeyguardViewManager.isSecure());
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7dd93d8..69cc39b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8875,7 +8875,7 @@
}
@Override
- public void setTaskResizeable(int taskId, boolean resizeable) {
+ public void setTaskResizeable(int taskId, int resizeableMode) {
synchronized (this) {
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
@@ -8883,9 +8883,9 @@
Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
return;
}
- if (task.mResizeable != resizeable) {
- task.mResizeable = resizeable;
- mWindowManager.setTaskResizeable(taskId, resizeable);
+ if (task.mResizeMode != resizeableMode) {
+ task.mResizeMode = resizeableMode;
+ mWindowManager.setTaskResizeable(taskId, resizeableMode);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
@@ -8904,10 +8904,10 @@
return;
}
int stackId = task.stack.mStackId;
- // First, check if this is a non-resizeble task in docked stack or if the task size
- // is affected by the docked stack changing size. If so, instead of resizing, we
- // can only scroll the task. No need to update configuration.
- if (bounds != null && !task.mResizeable
+ // We allow the task to scroll instead of resizing if this is a non-resizeable task
+ // in crop windows resize mode or if the task size is affected by the docked stack
+ // changing size. No need to update configuration.
+ if (bounds != null && task.inCropWindowsResizeMode()
&& mStackSupervisor.isStackDockedInEffect(stackId)) {
mWindowManager.scrollTask(task.taskId, bounds);
return;
@@ -12164,6 +12164,7 @@
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
mAlwaysFinishActivities = alwaysFinishActivities;
mForceResizableActivities = forceResizable;
+ mWindowManager.setForceResizableTasks(mForceResizableActivities);
mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
// This happens before any activities are started, so we can
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d1fcd3b..133ac38 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -19,8 +19,6 @@
import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -758,18 +756,13 @@
}
boolean isResizeable() {
- return !isHomeActivity() && (info.resizeMode == RESIZE_MODE_RESIZEABLE
- || info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE);
+ return !isHomeActivity() && ActivityInfo.isResizeableMode(info.resizeMode);
}
boolean supportsPictureInPicture() {
return !isHomeActivity() && info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
}
- boolean cropAppWindows() {
- return !isHomeActivity() && info.resizeMode == RESIZE_MODE_CROP_WINDOWS;
- }
-
boolean isAlwaysFocusable() {
return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 3e99558..dac0f7d0 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1410,10 +1410,11 @@
}
if (mStackId == DOCKED_STACK_ID) {
- // Docked stack is always visible, except in the case where the top running activity in
- // the focus stack doesn't support any form of resizing.
+ // Docked stack is always visible, except in the case where the top running activity
+ // task in the focus stack doesn't support any form of resizing.
final ActivityRecord r = focusedStack.topRunningActivityLocked();
- return r == null || r.isResizeable() || r.cropAppWindows()
+ final TaskRecord task = r != null ? r.task : null;
+ return task == null || task.isResizeable() || task.inCropWindowsResizeMode()
? STACK_VISIBLE : STACK_INVISIBLE;
}
@@ -4751,7 +4752,7 @@
// add the task to stack first, mTaskPositioner might need the stack association
addTask(task, toTop, "createTaskRecord");
final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
- if (!layoutTaskInStack(task, info.layout) && mBounds != null && task.mResizeable
+ if (!layoutTaskInStack(task, info.layout) && mBounds != null && task.isResizeable()
&& !isLockscreenShown) {
task.updateOverrideConfiguration(mBounds);
}
@@ -4816,8 +4817,7 @@
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
- r.cropAppWindows() | r.isResizeable(), r.isAlwaysFocusable());
- mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
+ task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask());
r.taskConfigOverride = task.mOverrideConfig;
}
@@ -4869,9 +4869,8 @@
private void setAppTask(ActivityRecord r, TaskRecord task) {
final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
- mWindowManager.setAppTask(
- r.appToken, task.taskId, mStackId, bounds, task.mOverrideConfig);
- mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
+ mWindowManager.setAppTask(r.appToken, task.taskId, mStackId, bounds, task.mOverrideConfig,
+ task.mResizeMode, task.isHomeTask());
r.taskConfigOverride = task.mOverrideConfig;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 11dd8a3..1660dda 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -119,6 +119,7 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
@@ -1713,7 +1714,7 @@
return;
}
- if (task.mResizeable && options != null) {
+ if (task.isResizeable() && options != null) {
int stackId = options.getLaunchStackId();
if (canUseActivityOptionsLaunchBounds(options, stackId)) {
final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
@@ -1895,10 +1896,10 @@
mTmpBounds.clear();
mTmpConfigs.clear();
mTmpInsetBounds.clear();
- ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final ArrayList<TaskRecord> tasks = stack.getAllTasks();
for (int i = tasks.size() - 1; i >= 0; i--) {
- TaskRecord task = tasks.get(i);
- if (task.mResizeable) {
+ final TaskRecord task = tasks.get(i);
+ if (task.isResizeable()) {
if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
// For freeform stack we don't adjust the size of the tasks to match that
// of the stack, but we do try to make sure the tasks are still contained
@@ -2010,7 +2011,7 @@
}
boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
- if (!task.mResizeable) {
+ if (!task.isResizeable()) {
Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
return true;
}
@@ -2189,13 +2190,13 @@
final boolean wasFront = isFrontStack(prevStack)
&& (prevStack.topRunningActivityLocked() == r);
- final boolean resizeable = task.mResizeable;
+ final int resizeMode = task.mResizeMode;
// Temporarily disable resizeablility of task we are moving. We don't want it to be resized
// if a docked stack is created below which will lead to the stack we are moving from and
// its resizeable tasks being resized.
- task.mResizeable = false;
+ task.mResizeMode = RESIZE_MODE_UNRESIZEABLE;
final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
- task.mResizeable = resizeable;
+ task.mResizeMode = resizeMode;
mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
stack.addTask(task, toTop, reason);
@@ -2266,7 +2267,7 @@
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
- if (!task.mResizeable && isStackDockedInEffect(stackId)) {
+ if (!task.isResizeable() && isStackDockedInEffect(stackId)) {
showNonResizeableDockToast(taskId);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7b7359f..22b8462 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1004,7 +1004,7 @@
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
- if (!mStartActivity.task.mResizeable
+ if (!mStartActivity.task.isResizeable()
&& mSupervisor.isStackDockedInEffect(mTargetStack.mStackId)) {
mSupervisor.showNonResizeableDockToast(mStartActivity.task.taskId);
}
@@ -1721,7 +1721,7 @@
Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
Rect newBounds = null;
- if (options != null && (r.isResizeable() || (inTask != null && inTask.mResizeable))) {
+ if (options != null && (r.isResizeable() || (inTask != null && inTask.isResizeable()))) {
if (mSupervisor.canUseActivityOptionsLaunchBounds(
options, options.getLaunchStackId())) {
newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index c9d4595..c14cfef 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -24,8 +24,9 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
@@ -118,7 +119,10 @@
private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
private static final String ATTR_CALLING_UID = "calling_uid";
private static final String ATTR_CALLING_PACKAGE = "calling_package";
+ // TODO(b/26847884): Currently needed while migrating to resize_mode.
+ // Can be removed at some later point.
private static final String ATTR_RESIZEABLE = "resizeable";
+ private static final String ATTR_RESIZE_MODE = "resize_mode";
private static final String ATTR_PRIVILEGED = "privileged";
private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
@@ -156,8 +160,8 @@
int numFullscreen; // Number of fullscreen activities.
- boolean mResizeable; // Activities in the task resizeable. Based on the resizable setting of
- // the root activity.
+ int mResizeMode; // The resize mode of this task and its activities.
+ // Based on the {@link ActivityInfo#resizeMode} of the root activity.
int mLockTaskMode; // Which tasklock mode to launch this task in. One of
// ActivityManager.LOCK_TASK_LAUNCH_MODE_*
private boolean mPrivileged; // The root activity application of this task holds
@@ -309,7 +313,7 @@
boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- boolean resizeable, boolean privileged, boolean realActivitySuspended) {
+ int resizeMode, boolean privileged, boolean _realActivitySuspended) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
@@ -323,7 +327,7 @@
voiceSession = null;
voiceInteractor = null;
realActivity = _realActivity;
- realActivitySuspended = realActivitySuspended;
+ realActivitySuspended = _realActivitySuspended;
origActivity = _origActivity;
rootWasReset = _rootWasReset;
isAvailable = true;
@@ -346,7 +350,7 @@
mNextAffiliateTaskId = nextTaskId;
mCallingUid = callingUid;
mCallingPackage = callingPackage;
- mResizeable = resizeable || mService.mForceResizableActivities;
+ mResizeMode = resizeMode;
mPrivileged = privileged;
ActivityInfo info = (mActivities.size() > 0) ? mActivities.get(0).info : null;
mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
@@ -448,9 +452,7 @@
} else {
autoRemoveRecents = false;
}
- mResizeable = info.resizeMode == RESIZE_MODE_RESIZEABLE
- || info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE
- || mService.mForceResizableActivities;
+ mResizeMode = info.resizeMode;
mLockTaskMode = info.lockTaskLaunchMode;
mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
setLockTaskAuth();
@@ -705,9 +707,6 @@
// Only set this based on the first activity
if (mActivities.isEmpty()) {
taskType = r.mActivityType;
- if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivities) {
- mResizeable = r.isResizeable();
- }
isPersistable = r.isPersistable();
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
@@ -935,6 +934,15 @@
return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
}
+ boolean isResizeable() {
+ return !isHomeTask() && (mService.mForceResizableActivities
+ || ActivityInfo.isResizeableMode(mResizeMode));
+ }
+
+ boolean inCropWindowsResizeMode() {
+ return !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
+ }
+
/**
* Find the activity in the history stack within the given task. Returns
* the index within the history at which it's found, or < 0 if not found.
@@ -1073,7 +1081,7 @@
out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
- out.attribute(null, ATTR_RESIZEABLE, String.valueOf(mResizeable));
+ out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
if (mLastNonFullscreenBounds != null) {
out.attribute(
@@ -1139,7 +1147,7 @@
int nextTaskId = INVALID_TASK_ID;
int callingUid = -1;
String callingPackage = "";
- boolean resizeable = false;
+ int resizeMode = RESIZE_MODE_UNRESIZEABLE;
boolean privileged = false;
Rect bounds = null;
@@ -1200,7 +1208,10 @@
} else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
callingPackage = attrValue;
} else if (ATTR_RESIZEABLE.equals(attrName)) {
- resizeable = Boolean.valueOf(attrValue);
+ resizeMode = Boolean.valueOf(attrValue)
+ ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_CROP_WINDOWS;
+ } else if (ATTR_RESIZE_MODE.equals(attrName)) {
+ resizeMode = Integer.valueOf(attrValue);
} else if (ATTR_PRIVILEGED.equals(attrName)) {
privileged = Boolean.valueOf(attrValue);
} else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
@@ -1264,7 +1275,7 @@
autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
- taskAffiliationColor, callingUid, callingPackage, resizeable, privileged,
+ taskAffiliationColor, callingUid, callingPackage, resizeMode, privileged,
realActivitySuspended);
task.updateOverrideConfiguration(bounds);
@@ -1404,7 +1415,7 @@
}
if (inStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- if (!mResizeable) {
+ if (!isResizeable()) {
throw new IllegalArgumentException("Can not position non-resizeable task="
+ this + " in stack=" + inStack);
}
@@ -1450,8 +1461,8 @@
final int stackId = stack.mStackId;
if (stackId == HOME_STACK_ID
|| stackId == FULLSCREEN_WORKSPACE_STACK_ID
- || (stackId == DOCKED_STACK_ID && !mResizeable)) {
- return mResizeable ? stack.mBounds : null;
+ || (stackId == DOCKED_STACK_ID && !isResizeable())) {
+ return isResizeable() ? stack.mBounds : null;
} else if (!StackId.persistTaskBounds(stackId)) {
return stack.mBounds;
}
@@ -1554,12 +1565,12 @@
if (stack != null) {
pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId);
}
- pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
- pw.print(" mResizeable="); pw.print(mResizeable);
- pw.print(" firstActiveTime="); pw.print(lastActiveTime);
- pw.print(" lastActiveTime="); pw.print(lastActiveTime);
- pw.print(" (inactive for ");
- pw.print((getInactiveDuration()/1000)); pw.println("s)");
+ pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
+ pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
+ pw.print(" isResizeable=" + isResizeable());
+ pw.print(" firstActiveTime=" + lastActiveTime);
+ pw.print(" lastActiveTime=" + lastActiveTime);
+ pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
}
@Override
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2732821..c0d34e8 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -125,9 +125,6 @@
boolean mLaunchTaskBehind;
boolean mEnteringAnimation;
- // True if the windows associated with this token should be cropped to their stack bounds.
- boolean mCropWindowsToStack;
-
boolean mAlwaysFocusable;
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d9667a1..4f59c62 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -21,6 +21,7 @@
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -32,6 +33,7 @@
import static android.view.WindowManager.DOCKED_TOP;
import android.app.ActivityManager.StackId;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.EventLog;
@@ -84,8 +86,8 @@
// For handling display rotations.
private Rect mTmpRect2 = new Rect();
- // Whether the task is resizeable
- private boolean mResizeable;
+ // Resize mode of the task. See {@link ActivityInfo#resizeMode}
+ private int mResizeMode;
// Whether we need to show toast about the app being non-resizeable when it becomes visible.
// This flag is set when a non-resizeable task is docked (or side-by-side). It's cleared
@@ -95,6 +97,8 @@
// Whether the task is currently being drag-resized
private boolean mDragResizing;
+ private boolean mHomeTask;
+
Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
Configuration config) {
mTaskId = taskId;
@@ -156,7 +160,7 @@
}
}
- void addAppToken(int addPos, AppWindowToken wtoken) {
+ void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
final int lastPos = mAppTokens.size();
if (addPos >= lastPos) {
addPos = lastPos;
@@ -171,6 +175,8 @@
mAppTokens.add(addPos, wtoken);
wtoken.mTask = this;
mDeferRemoval = false;
+ mResizeMode = resizeMode;
+ mHomeTask = homeTask;
}
private boolean hasAppTokensAlive() {
@@ -319,12 +325,21 @@
out.set(mTempInsetBounds);
}
- void setResizeable(boolean resizeable) {
- mResizeable = resizeable;
+ void setResizeable(int resizeMode) {
+ mResizeMode = resizeMode;
}
boolean isResizeable() {
- return mResizeable;
+ return !mHomeTask
+ && (ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks);
+ }
+
+ boolean cropWindowsToStackBounds() {
+ return !mHomeTask && (isResizeable() || mResizeMode == RESIZE_MODE_CROP_WINDOWS);
+ }
+
+ private boolean inCropWindowsResizeMode() {
+ return !mHomeTask && !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
}
boolean resizeLocked(Rect bounds, Configuration configuration, boolean forced) {
@@ -619,7 +634,7 @@
}
boolean isTwoFingerScrollMode() {
- return isDockedInEffect() && !isResizeable();
+ return inCropWindowsResizeMode() && isDockedInEffect();
}
WindowState getTopVisibleAppMainWindow() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e0e44dc..f93b495 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -114,7 +114,6 @@
import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManagerInternal;
import android.widget.Toast;
-
import com.android.internal.R;
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
@@ -220,8 +219,8 @@
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_STACK_CRAWLS;
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_SURFACE_ALLOC;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
@@ -492,6 +491,8 @@
private final SparseIntArray mTmpTaskIds = new SparseIntArray();
+ boolean mForceResizableTasks = false;
+
int getDragLayerLocked() {
return mPolicy.windowTypeToLayerLw(LayoutParams.TYPE_DRAG) * TYPE_LAYER_MULTIPLIER
+ TYPE_LAYER_OFFSET;
@@ -1892,6 +1893,12 @@
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
+ } else if (type == TYPE_QS_DIALOG) {
+ if (token.windowType != TYPE_QS_DIALOG) {
+ Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+ }
} else if (token.appWindowToken != null) {
Slog.w(TAG_WM, "Non-null appWindowToken for system window of type=" + type);
// It is not valid to use an app token with other system types; we will
@@ -3214,8 +3221,8 @@
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- Rect taskBounds, Configuration config, boolean cropWindowsToStack,
- boolean alwaysFocusable) {
+ Rect taskBounds, Configuration config, int taskResizeMode, boolean alwaysFocusable,
+ boolean homeTask) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3249,7 +3256,6 @@
atoken.layoutConfigChanges = (configChanges &
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
atoken.mLaunchTaskBehind = launchTaskBehind;
- atoken.mCropWindowsToStack = cropWindowsToStack;
atoken.mAlwaysFocusable = alwaysFocusable;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
@@ -3258,7 +3264,7 @@
if (task == null) {
task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
}
- task.addAppToken(addPos, atoken);
+ task.addAppToken(addPos, atoken, taskResizeMode, homeTask);
mTokenMap.put(token.asBinder(), atoken);
@@ -3269,8 +3275,8 @@
}
@Override
- public void setAppTask(
- IBinder token, int taskId, int stackId, Rect taskBounds, Configuration config) {
+ public void setAppTask(IBinder token, int taskId, int stackId, Rect taskBounds,
+ Configuration config, int taskResizeMode, boolean homeTask) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppTask()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3290,7 +3296,7 @@
newTask = createTaskLocked(
taskId, stackId, oldTask.mUserId, atoken, taskBounds, config);
}
- newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken);
+ newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken, taskResizeMode, homeTask);
}
}
@@ -10326,15 +10332,21 @@
}
}
- public void setTaskResizeable(int taskId, boolean resizeable) {
+ public void setTaskResizeable(int taskId, int resizeMode) {
synchronized (mWindowMap) {
- Task task = mTaskIdToTask.get(taskId);
+ final Task task = mTaskIdToTask.get(taskId);
if (task != null) {
- task.setResizeable(resizeable);
+ task.setResizeable(resizeMode);
}
}
}
+ public void setForceResizableTasks(boolean forceResizableTasks) {
+ synchronized (mWindowMap) {
+ mForceResizableTasks = forceResizableTasks;
+ }
+ }
+
static int dipToPixel(int dip, DisplayMetrics displayMetrics) {
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4dd2b4d..10a2a6c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1002,11 +1002,12 @@
* @param bounds The rect which gets the bounds.
*/
void getVisibleBounds(Rect bounds) {
- boolean intersectWithStackBounds = mAppToken != null && mAppToken.mCropWindowsToStack;
+ final Task task = getTask();
+ boolean intersectWithStackBounds = task != null && task.cropWindowsToStackBounds();
bounds.setEmpty();
mTmpRect.setEmpty();
if (intersectWithStackBounds) {
- final TaskStack stack = getStack();
+ final TaskStack stack = task.mStack;
if (stack != null) {
stack.getDimBounds(mTmpRect);
} else {
@@ -1932,11 +1933,12 @@
}
void cropRegionToStackBoundsIfNeeded(Region region) {
- if (mAppToken == null || !mAppToken.mCropWindowsToStack) {
+ final Task task = getTask();
+ if (task == null || !task.cropWindowsToStackBounds()) {
return;
}
- final TaskStack stack = getStack();
+ final TaskStack stack = task.mStack;
if (stack == null) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 428ab7a..d21a3b4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1171,9 +1171,8 @@
}
private void adjustCropToStackBounds(WindowState w, Rect clipRect, boolean isFreeformResizing) {
- final AppWindowToken appToken = w.mAppToken;
final Task task = w.getTask();
- if (task == null || !appToken.mCropWindowsToStack) {
+ if (task == null || !task.cropWindowsToStackBounds()) {
return;
}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index b78fd49..0286506 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
try {
mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
- Configuration.EMPTY, false, false);
+ Configuration.EMPTY, 0, false, false);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -103,7 +103,7 @@
}
try {
- mWm.setAppTask(null, 0, INVALID_STACK_ID, null, null);
+ mWm.setAppTask(null, 0, INVALID_STACK_ID, null, null, 0, false);
fail("IWindowManager.setAppGroupId did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 9f0153a..38eb5ee 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -77,7 +77,8 @@
@Override
public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
- Rect arg11, Configuration arg12, boolean arg13, boolean arg14) throws RemoteException {
+ Rect arg11, Configuration arg12, int arg13, boolean arg14, boolean arg15)
+ throws RemoteException {
// TODO Auto-generated method stub
}
@@ -322,7 +323,8 @@
}
@Override
- public void setAppTask(IBinder arg0, int arg1, int arg2, Rect arg3, Configuration arg4)
+ public void setAppTask(IBinder arg0, int arg1, int arg2, Rect arg3, Configuration arg4,
+ int arg5, boolean arg6)
throws RemoteException {
// TODO Auto-generated method stub
}