Merge "use running sum for ValueMetricProducer bucket simplify ValueMetricProducer logic for pulled data"
diff --git a/api/current.txt b/api/current.txt
index e97670a..a01de4f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -49586,6 +49586,44 @@
method public void proceed();
}
+ public class TracingConfig {
+ ctor public TracingConfig(int);
+ ctor public TracingConfig(int, java.lang.String, int);
+ method public java.lang.String getCustomCategoryPattern();
+ method public int getPresetCategories();
+ method public int getTracingMode();
+ field public static final int CATEGORIES_FRAME_VIEWER = 4; // 0x4
+ field public static final int CATEGORIES_INPUT_LATENCY = 1; // 0x1
+ field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3; // 0x3
+ field public static final int CATEGORIES_NONE = -1; // 0xffffffff
+ field public static final int CATEGORIES_RENDERING = 2; // 0x2
+ field public static final int CATEGORIES_WEB_DEVELOPER = 0; // 0x0
+ field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
+ field public static final int RECORD_TO_CONSOLE = 3; // 0x3
+ field public static final int RECORD_UNTIL_FULL = 0; // 0x0
+ field public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2; // 0x2
+ }
+
+ public abstract class TracingController {
+ ctor public TracingController();
+ method public static android.webkit.TracingController getInstance();
+ method public abstract boolean isTracing();
+ method public abstract boolean start(android.webkit.TracingConfig);
+ method public abstract boolean stop();
+ method public abstract boolean stopAndFlush(android.webkit.TracingController.TracingOutputStream, android.os.Handler);
+ }
+
+ public static abstract interface TracingController.TracingOutputStream {
+ method public abstract void complete();
+ method public abstract void write(byte[]);
+ }
+
+ public class TracingFileOutputStream implements android.webkit.TracingController.TracingOutputStream {
+ ctor public TracingFileOutputStream(java.lang.String) throws java.io.FileNotFoundException;
+ method public void complete();
+ method public void write(byte[]);
+ }
+
public final class URLUtil {
ctor public URLUtil();
method public static java.lang.String composeSearchUrl(java.lang.String, java.lang.String, java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index eb0b133..30e4cbc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4637,6 +4637,7 @@
method public abstract android.webkit.ServiceWorkerController getServiceWorkerController();
method public abstract android.webkit.WebViewFactoryProvider.Statics getStatics();
method public abstract android.webkit.TokenBindingService getTokenBindingService();
+ method public abstract android.webkit.TracingController getTracingController();
method public abstract android.webkit.WebIconDatabase getWebIconDatabase();
method public abstract android.webkit.WebStorage getWebStorage();
method public abstract android.webkit.WebViewDatabase getWebViewDatabase(android.content.Context);
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 9ee11f8..d3ec320 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -88,8 +88,8 @@
final boolean longpress = "--longpress".equals(args[index + 1]);
final int start = longpress ? index + 2 : index + 1;
inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
- if (length > start) {
- for (int i = start; i < length; i++) {
+ if (args.length > start) {
+ for (int i = start; i < args.length; i++) {
int keyCode = KeyEvent.keyCodeFromString(args[i]);
if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8824643..97dcb90 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -391,8 +391,12 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SHOW_MODE_AUTO, SHOW_MODE_HIDDEN})
- public @interface SoftKeyboardShowMode {};
+ @IntDef(prefix = { "SHOW_MODE_" }, value = {
+ SHOW_MODE_AUTO,
+ SHOW_MODE_HIDDEN
+ })
+ public @interface SoftKeyboardShowMode {}
+
public static final int SHOW_MODE_AUTO = 0;
public static final int SHOW_MODE_HIDDEN = 1;
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index bd9c9fa..782733f 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -290,8 +290,13 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({VISIBILITY_UNDEFINED, VISIBILITY_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE,
- VISIBILITY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_NOT_VISIBLE})
+ @IntDef(prefix = { "VISIBILITY_" }, value = {
+ VISIBILITY_UNDEFINED,
+ VISIBILITY_VISIBLE,
+ VISIBILITY_USER_MANAGED_VISIBLE,
+ VISIBILITY_NOT_VISIBLE,
+ VISIBILITY_USER_MANAGED_NOT_VISIBLE
+ })
public @interface AccountVisibility {
}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 0e8326d..04ff48c 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -95,7 +95,11 @@
public abstract class ActionBar {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
+ @IntDef(prefix = { "NAVIGATION_MODE_" }, value = {
+ NAVIGATION_MODE_STANDARD,
+ NAVIGATION_MODE_LIST,
+ NAVIGATION_MODE_TABS
+ })
public @interface NavigationMode {}
/**
@@ -139,15 +143,14 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- DISPLAY_USE_LOGO,
- DISPLAY_SHOW_HOME,
- DISPLAY_HOME_AS_UP,
- DISPLAY_SHOW_TITLE,
- DISPLAY_SHOW_CUSTOM,
- DISPLAY_TITLE_MULTIPLE_LINES
- })
+ @IntDef(flag = true, prefix = { "DISPLAY_" }, value = {
+ DISPLAY_USE_LOGO,
+ DISPLAY_SHOW_HOME,
+ DISPLAY_HOME_AS_UP,
+ DISPLAY_SHOW_TITLE,
+ DISPLAY_SHOW_CUSTOM,
+ DISPLAY_TITLE_MULTIPLE_LINES
+ })
public @interface DisplayOptions {}
/**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 3ca23f2..847082a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -175,7 +175,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "BUGREPORT_OPTION_" }, value = {
BUGREPORT_OPTION_FULL,
BUGREPORT_OPTION_INTERACTIVE,
BUGREPORT_OPTION_REMOTE,
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index c1a5104..c943574 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -258,8 +258,10 @@
public static final int OP_CHANGE_WIFI_STATE = 71;
/** @hide Request package deletion through package installer */
public static final int OP_REQUEST_DELETE_PACKAGES = 72;
+ /** @hide Bind an accessibility service. */
+ public static final int OP_BIND_ACCESSIBILITY_SERVICE = 73;
/** @hide */
- public static final int _NUM_OP = 73;
+ public static final int _NUM_OP = 74;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -503,6 +505,7 @@
OP_RUN_ANY_IN_BACKGROUND,
OP_CHANGE_WIFI_STATE,
OP_REQUEST_DELETE_PACKAGES,
+ OP_BIND_ACCESSIBILITY_SERVICE,
};
/**
@@ -583,6 +586,7 @@
null, // OP_RUN_ANY_IN_BACKGROUND
null, // OP_CHANGE_WIFI_STATE
null, // OP_REQUEST_DELETE_PACKAGES
+ null, // OP_BIND_ACCESSIBILITY_SERVICE
};
/**
@@ -663,6 +667,7 @@
"RUN_ANY_IN_BACKGROUND",
"CHANGE_WIFI_STATE",
"REQUEST_DELETE_PACKAGES",
+ "BIND_ACCESSIBILITY_SERVICE",
};
/**
@@ -743,6 +748,7 @@
null, // no permission for OP_RUN_ANY_IN_BACKGROUND
Manifest.permission.CHANGE_WIFI_STATE,
Manifest.permission.REQUEST_DELETE_PACKAGES,
+ Manifest.permission.BIND_ACCESSIBILITY_SERVICE,
};
/**
@@ -824,6 +830,7 @@
null, // OP_RUN_ANY_IN_BACKGROUND
null, // OP_CHANGE_WIFI_STATE
null, // REQUEST_DELETE_PACKAGES
+ null, // OP_BIND_ACCESSIBILITY_SERVICE
};
/**
@@ -904,6 +911,7 @@
false, // OP_RUN_ANY_IN_BACKGROUND
false, // OP_CHANGE_WIFI_STATE
false, // OP_REQUEST_DELETE_PACKAGES
+ false, // OP_BIND_ACCESSIBILITY_SERVICE
};
/**
@@ -983,6 +991,7 @@
AppOpsManager.MODE_ALLOWED, // OP_RUN_ANY_IN_BACKGROUND
AppOpsManager.MODE_ALLOWED, // OP_CHANGE_WIFI_STATE
AppOpsManager.MODE_ALLOWED, // REQUEST_DELETE_PACKAGES
+ AppOpsManager.MODE_ALLOWED, // OP_BIND_ACCESSIBILITY_SERVICE
};
/**
@@ -1066,6 +1075,7 @@
false, // OP_RUN_ANY_IN_BACKGROUND
false, // OP_CHANGE_WIFI_STATE
false, // OP_REQUEST_DELETE_PACKAGES
+ false, // OP_BIND_ACCESSIBILITY_SERVICE
};
/**
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 0f4a7fb..1103649 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -182,7 +182,12 @@
public static final int TRANSIT_FRAGMENT_FADE = 3 | TRANSIT_ENTER_MASK;
/** @hide */
- @IntDef({TRANSIT_NONE, TRANSIT_FRAGMENT_OPEN, TRANSIT_FRAGMENT_CLOSE, TRANSIT_FRAGMENT_FADE})
+ @IntDef(prefix = { "TRANSIT_" }, value = {
+ TRANSIT_NONE,
+ TRANSIT_FRAGMENT_OPEN,
+ TRANSIT_FRAGMENT_CLOSE,
+ TRANSIT_FRAGMENT_FADE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Transit {}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index fb9efe6..705f9a0 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -577,7 +577,13 @@
public int flags;
/** @hide */
- @IntDef({PRIORITY_DEFAULT,PRIORITY_LOW,PRIORITY_MIN,PRIORITY_HIGH,PRIORITY_MAX})
+ @IntDef(prefix = { "PRIORITY_" }, value = {
+ PRIORITY_DEFAULT,
+ PRIORITY_LOW,
+ PRIORITY_MIN,
+ PRIORITY_HIGH,
+ PRIORITY_MAX
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Priority {}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 23c4166..85a9be3 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -80,9 +80,14 @@
public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS
| DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS;
- @IntDef(flag = true,
- value = {DISABLE2_NONE, DISABLE2_MASK, DISABLE2_QUICK_SETTINGS, DISABLE2_SYSTEM_ICONS,
- DISABLE2_NOTIFICATION_SHADE, DISABLE2_GLOBAL_ACTIONS})
+ @IntDef(flag = true, prefix = { "DISABLE2_" }, value = {
+ DISABLE2_NONE,
+ DISABLE2_MASK,
+ DISABLE2_QUICK_SETTINGS,
+ DISABLE2_SYSTEM_ICONS,
+ DISABLE2_NOTIFICATION_SHADE,
+ DISABLE2_GLOBAL_ACTIONS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Disable2Flags {}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index bc61668..0da5e24 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -98,7 +98,11 @@
public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE";
/** @hide */
- @IntDef({MODE_NIGHT_AUTO, MODE_NIGHT_NO, MODE_NIGHT_YES})
+ @IntDef(prefix = { "MODE_" }, value = {
+ MODE_NIGHT_AUTO,
+ MODE_NIGHT_NO,
+ MODE_NIGHT_YES
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface NightMode {}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 081bd81..3829afb 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -176,7 +176,7 @@
// flags for which kind of wallpaper to act on
/** @hide */
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_SYSTEM,
FLAG_LOCK
})
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 80399ae..085fc79 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -89,7 +89,7 @@
public static final int WINDOWING_MODE_FREEFORM = 5;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "WINDOWING_MODE_" }, value = {
WINDOWING_MODE_UNDEFINED,
WINDOWING_MODE_FULLSCREEN,
WINDOWING_MODE_PINNED,
@@ -115,7 +115,7 @@
public static final int ACTIVITY_TYPE_ASSISTANT = 4;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "ACTIVITY_TYPE_" }, value = {
ACTIVITY_TYPE_UNDEFINED,
ACTIVITY_TYPE_STANDARD,
ACTIVITY_TYPE_HOME,
@@ -138,13 +138,12 @@
public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3;
/** @hide */
- @IntDef(flag = true,
- value = {
- WINDOW_CONFIG_BOUNDS,
- WINDOW_CONFIG_APP_BOUNDS,
- WINDOW_CONFIG_WINDOWING_MODE,
- WINDOW_CONFIG_ACTIVITY_TYPE
- })
+ @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = {
+ WINDOW_CONFIG_BOUNDS,
+ WINDOW_CONFIG_APP_BOUNDS,
+ WINDOW_CONFIG_WINDOWING_MODE,
+ WINDOW_CONFIG_ACTIVITY_TYPE
+ })
public @interface WindowConfig {}
public WindowConfiguration() {
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index d0d98c9..2e697ac 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -368,9 +368,9 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- BUGREPORT_FAILURE_FAILED_COMPLETING,
- BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
+ @IntDef(prefix = { "BUGREPORT_FAILURE_" }, value = {
+ BUGREPORT_FAILURE_FAILED_COMPLETING,
+ BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
})
public @interface BugreportFailureCode {}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e43ae5b..3c4036b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1376,8 +1376,13 @@
/**
* @hide
*/
- @IntDef({STATE_USER_UNMANAGED, STATE_USER_SETUP_INCOMPLETE, STATE_USER_SETUP_COMPLETE,
- STATE_USER_SETUP_FINALIZED, STATE_USER_PROFILE_COMPLETE})
+ @IntDef(prefix = { "STATE_USER_" }, value = {
+ STATE_USER_UNMANAGED,
+ STATE_USER_SETUP_INCOMPLETE,
+ STATE_USER_SETUP_COMPLETE,
+ STATE_USER_SETUP_FINALIZED,
+ STATE_USER_PROFILE_COMPLETE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface UserProvisioningState {}
@@ -1550,11 +1555,13 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
+ @IntDef(prefix = { "CODE_" }, value = {
+ CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER, CODE_HAS_PAIRED,
CODE_MANAGED_USERS_NOT_SUPPORTED, CODE_SYSTEM_USER, CODE_CANNOT_ADD_MANAGED_PROFILE,
CODE_NOT_SYSTEM_USER_SPLIT, CODE_DEVICE_ADMIN_NOT_SUPPORTED,
- CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED})
+ CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED
+ })
public @interface ProvisioningPreCondition {}
/**
@@ -1636,11 +1643,15 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {LOCK_TASK_FEATURE_NONE, LOCK_TASK_FEATURE_SYSTEM_INFO,
- LOCK_TASK_FEATURE_NOTIFICATIONS, LOCK_TASK_FEATURE_HOME,
- LOCK_TASK_FEATURE_RECENTS, LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
- LOCK_TASK_FEATURE_KEYGUARD})
+ @IntDef(flag = true, prefix = { "LOCK_TASK_FEATURE_" }, value = {
+ LOCK_TASK_FEATURE_NONE,
+ LOCK_TASK_FEATURE_SYSTEM_INFO,
+ LOCK_TASK_FEATURE_NOTIFICATIONS,
+ LOCK_TASK_FEATURE_HOME,
+ LOCK_TASK_FEATURE_RECENTS,
+ LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
+ LOCK_TASK_FEATURE_KEYGUARD
+ })
public @interface LockTaskFeature {}
/**
@@ -3169,7 +3180,9 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY})
+ @IntDef(flag = true, prefix = { "FLAG_EVICT_" }, value = {
+ FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY
+ })
public @interface LockNowFlag {}
/**
@@ -6233,12 +6246,13 @@
/**
* @hide
*/
- @IntDef(
- flag = true,
- prefix = {"SKIP_", "MAKE_USER_", "START_", "LEAVE_"},
- value = {SKIP_SETUP_WIZARD, MAKE_USER_EPHEMERAL, MAKE_USER_DEMO,
- START_USER_IN_BACKGROUND, LEAVE_ALL_SYSTEM_APPS_ENABLED}
- )
+ @IntDef(flag = true, prefix = { "SKIP_", "MAKE_USER_", "START_", "LEAVE_" }, value = {
+ SKIP_SETUP_WIZARD,
+ MAKE_USER_EPHEMERAL,
+ MAKE_USER_DEMO,
+ START_USER_IN_BACKGROUND,
+ LEAVE_ALL_SYSTEM_APPS_ENABLED
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface CreateAndManageUserFlags {}
@@ -8739,4 +8753,44 @@
throw re.rethrowFromSystemServer();
}
}
+
+ //TODO STOPSHIP Add link to onTransferComplete callback when implemented.
+ /**
+ * Transfers the current administrator. All policies from the current administrator are
+ * migrated to the new administrator. The whole operation is atomic - the transfer is either
+ * complete or not done at all.
+ *
+ * Depending on the current administrator (device owner, profile owner, corporate owned
+ * profile owner), you have the following expected behaviour:
+ * <ul>
+ * <li>A device owner can only be transferred to a new device owner</li>
+ * <li>A profile owner can only be transferred to a new profile owner</li>
+ * <li>A corporate owned managed profile can have two cases:
+ * <ul>
+ * <li>If the device owner and profile owner are the same package,
+ * both will be transferred.</li>
+ * <li>If the device owner and profile owner are different packages,
+ * and if this method is called from the profile owner, only the profile owner
+ * is transferred. Similarly, if it is called from the device owner, only
+ * the device owner is transferred.</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param target Which {@link DeviceAdminReceiver} we want the new administrator to be.
+ * @param bundle Parameters - This bundle allows the current administrator to pass data to the
+ * new administrator. The parameters will be received in the
+ * onTransferComplete callback.
+ * @hide
+ */
+ public void transferOwner(@NonNull ComponentName admin, @NonNull ComponentName target,
+ PersistableBundle bundle) {
+ throwIfParentInstance("transferOwner");
+ try {
+ mService.transferOwner(admin, target, bundle);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b76618b..014d7b9 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -378,4 +378,5 @@
boolean isLogoutEnabled();
List<String> getDisallowedSystemApps(in ComponentName admin, int userId, String provisioningAction);
+ void transferOwner(in ComponentName admin, in ComponentName target, in PersistableBundle bundle);
}
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index 4658a47..5fee853 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -223,7 +223,12 @@
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef({CHAR_UPPER_CASE, CHAR_LOWER_CASE, CHAR_DIGIT, CHAR_SYMBOL})
+ @IntDef(prefix = { "CHAR_" }, value = {
+ CHAR_UPPER_CASE,
+ CHAR_LOWER_CASE,
+ CHAR_DIGIT,
+ CHAR_SYMBOL
+ })
private @interface CharacterCatagory {}
private static final int CHAR_LOWER_CASE = 0;
private static final int CHAR_UPPER_CASE = 1;
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 2b590e0..0f93c59 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -43,10 +43,17 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({TAG_ADB_SHELL_INTERACTIVE, TAG_ADB_SHELL_CMD, TAG_SYNC_RECV_FILE, TAG_SYNC_SEND_FILE,
- TAG_APP_PROCESS_START, TAG_KEYGUARD_DISMISSED, TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
- TAG_KEYGUARD_SECURED})
- public @interface SECURITY_LOG_TAG {}
+ @IntDef(prefix = { "TAG_" }, value = {
+ TAG_ADB_SHELL_INTERACTIVE,
+ TAG_ADB_SHELL_CMD,
+ TAG_SYNC_RECV_FILE,
+ TAG_SYNC_SEND_FILE,
+ TAG_APP_PROCESS_START,
+ TAG_KEYGUARD_DISMISSED,
+ TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
+ TAG_KEYGUARD_SECURED
+ })
+ public @interface SecurityLogTag {}
/**
* Indicate that an ADB interactive shell was opened via "adb shell".
@@ -143,13 +150,8 @@
/**
* Returns the tag of this log entry, which specifies entry's semantics.
- * Could be one of {@link SecurityLog#TAG_SYNC_RECV_FILE},
- * {@link SecurityLog#TAG_SYNC_SEND_FILE}, {@link SecurityLog#TAG_ADB_SHELL_CMD},
- * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START},
- * {@link SecurityLog#TAG_KEYGUARD_DISMISSED}, {@link SecurityLog#TAG_KEYGUARD_SECURED},
- * {@link SecurityLog#TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT}.
*/
- public @SECURITY_LOG_TAG int getTag() {
+ public @SecurityLogTag int getTag() {
return mEvent.getTag();
}
diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java
index fa31273..b0376b5 100644
--- a/core/java/android/app/admin/SystemUpdateInfo.java
+++ b/core/java/android/app/admin/SystemUpdateInfo.java
@@ -52,7 +52,11 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SECURITY_PATCH_STATE_FALSE, SECURITY_PATCH_STATE_TRUE, SECURITY_PATCH_STATE_UNKNOWN})
+ @IntDef(prefix = { "SECURITY_PATCH_STATE_" }, value = {
+ SECURITY_PATCH_STATE_FALSE,
+ SECURITY_PATCH_STATE_TRUE,
+ SECURITY_PATCH_STATE_UNKNOWN
+ })
public @interface SecurityPatchState {}
private static final String ATTR_RECEIVED_TIME = "received-time";
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 995d98a..232a688 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -36,10 +36,11 @@
public class SystemUpdatePolicy implements Parcelable {
/** @hide */
- @IntDef({
- TYPE_INSTALL_AUTOMATIC,
- TYPE_INSTALL_WINDOWED,
- TYPE_POSTPONE})
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_INSTALL_AUTOMATIC,
+ TYPE_INSTALL_WINDOWED,
+ TYPE_POSTPONE
+ })
@Retention(RetentionPolicy.SOURCE)
@interface SystemUpdatePolicyType {}
diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
index 24141e5..0fdc7c5 100644
--- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -27,8 +27,17 @@
*/
public abstract class ActivityLifecycleItem extends ClientTransactionItem {
- @IntDef({UNDEFINED, PRE_ON_CREATE, ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP,
- ON_DESTROY, ON_RESTART})
+ @IntDef(prefix = { "UNDEFINED", "PRE_", "ON_" }, value = {
+ UNDEFINED,
+ PRE_ON_CREATE,
+ ON_CREATE,
+ ON_START,
+ ON_RESUME,
+ ON_PAUSE,
+ ON_STOP,
+ ON_DESTROY,
+ ON_RESTART
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface LifecycleState{}
public static final int UNDEFINED = -1;
diff --git a/core/java/android/app/timezone/Callback.java b/core/java/android/app/timezone/Callback.java
index aea8038..e3840be 100644
--- a/core/java/android/app/timezone/Callback.java
+++ b/core/java/android/app/timezone/Callback.java
@@ -30,9 +30,14 @@
public abstract class Callback {
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SUCCESS, ERROR_UNKNOWN_FAILURE, ERROR_INSTALL_BAD_DISTRO_STRUCTURE,
- ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION, ERROR_INSTALL_RULES_TOO_OLD,
- ERROR_INSTALL_VALIDATION_ERROR})
+ @IntDef(prefix = { "SUCCESS", "ERROR_" }, value = {
+ SUCCESS,
+ ERROR_UNKNOWN_FAILURE,
+ ERROR_INSTALL_BAD_DISTRO_STRUCTURE,
+ ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION,
+ ERROR_INSTALL_RULES_TOO_OLD,
+ ERROR_INSTALL_VALIDATION_ERROR
+ })
public @interface AsyncResultCode {}
/**
diff --git a/core/java/android/app/timezone/RulesManager.java b/core/java/android/app/timezone/RulesManager.java
index 417e7d2..0a38eb9 100644
--- a/core/java/android/app/timezone/RulesManager.java
+++ b/core/java/android/app/timezone/RulesManager.java
@@ -69,7 +69,11 @@
private static final boolean DEBUG = false;
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SUCCESS, ERROR_UNKNOWN_FAILURE, ERROR_OPERATION_IN_PROGRESS})
+ @IntDef(prefix = { "SUCCESS", "ERROR_" }, value = {
+ SUCCESS,
+ ERROR_UNKNOWN_FAILURE,
+ ERROR_OPERATION_IN_PROGRESS
+ })
public @interface ResultCode {}
/**
diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java
index ec247eb..16309fa 100644
--- a/core/java/android/app/timezone/RulesState.java
+++ b/core/java/android/app/timezone/RulesState.java
@@ -63,11 +63,12 @@
public final class RulesState implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "STAGED_OPERATION_" }, value = {
STAGED_OPERATION_UNKNOWN,
STAGED_OPERATION_NONE,
STAGED_OPERATION_UNINSTALL,
- STAGED_OPERATION_INSTALL })
+ STAGED_OPERATION_INSTALL
+ })
private @interface StagedOperationType {}
/** Staged state could not be determined. */
@@ -80,10 +81,11 @@
public static final int STAGED_OPERATION_INSTALL = 3;
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "DISTRO_STATUS_" }, value = {
DISTRO_STATUS_UNKNOWN,
DISTRO_STATUS_NONE,
- DISTRO_STATUS_INSTALLED })
+ DISTRO_STATUS_INSTALLED
+ })
private @interface DistroStatus {}
/** The current distro status could not be determined. */
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index 222e9a0..2e44a63 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -129,7 +129,11 @@
*/
public static class Bucket {
/** @hide */
- @IntDef({STATE_ALL, STATE_DEFAULT, STATE_FOREGROUND})
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_ALL,
+ STATE_DEFAULT,
+ STATE_FOREGROUND
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface State {}
@@ -164,7 +168,11 @@
public static final int UID_TETHERING = TrafficStats.UID_TETHERING;
/** @hide */
- @IntDef({METERED_ALL, METERED_NO, METERED_YES})
+ @IntDef(prefix = { "METERED_" }, value = {
+ METERED_ALL,
+ METERED_NO,
+ METERED_YES
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Metered {}
@@ -187,7 +195,11 @@
public static final int METERED_YES = 0x2;
/** @hide */
- @IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES})
+ @IntDef(prefix = { "ROAMING_" }, value = {
+ ROAMING_ALL,
+ ROAMING_NO,
+ ROAMING_YES
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Roaming {}
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 8200414..f04e907 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -110,10 +110,9 @@
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
/** @hide */
- @IntDef(flag = true,
- value = {
- FLAG_IS_PACKAGE_INSTANT_APP,
- })
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_IS_PACKAGE_INSTANT_APP,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface EventFlags {}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 1fc45c9..edb6a74 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -151,7 +151,7 @@
public static final String REASON_PREDICTED = "predicted";
/** @hide */
- @IntDef(flag = false, value = {
+ @IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = {
STANDBY_BUCKET_EXEMPTED,
STANDBY_BUCKET_ACTIVE,
STANDBY_BUCKET_WORKING_SET,
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c7be0f3..3290d57 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -156,7 +156,7 @@
"android.bluetooth.adapter.extra.PREVIOUS_STATE";
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "STATE_" }, value = {
STATE_OFF,
STATE_TURNING_ON,
STATE_ON,
@@ -357,7 +357,11 @@
"android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
/** @hide */
- @IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE})
+ @IntDef(prefix = { "SCAN_" }, value = {
+ SCAN_MODE_NONE,
+ SCAN_MODE_CONNECTABLE,
+ SCAN_MODE_CONNECTABLE_DISCOVERABLE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface ScanMode {}
diff --git a/core/java/android/companion/DeviceFilter.java b/core/java/android/companion/DeviceFilter.java
index 9b4fdfd..10135a4 100644
--- a/core/java/android/companion/DeviceFilter.java
+++ b/core/java/android/companion/DeviceFilter.java
@@ -62,7 +62,11 @@
}
/** @hide */
- @IntDef({MEDIUM_TYPE_BLUETOOTH, MEDIUM_TYPE_BLUETOOTH_LE, MEDIUM_TYPE_WIFI})
+ @IntDef(prefix = { "MEDIUM_TYPE_" }, value = {
+ MEDIUM_TYPE_BLUETOOTH,
+ MEDIUM_TYPE_BLUETOOTH_LE,
+ MEDIUM_TYPE_WIFI
+ })
@Retention(RetentionPolicy.SOURCE)
@interface MediumType {}
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9ccc552..8d2e141 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -335,7 +335,7 @@
public static final String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
/** @hide */
- @IntDef(flag = false, value = {
+ @IntDef(flag = false, prefix = { "QUERY_SORT_DIRECTION_" }, value = {
QUERY_SORT_DIRECTION_ASCENDING,
QUERY_SORT_DIRECTION_DESCENDING
})
@@ -482,11 +482,10 @@
public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
/** @hide */
- @IntDef(flag = true,
- value = {
- NOTIFY_SYNC_TO_NETWORK,
- NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
- })
+ @IntDef(flag = true, prefix = { "NOTIFY_" }, value = {
+ NOTIFY_SYNC_TO_NETWORK,
+ NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface NotifyFlags {}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 458ba05..137c169 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -221,17 +221,16 @@
public static final int MODE_NO_LOCALIZED_COLLATORS = 0x0010;
/** @hide */
- @IntDef(flag = true,
- value = {
- BIND_AUTO_CREATE,
- BIND_DEBUG_UNBIND,
- BIND_NOT_FOREGROUND,
- BIND_ABOVE_CLIENT,
- BIND_ALLOW_OOM_MANAGEMENT,
- BIND_WAIVE_PRIORITY,
- BIND_IMPORTANT,
- BIND_ADJUST_WITH_ACTIVITY
- })
+ @IntDef(flag = true, prefix = { "BIND_" }, value = {
+ BIND_AUTO_CREATE,
+ BIND_DEBUG_UNBIND,
+ BIND_NOT_FOREGROUND,
+ BIND_ABOVE_CLIENT,
+ BIND_ALLOW_OOM_MANAGEMENT,
+ BIND_WAIVE_PRIORITY,
+ BIND_IMPORTANT,
+ BIND_ADJUST_WITH_ACTIVITY
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface BindServiceFlags {}
@@ -406,10 +405,9 @@
public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
/** @hide */
- @IntDef(flag = true,
- value = {
- RECEIVER_VISIBLE_TO_INSTANT_APPS
- })
+ @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE_" }, value = {
+ RECEIVER_VISIBLE_TO_INSTANT_APPS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface RegisterReceiverFlags {}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6fb1afd..e940769 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5690,11 +5690,14 @@
private static final int COPY_MODE_HISTORY = 2;
/** @hide */
- @IntDef(value = {COPY_MODE_ALL, COPY_MODE_FILTER, COPY_MODE_HISTORY})
+ @IntDef(prefix = { "COPY_MODE_" }, value = {
+ COPY_MODE_ALL,
+ COPY_MODE_FILTER,
+ COPY_MODE_HISTORY
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface CopyMode {}
-
/**
* Create an empty intent.
*/
@@ -8966,17 +8969,16 @@
}
/** @hide */
- @IntDef(flag = true,
- value = {
- FILL_IN_ACTION,
- FILL_IN_DATA,
- FILL_IN_CATEGORIES,
- FILL_IN_COMPONENT,
- FILL_IN_PACKAGE,
- FILL_IN_SOURCE_BOUNDS,
- FILL_IN_SELECTOR,
- FILL_IN_CLIP_DATA
- })
+ @IntDef(flag = true, prefix = { "FILL_IN_" }, value = {
+ FILL_IN_ACTION,
+ FILL_IN_DATA,
+ FILL_IN_CATEGORIES,
+ FILL_IN_COMPONENT,
+ FILL_IN_PACKAGE,
+ FILL_IN_SOURCE_BOUNDS,
+ FILL_IN_SELECTOR,
+ FILL_IN_CLIP_DATA
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface FillInFlags {}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index f8cdce6..1461711 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -262,10 +262,10 @@
public static final int COLOR_MODE_HDR = 2;
/** @hide */
- @IntDef({
- COLOR_MODE_DEFAULT,
- COLOR_MODE_WIDE_COLOR_GAMUT,
- COLOR_MODE_HDR,
+ @IntDef(prefix = { "COLOR_MODE_" }, value = {
+ COLOR_MODE_DEFAULT,
+ COLOR_MODE_WIDE_COLOR_GAMUT,
+ COLOR_MODE_HDR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ColorMode {}
@@ -492,7 +492,7 @@
public int flags;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "SCREEN_ORIENTATION_" }, value = {
SCREEN_ORIENTATION_UNSET,
SCREEN_ORIENTATION_UNSPECIFIED,
SCREEN_ORIENTATION_LANDSCAPE,
@@ -638,25 +638,24 @@
public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
/** @hide */
- @IntDef(flag = true,
- value = {
- CONFIG_MCC,
- CONFIG_MNC,
- CONFIG_LOCALE,
- CONFIG_TOUCHSCREEN,
- CONFIG_KEYBOARD,
- CONFIG_KEYBOARD_HIDDEN,
- CONFIG_NAVIGATION,
- CONFIG_ORIENTATION,
- CONFIG_SCREEN_LAYOUT,
- CONFIG_UI_MODE,
- CONFIG_SCREEN_SIZE,
- CONFIG_SMALLEST_SCREEN_SIZE,
- CONFIG_DENSITY,
- CONFIG_LAYOUT_DIRECTION,
- CONFIG_COLOR_MODE,
- CONFIG_FONT_SCALE,
- })
+ @IntDef(flag = true, prefix = { "CONFIG_" }, value = {
+ CONFIG_MCC,
+ CONFIG_MNC,
+ CONFIG_LOCALE,
+ CONFIG_TOUCHSCREEN,
+ CONFIG_KEYBOARD,
+ CONFIG_KEYBOARD_HIDDEN,
+ CONFIG_NAVIGATION,
+ CONFIG_ORIENTATION,
+ CONFIG_SCREEN_LAYOUT,
+ CONFIG_UI_MODE,
+ CONFIG_SCREEN_SIZE,
+ CONFIG_SMALLEST_SCREEN_SIZE,
+ CONFIG_DENSITY,
+ CONFIG_LAYOUT_DIRECTION,
+ CONFIG_COLOR_MODE,
+ CONFIG_FONT_SCALE,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Config {}
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index d09ba0b..b4a7eec 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -343,14 +343,13 @@
public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
/** @hide */
- @IntDef(flag = true,
- value = {
- FLAG_MATCH_DYNAMIC,
- FLAG_MATCH_PINNED,
- FLAG_MATCH_MANIFEST,
- FLAG_GET_KEY_FIELDS_ONLY,
- FLAG_MATCH_MANIFEST,
- })
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_MATCH_DYNAMIC,
+ FLAG_MATCH_PINNED,
+ FLAG_MATCH_MANIFEST,
+ FLAG_GET_KEY_FIELDS_ONLY,
+ FLAG_MATCH_MANIFEST,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface QueryFlags {}
@@ -1380,7 +1379,10 @@
public static final int REQUEST_TYPE_APPWIDGET = 2;
/** @hide */
- @IntDef(value = {REQUEST_TYPE_SHORTCUT})
+ @IntDef(prefix = { "REQUEST_TYPE_" }, value = {
+ REQUEST_TYPE_SHORTCUT,
+ REQUEST_TYPE_APPWIDGET
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface RequestType {}
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 2f1b256..33bc951 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -36,13 +36,11 @@
public final class SharedLibraryInfo implements Parcelable {
/** @hide */
- @IntDef(
- flag = true,
- value = {
- TYPE_BUILTIN,
- TYPE_DYNAMIC,
- TYPE_STATIC,
- })
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_BUILTIN,
+ TYPE_DYNAMIC,
+ TYPE_STATIC,
+ })
@Retention(RetentionPolicy.SOURCE)
@interface Type{}
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 9ff0775..8839cf9 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -109,8 +109,7 @@
public static final int FLAG_SHADOW = 1 << 12;
/** @hide */
- @IntDef(flag = true,
- value = {
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_DYNAMIC,
FLAG_PINNED,
FLAG_HAS_ICON_RES,
@@ -153,15 +152,14 @@
| CLONE_REMOVE_RES_NAMES;
/** @hide */
- @IntDef(flag = true,
- value = {
- CLONE_REMOVE_ICON,
- CLONE_REMOVE_INTENT,
- CLONE_REMOVE_NON_KEY_INFO,
- CLONE_REMOVE_RES_NAMES,
- CLONE_REMOVE_FOR_CREATOR,
- CLONE_REMOVE_FOR_LAUNCHER
- })
+ @IntDef(flag = true, prefix = { "CLONE_" }, value = {
+ CLONE_REMOVE_ICON,
+ CLONE_REMOVE_INTENT,
+ CLONE_REMOVE_NON_KEY_INFO,
+ CLONE_REMOVE_RES_NAMES,
+ CLONE_REMOVE_FOR_CREATOR,
+ CLONE_REMOVE_FOR_LAUNCHER
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface CloneFlags {}
@@ -212,7 +210,7 @@
public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
/** @hide */
- @IntDef(value = {
+ @IntDef(prefix = { "DISABLED_REASON_" }, value = {
DISABLED_REASON_NOT_DISABLED,
DISABLED_REASON_BY_APP,
DISABLED_REASON_APP_CHANGED,
@@ -220,7 +218,7 @@
DISABLED_REASON_BACKUP_NOT_SUPPORTED,
DISABLED_REASON_SIGNATURE_MISMATCH,
DISABLED_REASON_OTHER_RESTORE_ISSUE,
- })
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface DisabledReason{}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 26efda1..eb30979 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -781,25 +781,24 @@
public int seq;
/** @hide */
- @IntDef(flag = true,
- value = {
- NATIVE_CONFIG_MCC,
- NATIVE_CONFIG_MNC,
- NATIVE_CONFIG_LOCALE,
- NATIVE_CONFIG_TOUCHSCREEN,
- NATIVE_CONFIG_KEYBOARD,
- NATIVE_CONFIG_KEYBOARD_HIDDEN,
- NATIVE_CONFIG_NAVIGATION,
- NATIVE_CONFIG_ORIENTATION,
- NATIVE_CONFIG_DENSITY,
- NATIVE_CONFIG_SCREEN_SIZE,
- NATIVE_CONFIG_VERSION,
- NATIVE_CONFIG_SCREEN_LAYOUT,
- NATIVE_CONFIG_UI_MODE,
- NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
- NATIVE_CONFIG_LAYOUTDIR,
- NATIVE_CONFIG_COLOR_MODE,
- })
+ @IntDef(flag = true, prefix = { "NATIVE_CONFIG_" }, value = {
+ NATIVE_CONFIG_MCC,
+ NATIVE_CONFIG_MNC,
+ NATIVE_CONFIG_LOCALE,
+ NATIVE_CONFIG_TOUCHSCREEN,
+ NATIVE_CONFIG_KEYBOARD,
+ NATIVE_CONFIG_KEYBOARD_HIDDEN,
+ NATIVE_CONFIG_NAVIGATION,
+ NATIVE_CONFIG_ORIENTATION,
+ NATIVE_CONFIG_DENSITY,
+ NATIVE_CONFIG_SCREEN_SIZE,
+ NATIVE_CONFIG_VERSION,
+ NATIVE_CONFIG_SCREEN_LAYOUT,
+ NATIVE_CONFIG_UI_MODE,
+ NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
+ NATIVE_CONFIG_LAYOUTDIR,
+ NATIVE_CONFIG_COLOR_MODE,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface NativeConfig {}
diff --git a/core/java/android/content/res/GradientColor.java b/core/java/android/content/res/GradientColor.java
index e465961..35ad503 100644
--- a/core/java/android/content/res/GradientColor.java
+++ b/core/java/android/content/res/GradientColor.java
@@ -75,9 +75,14 @@
private static final boolean DBG_GRADIENT = false;
- @IntDef({TILE_MODE_CLAMP, TILE_MODE_REPEAT, TILE_MODE_MIRROR})
+ @IntDef(prefix = { "TILE_MODE_" }, value = {
+ TILE_MODE_CLAMP,
+ TILE_MODE_REPEAT,
+ TILE_MODE_MIRROR
+ })
@Retention(RetentionPolicy.SOURCE)
private @interface GradientTileMode {}
+
private static final int TILE_MODE_CLAMP = 0;
private static final int TILE_MODE_REPEAT = 1;
private static final int TILE_MODE_MIRROR = 2;
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index b111ad3..7866b52 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -42,7 +42,15 @@
public final class HardwareBuffer implements Parcelable, AutoCloseable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({RGBA_8888, RGBA_FP16, RGBA_1010102, RGBX_8888, RGB_888, RGB_565, BLOB})
+ @IntDef(prefix = { "RGB", "BLOB" }, value = {
+ RGBA_8888,
+ RGBA_FP16,
+ RGBA_1010102,
+ RGBX_8888,
+ RGB_888,
+ RGB_565,
+ BLOB
+ })
public @interface Format {
}
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 7c876cf..5ff627f 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -68,8 +68,15 @@
*
* @hide
*/
- @IntDef({TYPE_FRAME_BEGIN, TYPE_FRAME_END, TYPE_UNTRACKED_DELAY, TYPE_INTERNAL_TEMPERATURE,
- TYPE_VEC3_CALIBRATION, TYPE_SENSOR_PLACEMENT, TYPE_SAMPLING})
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_FRAME_BEGIN,
+ TYPE_FRAME_END,
+ TYPE_UNTRACKED_DELAY,
+ TYPE_INTERNAL_TEMPERATURE,
+ TYPE_VEC3_CALIBRATION,
+ TYPE_SENSOR_PLACEMENT,
+ TYPE_SAMPLING
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AdditionalInfoType {}
diff --git a/core/java/android/hardware/SensorDirectChannel.java b/core/java/android/hardware/SensorDirectChannel.java
index 36607c9..214d3ec 100644
--- a/core/java/android/hardware/SensorDirectChannel.java
+++ b/core/java/android/hardware/SensorDirectChannel.java
@@ -40,8 +40,12 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {TYPE_MEMORY_FILE, TYPE_HARDWARE_BUFFER})
- public @interface MemoryType {};
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_MEMORY_FILE,
+ TYPE_HARDWARE_BUFFER
+ })
+ public @interface MemoryType {}
+
/**
* Shared memory type ashmem, wrapped in MemoryFile object.
*
@@ -60,8 +64,13 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {RATE_STOP, RATE_NORMAL, RATE_FAST, RATE_VERY_FAST})
- public @interface RateLevel {};
+ @IntDef(flag = true, prefix = { "RATE_" }, value = {
+ RATE_STOP,
+ RATE_NORMAL,
+ RATE_FAST,
+ RATE_VERY_FAST
+ })
+ public @interface RateLevel {}
/**
* Sensor stopped (no event output).
diff --git a/core/java/android/hardware/camera2/CameraAccessException.java b/core/java/android/hardware/camera2/CameraAccessException.java
index f9b659c..d238797 100644
--- a/core/java/android/hardware/camera2/CameraAccessException.java
+++ b/core/java/android/hardware/camera2/CameraAccessException.java
@@ -16,7 +16,6 @@
package android.hardware.camera2;
-import android.annotation.NonNull;
import android.annotation.IntDef;
import android.util.AndroidException;
@@ -81,15 +80,16 @@
*/
public static final int CAMERA_DEPRECATED_HAL = 1000;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- {CAMERA_IN_USE,
- MAX_CAMERAS_IN_USE,
- CAMERA_DISABLED,
- CAMERA_DISCONNECTED,
- CAMERA_ERROR})
- public @interface AccessError {};
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "CAMERA_", "MAX_CAMERAS_IN_USE" }, value = {
+ CAMERA_IN_USE,
+ MAX_CAMERAS_IN_USE,
+ CAMERA_DISABLED,
+ CAMERA_DISCONNECTED,
+ CAMERA_ERROR
+ })
+ public @interface AccessError {}
// Make the eclipse warning about serializable exceptions go away
private static final long serialVersionUID = 5630338637471475675L; // randomly generated
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index c531a89..1de8882 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -188,7 +188,11 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SWITCH_STATE_UNKNOWN, SWITCH_STATE_OFF, SWITCH_STATE_ON})
+ @IntDef(prefix = { "SWITCH_STATE_" }, value = {
+ SWITCH_STATE_UNKNOWN,
+ SWITCH_STATE_OFF,
+ SWITCH_STATE_ON
+ })
public @interface SwitchState {}
/**
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index b808de3..2a66cbc 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -47,13 +47,15 @@
* Constants describing the type of a transaction through the Context Hub Service.
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "TYPE_" }, value = {
TYPE_LOAD_NANOAPP,
TYPE_UNLOAD_NANOAPP,
TYPE_ENABLE_NANOAPP,
TYPE_DISABLE_NANOAPP,
- TYPE_QUERY_NANOAPPS})
- public @interface Type {}
+ TYPE_QUERY_NANOAPPS
+ })
+ public @interface Type { }
+
public static final int TYPE_LOAD_NANOAPP = 0;
public static final int TYPE_UNLOAD_NANOAPP = 1;
public static final int TYPE_ENABLE_NANOAPP = 2;
@@ -64,7 +66,7 @@
* Constants describing the result of a transaction or request through the Context Hub Service.
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "TRANSACTION_" }, value = {
TRANSACTION_SUCCESS,
TRANSACTION_FAILED_UNKNOWN,
TRANSACTION_FAILED_BAD_PARAMS,
@@ -73,7 +75,8 @@
TRANSACTION_FAILED_AT_HUB,
TRANSACTION_FAILED_TIMEOUT,
TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE,
- TRANSACTION_FAILED_HAL_UNAVAILABLE})
+ TRANSACTION_FAILED_HAL_UNAVAILABLE
+ })
public @interface Result {}
public static final int TRANSACTION_SUCCESS = 0;
/**
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index aad202e..eae7d70 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -40,9 +40,11 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- DEVICE_TEMPERATURE_CPU, DEVICE_TEMPERATURE_GPU, DEVICE_TEMPERATURE_BATTERY,
- DEVICE_TEMPERATURE_SKIN
+ @IntDef(prefix = { "DEVICE_TEMPERATURE_" }, value = {
+ DEVICE_TEMPERATURE_CPU,
+ DEVICE_TEMPERATURE_GPU,
+ DEVICE_TEMPERATURE_BATTERY,
+ DEVICE_TEMPERATURE_SKIN
})
public @interface DeviceTemperatureType {}
@@ -50,9 +52,11 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- TEMPERATURE_CURRENT, TEMPERATURE_THROTTLING, TEMPERATURE_SHUTDOWN,
- TEMPERATURE_THROTTLING_BELOW_VR_MIN
+ @IntDef(prefix = { "TEMPERATURE_" }, value = {
+ TEMPERATURE_CURRENT,
+ TEMPERATURE_THROTTLING,
+ TEMPERATURE_SHUTDOWN,
+ TEMPERATURE_THROTTLING_BELOW_VR_MIN
})
public @interface TemperatureSource {}
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 624e28a..96e7a59 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -871,7 +871,11 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={EVENT_INPUT, EVENT_OUTPUT, EVENT_ERROR})
+ @IntDef(flag = true, prefix = { "EVENT_" }, value = {
+ EVENT_INPUT,
+ EVENT_OUTPUT,
+ EVENT_ERROR
+ })
public @interface Events {}
/**
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 01fe5bf..56c6391 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -466,7 +466,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "SHUTDOWN_REASON_" }, value = {
SHUTDOWN_REASON_UNKNOWN,
SHUTDOWN_REASON_SHUTDOWN,
SHUTDOWN_REASON_REBOOT,
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 61dd462..fb60bbb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -103,8 +103,12 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={RESTRICTION_NOT_SET, RESTRICTION_SOURCE_SYSTEM,
- RESTRICTION_SOURCE_DEVICE_OWNER, RESTRICTION_SOURCE_PROFILE_OWNER})
+ @IntDef(flag = true, prefix = { "RESTRICTION_" }, value = {
+ RESTRICTION_NOT_SET,
+ RESTRICTION_SOURCE_SYSTEM,
+ RESTRICTION_SOURCE_DEVICE_OWNER,
+ RESTRICTION_SOURCE_PROFILE_OWNER
+ })
@SystemApi
public @interface UserRestrictionSource {}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4796712..9833fe1 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1690,7 +1690,7 @@
public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
/** @hide */
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = {
FLAG_ALLOCATE_AGGRESSIVE,
FLAG_ALLOCATE_DEFY_ALL_RESERVED,
FLAG_ALLOCATE_DEFY_HALF_RESERVED,
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index ce5b11e..f0d9a0c 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -49,8 +49,9 @@
public final class PrintAttributes implements Parcelable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- COLOR_MODE_MONOCHROME, COLOR_MODE_COLOR
+ @IntDef(flag = true, prefix = { "COLOR_MODE_" }, value = {
+ COLOR_MODE_MONOCHROME,
+ COLOR_MODE_COLOR
})
@interface ColorMode {
}
@@ -64,8 +65,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, DUPLEX_MODE_SHORT_EDGE
+ @IntDef(flag = true, prefix = { "DUPLEX_MODE_" }, value = {
+ DUPLEX_MODE_NONE,
+ DUPLEX_MODE_LONG_EDGE,
+ DUPLEX_MODE_SHORT_EDGE
})
@interface DuplexMode {
}
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index 6143404..55c902e 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -83,11 +83,14 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_DOCUMENT, CONTENT_TYPE_PHOTO
+ @IntDef(prefix = { "CONTENT_TYPE_" }, value = {
+ CONTENT_TYPE_UNKNOWN,
+ CONTENT_TYPE_DOCUMENT,
+ CONTENT_TYPE_PHOTO
})
public @interface ContentType {
}
+
/**
* Content type: unknown.
*/
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 94686a8..85fdd64 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -45,9 +45,14 @@
public final class PrintJobInfo implements Parcelable {
/** @hide */
- @IntDef({
- STATE_CREATED, STATE_QUEUED, STATE_STARTED, STATE_BLOCKED, STATE_COMPLETED,
- STATE_FAILED, STATE_CANCELED
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_CREATED,
+ STATE_QUEUED,
+ STATE_STARTED,
+ STATE_BLOCKED,
+ STATE_COMPLETED,
+ STATE_FAILED,
+ STATE_CANCELED
})
@Retention(RetentionPolicy.SOURCE)
public @interface State {
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index 88feab7..e79cc65 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -53,12 +53,15 @@
public final class PrinterInfo implements Parcelable {
/** @hide */
- @IntDef({
- STATUS_IDLE, STATUS_BUSY, STATUS_UNAVAILABLE
+ @IntDef(prefix = { "STATUS_" }, value = {
+ STATUS_IDLE,
+ STATUS_BUSY,
+ STATUS_UNAVAILABLE
})
@Retention(RetentionPolicy.SOURCE)
public @interface Status {
}
+
/** Printer status: the printer is idle and ready to print. */
public static final int STATUS_IDLE = PrinterInfoProto.STATUS_IDLE;
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index d8540ff..a1d1c57 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -283,7 +283,11 @@
public static final int STATUS_REJECTED = 3;
/** @hide */
- @IntDef({STATUS_OK, STATUS_WRONG_CERTIFICATES, STATUS_UNEXPECTED_DATA_PROVIDED})
+ @IntDef(prefix = { "STATUS_" }, value = {
+ STATUS_OK,
+ STATUS_WRONG_CERTIFICATES,
+ STATUS_UNEXPECTED_DATA_PROVIDED
+ })
@Retention(RetentionPolicy.SOURCE)
@interface FontResultStatus {}
@@ -438,9 +442,13 @@
public static final int FAIL_REASON_MALFORMED_QUERY = Columns.RESULT_CODE_MALFORMED_QUERY;
/** @hide */
- @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
- FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
- FAIL_REASON_MALFORMED_QUERY })
+ @IntDef(prefix = { "FAIL_" }, value = {
+ FAIL_REASON_PROVIDER_NOT_FOUND,
+ FAIL_REASON_FONT_LOAD_ERROR,
+ FAIL_REASON_FONT_NOT_FOUND,
+ FAIL_REASON_FONT_UNAVAILABLE,
+ FAIL_REASON_MALFORMED_QUERY
+ })
@Retention(RetentionPolicy.SOURCE)
@interface FontRequestFailReason {}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 94ac052..4ecbdf5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1689,7 +1689,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
+ @IntDef(prefix = { "RESET_MODE_" }, value = {
RESET_MODE_PACKAGE_DEFAULTS,
RESET_MODE_UNTRUSTED_DEFAULTS,
RESET_MODE_UNTRUSTED_CHANGES,
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index facad2d..a527f16 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -226,12 +226,13 @@
public static final int TYPE_CONTEXT_COMMITTED = 4;
/** @hide */
- @IntDef(
- value = {TYPE_DATASET_SELECTED,
- TYPE_DATASET_AUTHENTICATION_SELECTED,
- TYPE_AUTHENTICATION_SELECTED,
- TYPE_SAVE_SHOWN,
- TYPE_CONTEXT_COMMITTED})
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_DATASET_SELECTED,
+ TYPE_DATASET_AUTHENTICATION_SELECTED,
+ TYPE_AUTHENTICATION_SELECTED,
+ TYPE_SAVE_SHOWN,
+ TYPE_CONTEXT_COMMITTED
+ })
@Retention(RetentionPolicy.SOURCE)
@interface EventIds{}
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index ddc92f6..33619ac 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -69,9 +69,9 @@
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
/** @hide */
- @IntDef(
- flag = true,
- value = {FLAG_MANUAL_REQUEST})
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_MANUAL_REQUEST
+ })
@Retention(RetentionPolicy.SOURCE)
@interface RequestFlags{}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 04db698..014d3e8 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -63,7 +63,7 @@
public static final int FLAG_DISABLE_ACTIVITY_ONLY = 0x2;
/** @hide */
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_TRACK_CONTEXT_COMMITED,
FLAG_DISABLE_ACTIVITY_ONLY
})
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 0b50f07..a5a6177 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -198,23 +198,22 @@
public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1;
/** @hide */
- @IntDef(
- value = {
- NEGATIVE_BUTTON_STYLE_CANCEL,
- NEGATIVE_BUTTON_STYLE_REJECT})
+ @IntDef(prefix = { "NEGATIVE_BUTTON_STYLE_" }, value = {
+ NEGATIVE_BUTTON_STYLE_CANCEL,
+ NEGATIVE_BUTTON_STYLE_REJECT
+ })
@Retention(RetentionPolicy.SOURCE)
@interface NegativeButtonStyle{}
/** @hide */
- @IntDef(
- flag = true,
- value = {
- SAVE_DATA_TYPE_GENERIC,
- SAVE_DATA_TYPE_PASSWORD,
- SAVE_DATA_TYPE_ADDRESS,
- SAVE_DATA_TYPE_CREDIT_CARD,
- SAVE_DATA_TYPE_USERNAME,
- SAVE_DATA_TYPE_EMAIL_ADDRESS})
+ @IntDef(flag = true, prefix = { "SAVE_DATA_TYPE_" }, value = {
+ SAVE_DATA_TYPE_GENERIC,
+ SAVE_DATA_TYPE_PASSWORD,
+ SAVE_DATA_TYPE_ADDRESS,
+ SAVE_DATA_TYPE_CREDIT_CARD,
+ SAVE_DATA_TYPE_USERNAME,
+ SAVE_DATA_TYPE_EMAIL_ADDRESS
+ })
@Retention(RetentionPolicy.SOURCE)
@interface SaveDataType{}
@@ -235,9 +234,10 @@
public static final int FLAG_DONT_SAVE_ON_FINISH = 0x2;
/** @hide */
- @IntDef(
- flag = true,
- value = {FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE, FLAG_DONT_SAVE_ON_FINISH})
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE,
+ FLAG_DONT_SAVE_ON_FINISH
+ })
@Retention(RetentionPolicy.SOURCE)
@interface SaveInfoFlags{}
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 447afe6..2a352ad 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -39,7 +39,12 @@
public static final String SCHEME = "condition";
/** @hide */
- @IntDef({STATE_FALSE, STATE_TRUE, STATE_TRUE, STATE_ERROR})
+ @IntDef(prefix = { "STATE_" }, value = {
+ STATE_FALSE,
+ STATE_TRUE,
+ STATE_UNKNOWN,
+ STATE_ERROR
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface State {}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index dac663e7..18d4a1e 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -229,8 +229,11 @@
/** @hide */
- @IntDef({NOTIFICATION_CHANNEL_OR_GROUP_ADDED, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED,
- NOTIFICATION_CHANNEL_OR_GROUP_DELETED})
+ @IntDef(prefix = { "NOTIFICATION_CHANNEL_OR_GROUP_" }, value = {
+ NOTIFICATION_CHANNEL_OR_GROUP_ADDED,
+ NOTIFICATION_CHANNEL_OR_GROUP_UPDATED,
+ NOTIFICATION_CHANNEL_OR_GROUP_DELETED
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface ChannelOrGroupModificationTypes {}
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 9332a5b..0bf68b7 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -65,10 +65,10 @@
*/
public static final int FLASH_LOCK_LOCKED = 1;
- @IntDef({
- FLASH_LOCK_UNKNOWN,
- FLASH_LOCK_LOCKED,
- FLASH_LOCK_UNLOCKED,
+ @IntDef(prefix = { "FLASH_LOCK_" }, value = {
+ FLASH_LOCK_UNKNOWN,
+ FLASH_LOCK_LOCKED,
+ FLASH_LOCK_UNLOCKED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface FlashLockState {}
diff --git a/core/java/android/service/settings/suggestions/Suggestion.java b/core/java/android/service/settings/suggestions/Suggestion.java
index cfeb7fc..11e1e67 100644
--- a/core/java/android/service/settings/suggestions/Suggestion.java
+++ b/core/java/android/service/settings/suggestions/Suggestion.java
@@ -38,7 +38,7 @@
/**
* @hide
*/
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_HAS_BUTTON,
})
@Retention(RetentionPolicy.SOURCE)
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 5ef934e..4bade9f 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -114,11 +114,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- FLAG_GRANT_TRUST_INITIATED_BY_USER,
- FLAG_GRANT_TRUST_DISMISS_KEYGUARD,
- })
+ @IntDef(flag = true, prefix = { "FLAG_GRANT_TRUST_" }, value = {
+ FLAG_GRANT_TRUST_INITIATED_BY_USER,
+ FLAG_GRANT_TRUST_DISMISS_KEYGUARD,
+ })
public @interface GrantTrustFlags {}
@@ -138,11 +137,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- TOKEN_STATE_ACTIVE,
- TOKEN_STATE_INACTIVE,
- })
+ @IntDef(flag = true, prefix = { "TOKEN_STATE_" }, value = {
+ TOKEN_STATE_ACTIVE,
+ TOKEN_STATE_INACTIVE,
+ })
public @interface TokenState {}
private static final int MSG_UNLOCK_ATTEMPT = 1;
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 9464a87..76d89ef 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -87,11 +87,11 @@
// Keyphrase management actions. Used in getManageIntent() ----//
@Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- MANAGE_ACTION_ENROLL,
- MANAGE_ACTION_RE_ENROLL,
- MANAGE_ACTION_UN_ENROLL
- })
+ @IntDef(prefix = { "MANAGE_ACTION_" }, value = {
+ MANAGE_ACTION_ENROLL,
+ MANAGE_ACTION_RE_ENROLL,
+ MANAGE_ACTION_UN_ENROLL
+ })
private @interface ManageActions {}
/**
@@ -116,12 +116,11 @@
//-- Flags for startRecognition ----//
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- RECOGNITION_FLAG_NONE,
- RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO,
- RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
- })
+ @IntDef(flag = true, prefix = { "RECOGNITION_FLAG_" }, value = {
+ RECOGNITION_FLAG_NONE,
+ RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO,
+ RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
+ })
public @interface RecognitionFlags {}
/**
@@ -150,11 +149,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- RECOGNITION_MODE_VOICE_TRIGGER,
- RECOGNITION_MODE_USER_IDENTIFICATION,
- })
+ @IntDef(flag = true, prefix = { "RECOGNITION_MODE_" }, value = {
+ RECOGNITION_MODE_VOICE_TRIGGER,
+ RECOGNITION_MODE_USER_IDENTIFICATION,
+ })
public @interface RecognitionModes {}
/**
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 763ea2c..01562b3 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -80,8 +80,15 @@
public static final int STOPPED = -2;
/** @hide */
- @IntDef({ERROR_SYNTHESIS, ERROR_SERVICE, ERROR_OUTPUT, ERROR_NETWORK, ERROR_NETWORK_TIMEOUT,
- ERROR_INVALID_REQUEST, ERROR_NOT_INSTALLED_YET})
+ @IntDef(prefix = { "ERROR_" }, value = {
+ ERROR_SYNTHESIS,
+ ERROR_SERVICE,
+ ERROR_OUTPUT,
+ ERROR_NETWORK,
+ ERROR_NETWORK_TIMEOUT,
+ ERROR_INVALID_REQUEST,
+ ERROR_NOT_INSTALLED_YET
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Error {}
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 4654e83..7386e3e 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -179,7 +179,11 @@
/** @hide */
@Retention(SOURCE)
- @IntDef({VARIANT_DEFAULT, VARIANT_COMPACT, VARIANT_ELEGANT})
+ @IntDef(prefix = { "VARIANT_" }, value = {
+ VARIANT_DEFAULT,
+ VARIANT_COMPACT,
+ VARIANT_ELEGANT
+ })
public @interface Variant {}
/**
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 2a693a1..bf4b6ac 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -48,7 +48,11 @@
*/
public abstract class Layout {
/** @hide */
- @IntDef({BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED})
+ @IntDef(prefix = { "BREAK_STRATEGY_" }, value = {
+ BREAK_STRATEGY_SIMPLE,
+ BREAK_STRATEGY_HIGH_QUALITY,
+ BREAK_STRATEGY_BALANCED
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface BreakStrategy {}
@@ -73,8 +77,11 @@
public static final int BREAK_STRATEGY_BALANCED = 2;
/** @hide */
- @IntDef({HYPHENATION_FREQUENCY_NORMAL, HYPHENATION_FREQUENCY_FULL,
- HYPHENATION_FREQUENCY_NONE})
+ @IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = {
+ HYPHENATION_FREQUENCY_NORMAL,
+ HYPHENATION_FREQUENCY_FULL,
+ HYPHENATION_FREQUENCY_NONE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface HyphenationFrequency {}
@@ -105,7 +112,10 @@
ArrayUtils.emptyArray(ParagraphStyle.class);
/** @hide */
- @IntDef({JUSTIFICATION_MODE_NONE, JUSTIFICATION_MODE_INTER_WORD})
+ @IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = {
+ JUSTIFICATION_MODE_NONE,
+ JUSTIFICATION_MODE_INTER_WORD
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface JustificationMode {}
@@ -2267,7 +2277,10 @@
private int mJustificationMode;
/** @hide */
- @IntDef({DIR_LEFT_TO_RIGHT, DIR_RIGHT_TO_LEFT})
+ @IntDef(prefix = { "DIR_" }, value = {
+ DIR_LEFT_TO_RIGHT,
+ DIR_RIGHT_TO_LEFT
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Direction {}
@@ -2308,7 +2321,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({TEXT_SELECTION_LAYOUT_RIGHT_TO_LEFT, TEXT_SELECTION_LAYOUT_LEFT_TO_RIGHT})
+ @IntDef(prefix = { "TEXT_SELECTION_LAYOUT_" }, value = {
+ TEXT_SELECTION_LAYOUT_RIGHT_TO_LEFT,
+ TEXT_SELECTION_LAYOUT_LEFT_TO_RIGHT
+ })
public @interface TextSelectionLayout {}
/** @hide */
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 5b851ca..f0838a1 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -52,7 +52,10 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={MODE_IN, MODE_OUT})
+ @IntDef(flag = true, prefix = { "MODE_" }, value = {
+ MODE_IN,
+ MODE_OUT
+ })
@interface VisibilityMode {}
/**
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 9673be0..5bd7446 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1323,10 +1323,10 @@
public static final int HDR_TYPE_HLG = 3;
/** @hide */
- @IntDef({
- HDR_TYPE_DOLBY_VISION,
- HDR_TYPE_HDR10,
- HDR_TYPE_HLG,
+ @IntDef(prefix = { "HDR_TYPE_" }, value = {
+ HDR_TYPE_DOLBY_VISION,
+ HDR_TYPE_HDR10,
+ HDR_TYPE_HLG,
})
@Retention(RetentionPolicy.SOURCE)
public @interface HdrType {}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ddced6c..a417a4a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -121,8 +121,12 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
- SCALING_MODE_SCALE_CROP, SCALING_MODE_NO_SCALE_CROP})
+ @IntDef(prefix = { "SCALING_MODE_" }, value = {
+ SCALING_MODE_FREEZE,
+ SCALING_MODE_SCALE_TO_WINDOW,
+ SCALING_MODE_SCALE_CROP,
+ SCALING_MODE_NO_SCALE_CROP
+ })
public @interface ScalingMode {}
// From system/window.h
/** @hide */
@@ -135,7 +139,12 @@
public static final int SCALING_MODE_NO_SCALE_CROP = 3;
/** @hide */
- @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
+ @IntDef(prefix = { "ROTATION_" }, value = {
+ ROTATION_0,
+ ROTATION_90,
+ ROTATION_180,
+ ROTATION_270
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Rotation {}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 357b8d9..268e460 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -30,6 +30,7 @@
import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.IBinder;
@@ -37,8 +38,12 @@
import android.os.Parcelable;
import android.os.Process;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
+
+import com.android.internal.annotations.GuardedBy;
+
import dalvik.system.CloseGuard;
import libcore.util.NativeAllocationRegistry;
@@ -153,6 +158,13 @@
private final String mName;
long mNativeObject; // package visibility only for Surface.java access
+ // TODO: Move this to native.
+ private final Object mSizeLock = new Object();
+ @GuardedBy("mSizeLock")
+ private int mWidth;
+ @GuardedBy("mSizeLock")
+ private int mHeight;
+
static Transaction sGlobalTransaction;
static long sTransactionNestCount = 0;
@@ -567,6 +579,8 @@
}
mName = name;
+ mWidth = w;
+ mHeight = h;
mNativeObject = nativeCreate(session, name, w, h, format, flags,
parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
if (mNativeObject == 0) {
@@ -582,6 +596,8 @@
// event logging.
public SurfaceControl(SurfaceControl other) {
mName = other.mName;
+ mWidth = other.mWidth;
+ mHeight = other.mHeight;
mNativeObject = other.mNativeObject;
other.mCloseGuard.close();
other.mNativeObject = 0;
@@ -590,6 +606,8 @@
private SurfaceControl(Parcel in) {
mName = in.readString();
+ mWidth = in.readInt();
+ mHeight = in.readInt();
mNativeObject = nativeReadFromParcel(in);
if (mNativeObject == 0) {
throw new IllegalArgumentException("Couldn't read SurfaceControl from parcel=" + in);
@@ -605,6 +623,8 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName);
+ dest.writeInt(mWidth);
+ dest.writeInt(mHeight);
nativeWriteToParcel(mNativeObject, dest);
}
@@ -922,6 +942,18 @@
}
}
+ public int getWidth() {
+ synchronized (mSizeLock) {
+ return mWidth;
+ }
+ }
+
+ public int getHeight() {
+ synchronized (mSizeLock) {
+ return mHeight;
+ }
+ }
+
@Override
public String toString() {
return "Surface(name=" + mName + ")/@0x" +
@@ -1282,6 +1314,7 @@
nativeGetNativeTransactionFinalizer(), 512);
private long mNativeObject;
+ private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>();
Runnable mFreeNativeResources;
public Transaction() {
@@ -1312,9 +1345,22 @@
* Jankier version of apply. Avoid use (b/28068298).
*/
public void apply(boolean sync) {
+ applyResizedSurfaces();
nativeApplyTransaction(mNativeObject, sync);
}
+ private void applyResizedSurfaces() {
+ for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) {
+ final Point size = mResizedSurfaces.valueAt(i);
+ final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i);
+ synchronized (surfaceControl.mSizeLock) {
+ surfaceControl.mWidth = size.x;
+ surfaceControl.mHeight = size.y;
+ }
+ }
+ mResizedSurfaces.clear();
+ }
+
public Transaction show(SurfaceControl sc) {
sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
@@ -1335,6 +1381,7 @@
public Transaction setSize(SurfaceControl sc, int w, int h) {
sc.checkNotReleased();
+ mResizedSurfaces.put(sc, new Point(w, h));
nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
return this;
}
@@ -1567,6 +1614,8 @@
* other transaction as if it had been applied.
*/
public Transaction merge(Transaction other) {
+ mResizedSurfaces.putAll(other.mResizedSurfaces);
+ other.mResizedSurfaces.clear();
nativeMergeTransaction(mNativeObject, other.mNativeObject);
return this;
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 0a69772..6a8f8b1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -344,8 +344,10 @@
private static final int FLAG_DUMP_FRAMESTATS = 1 << 0;
private static final int FLAG_DUMP_RESET = 1 << 1;
- @IntDef(flag = true, value = {
- FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET })
+ @IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = {
+ FLAG_DUMP_FRAMESTATS,
+ FLAG_DUMP_RESET
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface DumpFlags {}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 623759e..ab5372a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1178,7 +1178,7 @@
private AutofillId mAutofillId;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = {
AUTOFILL_TYPE_NONE,
AUTOFILL_TYPE_TEXT,
AUTOFILL_TYPE_TOGGLE,
@@ -1249,7 +1249,7 @@
public static final int AUTOFILL_TYPE_DATE = 4;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = {
IMPORTANT_FOR_AUTOFILL_AUTO,
IMPORTANT_FOR_AUTOFILL_YES,
IMPORTANT_FOR_AUTOFILL_NO,
@@ -1300,9 +1300,9 @@
public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8;
/** @hide */
- @IntDef(
- flag = true,
- value = {AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS})
+ @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = {
+ AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AutofillFlags {}
@@ -1452,7 +1452,11 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO})
+ @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = {
+ DRAWING_CACHE_QUALITY_LOW,
+ DRAWING_CACHE_QUALITY_HIGH,
+ DRAWING_CACHE_QUALITY_AUTO
+ })
public @interface DrawingCacheQuality {}
/**
@@ -1551,13 +1555,12 @@
*/
static final int CONTEXT_CLICKABLE = 0x00800000;
-
/** @hide */
- @IntDef({
- SCROLLBARS_INSIDE_OVERLAY,
- SCROLLBARS_INSIDE_INSET,
- SCROLLBARS_OUTSIDE_OVERLAY,
- SCROLLBARS_OUTSIDE_INSET
+ @IntDef(prefix = { "SCROLLBARS_" }, value = {
+ SCROLLBARS_INSIDE_OVERLAY,
+ SCROLLBARS_INSIDE_INSET,
+ SCROLLBARS_OUTSIDE_OVERLAY,
+ SCROLLBARS_OUTSIDE_INSET
})
@Retention(RetentionPolicy.SOURCE)
public @interface ScrollBarStyle {}
@@ -1651,11 +1654,10 @@
static final int TOOLTIP = 0x40000000;
/** @hide */
- @IntDef(flag = true,
- value = {
- FOCUSABLES_ALL,
- FOCUSABLES_TOUCH_MODE
- })
+ @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = {
+ FOCUSABLES_ALL,
+ FOCUSABLES_TOUCH_MODE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface FocusableMode {}
@@ -1672,7 +1674,7 @@
public static final int FOCUSABLES_TOUCH_MODE = 0x00000001;
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "FOCUS_" }, value = {
FOCUS_BACKWARD,
FOCUS_FORWARD,
FOCUS_LEFT,
@@ -1684,7 +1686,7 @@
public @interface FocusDirection {}
/** @hide */
- @IntDef({
+ @IntDef(prefix = { "FOCUS_" }, value = {
FOCUS_LEFT,
FOCUS_UP,
FOCUS_RIGHT,
@@ -2426,20 +2428,20 @@
static final int PFLAG2_DRAG_HOVERED = 0x00000002;
/** @hide */
- @IntDef({
- LAYOUT_DIRECTION_LTR,
- LAYOUT_DIRECTION_RTL,
- LAYOUT_DIRECTION_INHERIT,
- LAYOUT_DIRECTION_LOCALE
+ @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = {
+ LAYOUT_DIRECTION_LTR,
+ LAYOUT_DIRECTION_RTL,
+ LAYOUT_DIRECTION_INHERIT,
+ LAYOUT_DIRECTION_LOCALE
})
@Retention(RetentionPolicy.SOURCE)
// Not called LayoutDirection to avoid conflict with android.util.LayoutDirection
public @interface LayoutDir {}
/** @hide */
- @IntDef({
- LAYOUT_DIRECTION_LTR,
- LAYOUT_DIRECTION_RTL
+ @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = {
+ LAYOUT_DIRECTION_LTR,
+ LAYOUT_DIRECTION_RTL
})
@Retention(RetentionPolicy.SOURCE)
public @interface ResolvedLayoutDir {}
@@ -2645,14 +2647,14 @@
TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
/** @hide */
- @IntDef({
- TEXT_ALIGNMENT_INHERIT,
- TEXT_ALIGNMENT_GRAVITY,
- TEXT_ALIGNMENT_CENTER,
- TEXT_ALIGNMENT_TEXT_START,
- TEXT_ALIGNMENT_TEXT_END,
- TEXT_ALIGNMENT_VIEW_START,
- TEXT_ALIGNMENT_VIEW_END
+ @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = {
+ TEXT_ALIGNMENT_INHERIT,
+ TEXT_ALIGNMENT_GRAVITY,
+ TEXT_ALIGNMENT_CENTER,
+ TEXT_ALIGNMENT_TEXT_START,
+ TEXT_ALIGNMENT_TEXT_END,
+ TEXT_ALIGNMENT_VIEW_START,
+ TEXT_ALIGNMENT_VIEW_END
})
@Retention(RetentionPolicy.SOURCE)
public @interface TextAlignment {}
@@ -3049,15 +3051,14 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- value = {
- SCROLL_INDICATOR_TOP,
- SCROLL_INDICATOR_BOTTOM,
- SCROLL_INDICATOR_LEFT,
- SCROLL_INDICATOR_RIGHT,
- SCROLL_INDICATOR_START,
- SCROLL_INDICATOR_END,
- })
+ @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = {
+ SCROLL_INDICATOR_TOP,
+ SCROLL_INDICATOR_BOTTOM,
+ SCROLL_INDICATOR_LEFT,
+ SCROLL_INDICATOR_RIGHT,
+ SCROLL_INDICATOR_START,
+ SCROLL_INDICATOR_END,
+ })
public @interface ScrollIndicators {}
/**
@@ -3683,8 +3684,10 @@
| SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
/** @hide */
- @IntDef(flag = true,
- value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION })
+ @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = {
+ FIND_VIEWS_WITH_TEXT,
+ FIND_VIEWS_WITH_CONTENT_DESCRIPTION
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface FindViewFlags {}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index ce3022e..012e864 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1746,7 +1746,7 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
+ @IntDef(flag = true, prefix = { "SOFT_INPUT_" }, value = {
SOFT_INPUT_STATE_UNSPECIFIED,
SOFT_INPUT_STATE_UNCHANGED,
SOFT_INPUT_STATE_HIDDEN,
diff --git a/core/java/android/view/accessibility/AccessibilityRequestPreparer.java b/core/java/android/view/accessibility/AccessibilityRequestPreparer.java
index 889feb9..25f830a 100644
--- a/core/java/android/view/accessibility/AccessibilityRequestPreparer.java
+++ b/core/java/android/view/accessibility/AccessibilityRequestPreparer.java
@@ -44,10 +44,9 @@
public static final int REQUEST_TYPE_EXTRA_DATA = 0x00000001;
/** @hide */
- @IntDef(flag = true,
- value = {
- REQUEST_TYPE_EXTRA_DATA
- })
+ @IntDef(flag = true, prefix = { "REQUEST_TYPE_" }, value = {
+ REQUEST_TYPE_EXTRA_DATA
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface RequestTypes {}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 419aeb3..6d84aa0 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1987,7 +1987,11 @@
public abstract static class AutofillCallback {
/** @hide */
- @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN, EVENT_INPUT_UNAVAILABLE})
+ @IntDef(prefix = { "EVENT_INPUT_" }, value = {
+ EVENT_INPUT_SHOWN,
+ EVENT_INPUT_HIDDEN,
+ EVENT_INPUT_UNAVAILABLE
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AutofillEventType {}
diff --git a/core/java/android/webkit/TracingConfig.java b/core/java/android/webkit/TracingConfig.java
new file mode 100644
index 0000000..75e2bf7
--- /dev/null
+++ b/core/java/android/webkit/TracingConfig.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2017 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 android.webkit;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Holds tracing configuration information and predefined settings.
+ */
+public class TracingConfig {
+
+ private final String mCustomCategoryPattern;
+ private final @PresetCategories int mPresetCategories;
+ private @TracingMode int mTracingMode;
+
+ /** @hide */
+ @IntDef({CATEGORIES_NONE, CATEGORIES_WEB_DEVELOPER, CATEGORIES_INPUT_LATENCY,
+ CATEGORIES_RENDERING, CATEGORIES_JAVASCRIPT_AND_RENDERING, CATEGORIES_FRAME_VIEWER})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PresetCategories {}
+
+ /**
+ * Indicates that there are no preset categories.
+ */
+ public static final int CATEGORIES_NONE = -1;
+
+ /**
+ * Predefined categories typically useful for web developers.
+ * Typically includes blink, compositor, renderer.scheduler and v8 categories.
+ */
+ public static final int CATEGORIES_WEB_DEVELOPER = 0;
+
+ /**
+ * Predefined categories for analyzing input latency issues.
+ * Typically includes input, renderer.scheduler categories.
+ */
+ public static final int CATEGORIES_INPUT_LATENCY = 1;
+
+ /**
+ * Predefined categories for analyzing rendering issues.
+ * Typically includes blink, compositor and gpu categories.
+ */
+ public static final int CATEGORIES_RENDERING = 2;
+
+ /**
+ * Predefined categories for analyzing javascript and rendering issues.
+ * Typically includes blink, compositor, gpu, renderer.schduler and v8 categories.
+ */
+ public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3;
+
+ /**
+ * Predefined categories for studying difficult rendering performance problems.
+ * Typically includes blink, compositor, gpu, renderer.scheduler, v8 and
+ * some other compositor categories which are disabled by default.
+ */
+ public static final int CATEGORIES_FRAME_VIEWER = 4;
+
+ /** @hide */
+ @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY, RECORD_UNTIL_FULL_LARGE_BUFFER,
+ RECORD_TO_CONSOLE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TracingMode {}
+
+ /**
+ * Record trace events until the internal tracing buffer is full. Default tracing mode.
+ * Typically the buffer memory usage is between {@link #RECORD_CONTINUOUSLY} and the
+ * {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}. Depending on the implementation typically allows
+ * up to 256k events to be stored.
+ */
+ public static final int RECORD_UNTIL_FULL = 0;
+
+ /**
+ * Record trace events continuously using an internal ring buffer. Overwrites
+ * old events if they exceed buffer capacity. Uses less memory than both
+ * {@link #RECORD_UNTIL_FULL} and {@link #RECORD_UNTIL_FULL_LARGE_BUFFER} modes.
+ * Depending on the implementation typically allows up to 64k events to be stored.
+ */
+ public static final int RECORD_CONTINUOUSLY = 1;
+
+ /**
+ * Record trace events using a larger internal tracing buffer until it is full.
+ * Uses more memory than the other modes and may not be suitable on devices
+ * with smaller RAM. Depending on the implementation typically allows up to
+ * 512 million events to be stored.
+ */
+ public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2;
+
+ /**
+ * Record trace events to console (logcat). The events are discarded and nothing
+ * is sent back to the caller. Uses the least memory as compared to the other modes.
+ */
+ public static final int RECORD_TO_CONSOLE = 3;
+
+ /**
+ * Create config with the preset categories.
+ * <p>
+ * Example:
+ * TracingConfig(CATEGORIES_WEB_DEVELOPER) -- records trace events from the "web developer"
+ * preset categories.
+ *
+ * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
+ * {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
+ * {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
+ * {@link #CATEGORIES_FRAME_VIEWER}.
+ *
+ * Note: for specifying custom categories without presets use
+ * {@link #TracingConfig(int, String, int)}.
+ *
+ */
+ public TracingConfig(@PresetCategories int presetCategories) {
+ this(presetCategories, "", RECORD_UNTIL_FULL);
+ }
+
+ /**
+ * Create a configuration with both preset categories and custom categories.
+ * Also allows to specify the tracing mode.
+ *
+ * Note that the categories are defined by the currently-in-use version of WebView. They live
+ * in chromium code and are not part of the Android API. See
+ * See <a href="https://www.chromium.org/developers/how-tos/trace-event-profiling-tool">
+ * chromium documentation on tracing</a> for more details.
+ *
+ * <p>
+ * Examples:
+ *
+ * Preset category with a specified trace mode:
+ * TracingConfig(CATEGORIES_WEB_DEVELOPER, "", RECORD_UNTIL_FULL_LARGE_BUFFER);
+ * Custom categories:
+ * TracingConfig(CATEGORIES_NONE, "browser", RECORD_UNTIL_FULL)
+ * -- records only the trace events from the "browser" category.
+ * TraceConfig(CATEGORIES_NONE, "-input,-gpu", RECORD_UNTIL_FULL)
+ * -- records all trace events excluding the events from the "input" and 'gpu' categories.
+ * TracingConfig(CATEGORIES_NONE, "blink*,devtools*", RECORD_UNTIL_FULL)
+ * -- records only the trace events matching the "blink*" and "devtools*" patterns
+ * (e.g. "blink_gc" and "devtools.timeline" categories).
+ *
+ * Combination of preset and additional custom categories:
+ * TracingConfig(CATEGORIES_WEB_DEVELOPER, "memory-infra", RECORD_CONTINUOUSLY)
+ * -- records events from the "web developer" categories and events from the "memory-infra"
+ * category to understand where memory is being used.
+ *
+ * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
+ * {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
+ * {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
+ * {@link #CATEGORIES_FRAME_VIEWER}.
+ * @param customCategories a comma-delimited list of category wildcards. A category can
+ * have an optional '-' prefix to make it an excluded category.
+ * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL},
+ * {@link #RECORD_CONTINUOUSLY}, {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}
+ * or {@link #RECORD_TO_CONSOLE}.
+ */
+ public TracingConfig(@PresetCategories int presetCategories,
+ @NonNull String customCategories, @TracingMode int tracingMode) {
+ mPresetCategories = presetCategories;
+ mCustomCategoryPattern = customCategories;
+ mTracingMode = RECORD_UNTIL_FULL;
+ }
+
+ /**
+ * Returns the custom category pattern for this configuration.
+ *
+ * @return empty string if no custom category pattern is specified.
+ */
+ @NonNull
+ public String getCustomCategoryPattern() {
+ return mCustomCategoryPattern;
+ }
+
+ /**
+ * Returns the preset categories value of this configuration.
+ */
+ @PresetCategories
+ public int getPresetCategories() {
+ return mPresetCategories;
+ }
+
+ /**
+ * Returns the tracing mode of this configuration.
+ */
+ @TracingMode
+ public int getTracingMode() {
+ return mTracingMode;
+ }
+
+}
diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java
new file mode 100644
index 0000000..cadb8a1
--- /dev/null
+++ b/core/java/android/webkit/TracingController.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2017 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 android.webkit;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+
+/**
+ * Manages tracing of WebViews. In particular provides functionality for the app
+ * to enable/disable tracing of parts of code and to collect tracing data.
+ * This is useful for profiling performance issues, debugging and memory usage
+ * analysis in production and real life scenarios.
+ * <p>
+ * The resulting trace data is sent back as a byte sequence in json format. This
+ * file can be loaded in "chrome://tracing" for further analysis.
+ * <p>
+ * Note: All methods in this class must be called on the UI thread. All callbacks
+ * are also called on the UI thread.
+ * <p>
+ * Example usage:
+ * <pre class="prettyprint">
+ * TracingController tracingController = TracingController.getInstance();
+ * tracingController.start(new TraceConfig(CATEGORIES_WEB_DEVELOPER));
+ * [..]
+ * tracingController.stopAndFlush(new TraceFileOutput("trace.json"), null);
+ * </pre></p>
+ */
+public abstract class TracingController {
+
+ /**
+ * Interface for capturing tracing data.
+ */
+ public interface TracingOutputStream {
+ /**
+ * Will be called to return tracing data in chunks.
+ * Tracing data is returned in json format an array of bytes.
+ */
+ void write(byte[] chunk);
+
+ /**
+ * Called when tracing is finished and the data collection is over.
+ * There will be no calls to #write after #complete is called.
+ */
+ void complete();
+ }
+
+ /**
+ * Returns the default TracingController instance. At present there is
+ * only one TracingController instance for all WebView instances,
+ * however this restriction may be relaxed in the future.
+ *
+ * @return the default TracingController instance
+ */
+ @NonNull
+ public static TracingController getInstance() {
+ return WebViewFactory.getProvider().getTracingController();
+ }
+
+ /**
+ * Starts tracing all webviews. Depeding on the trace mode in traceConfig
+ * specifies how the trace events are recorded.
+ *
+ * For tracing modes {@link TracingConfig#RECORD_UNTIL_FULL},
+ * {@link TracingConfig#RECORD_CONTINUOUSLY} and
+ * {@link TracingConfig#RECORD_UNTIL_FULL_LARGE_BUFFER} the events are recorded
+ * using an internal buffer and flushed to the outputStream when
+ * {@link #stopAndFlush(TracingOutputStream, Handler)} is called.
+ *
+ * @param tracingConfig configuration options to use for tracing
+ * @return false if the system is already tracing, true otherwise.
+ */
+ public abstract boolean start(TracingConfig tracingConfig);
+
+ /**
+ * Stops tracing and discards all tracing data.
+ *
+ * This method is particularly useful in conjunction with the
+ * {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode because tracing data is logged to
+ * console and not sent to an outputStream as with
+ * {@link #stopAndFlush(TracingOutputStream, Handler)}.
+ *
+ * @return false if the system was not tracing at the time of the call, true
+ * otherwise.
+ */
+ public abstract boolean stop();
+
+ /**
+ * Stops tracing and flushes tracing data to the specifid outputStream.
+ *
+ * Note that if the {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode is used
+ * nothing will be sent to the outputStream and no TracingOuputStream methods will be
+ * called. In that case it is more convenient to just use {@link #stop()} instead.
+ *
+ * @param outputStream the output steam the tracing data will be sent to.
+ * @param handler the {@link android.os.Handler} on which the outputStream callbacks
+ * will be invoked. If the handler is null the current thread's Looper
+ * will be used.
+ * @return false if the system was not tracing at the time of the call, true
+ * otherwise.
+ */
+ public abstract boolean stopAndFlush(TracingOutputStream outputStream,
+ @Nullable Handler handler);
+
+ /** True if the system is tracing */
+ public abstract boolean isTracing();
+
+ // TODO: consider adding getTraceBufferUsage, percentage and approx event count.
+ // TODO: consider adding String getCategories(), for obtaining the actual list
+ // of categories used (given that presets are ints).
+
+}
diff --git a/core/java/android/webkit/TracingFileOutputStream.java b/core/java/android/webkit/TracingFileOutputStream.java
new file mode 100644
index 0000000..8a5fa36
--- /dev/null
+++ b/core/java/android/webkit/TracingFileOutputStream.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 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 android.webkit;
+
+import android.annotation.NonNull;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Simple TracingOutputStream implementation which writes the trace data from
+ * {@link TracingController} to a new file.
+ *
+ */
+public class TracingFileOutputStream implements TracingController.TracingOutputStream {
+
+ private FileOutputStream mFileOutput;
+
+ public TracingFileOutputStream(@NonNull String filename) throws FileNotFoundException {
+ mFileOutput = new FileOutputStream(filename);
+ }
+
+ /**
+ * Writes bytes chunk to the file.
+ */
+ public void write(byte[] chunk) {
+ try {
+ mFileOutput.write(chunk);
+ } catch (IOException e) {
+ onIOException(e);
+ }
+ }
+
+ /**
+ * Closes the file.
+ */
+ public void complete() {
+ try {
+ mFileOutput.close();
+ } catch (IOException e) {
+ onIOException(e);
+ }
+ }
+
+ private void onIOException(IOException e) {
+ throw new RuntimeException(e);
+ }
+}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index e493739..90cc481 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -122,7 +122,13 @@
}
/** @hide */
- @IntDef({LOAD_DEFAULT, LOAD_NORMAL, LOAD_CACHE_ELSE_NETWORK, LOAD_NO_CACHE, LOAD_CACHE_ONLY})
+ @IntDef(prefix = { "LOAD_" }, value = {
+ LOAD_DEFAULT,
+ LOAD_NORMAL,
+ LOAD_CACHE_ELSE_NETWORK,
+ LOAD_NO_CACHE,
+ LOAD_CACHE_ONLY
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface CacheMode {}
@@ -1415,13 +1421,12 @@
/**
* @hide
*/
- @IntDef(flag = true,
- value = {
- MENU_ITEM_NONE,
- MENU_ITEM_SHARE,
- MENU_ITEM_WEB_SEARCH,
- MENU_ITEM_PROCESS_TEXT
- })
+ @IntDef(flag = true, prefix = { "MENU_ITEM_" }, value = {
+ MENU_ITEM_NONE,
+ MENU_ITEM_SHARE,
+ MENU_ITEM_WEB_SEARCH,
+ MENU_ITEM_PROCESS_TEXT
+ })
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.PARAMETER, ElementType.METHOD})
private @interface MenuItemFlags {}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6f99254..d39c1e1 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2249,10 +2249,10 @@
}
/** @hide */
- @IntDef({
- RENDERER_PRIORITY_WAIVED,
- RENDERER_PRIORITY_BOUND,
- RENDERER_PRIORITY_IMPORTANT
+ @IntDef(prefix = { "RENDERER_PRIORITY_" }, value = {
+ RENDERER_PRIORITY_WAIVED,
+ RENDERER_PRIORITY_BOUND,
+ RENDERER_PRIORITY_IMPORTANT
})
@Retention(RetentionPolicy.SOURCE)
public @interface RendererPriority {}
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 46c3983..d0f9eee 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -256,11 +256,11 @@
public static final int ERROR_UNSAFE_RESOURCE = -16;
/** @hide */
- @IntDef({
- SAFE_BROWSING_THREAT_UNKNOWN,
- SAFE_BROWSING_THREAT_MALWARE,
- SAFE_BROWSING_THREAT_PHISHING,
- SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE
+ @IntDef(prefix = { "SAFE_BROWSING_THREAT_" }, value = {
+ SAFE_BROWSING_THREAT_UNKNOWN,
+ SAFE_BROWSING_THREAT_MALWARE,
+ SAFE_BROWSING_THREAT_PHISHING,
+ SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE
})
@Retention(RetentionPolicy.SOURCE)
public @interface SafeBrowsingThreat {}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 4c47abc..3ced6a5 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -134,6 +134,14 @@
TokenBindingService getTokenBindingService();
/**
+ * Gets the TracingController instance for this WebView implementation. The
+ * implementation must return the same instance on subsequent calls.
+ *
+ * @return the TracingController instance
+ */
+ TracingController getTracingController();
+
+ /**
* Gets the ServiceWorkerController instance for this WebView implementation. The
* implementation must return the same instance on subsequent calls.
*
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index dfb3642..b2b93fa 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -107,7 +107,10 @@
public static final int MODE_CALENDAR = 2;
/** @hide */
- @IntDef({MODE_SPINNER, MODE_CALENDAR})
+ @IntDef(prefix = { "MODE_" }, value = {
+ MODE_SPINNER,
+ MODE_CALENDAR
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface DatePickerMode {}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index e065dc1..a440398 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4924,7 +4924,10 @@
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef({HANDLE_TYPE_SELECTION_START, HANDLE_TYPE_SELECTION_END})
+ @IntDef(prefix = { "HANDLE_TYPE_" }, value = {
+ HANDLE_TYPE_SELECTION_START,
+ HANDLE_TYPE_SELECTION_END
+ })
public @interface HandleType {}
public static final int HANDLE_TYPE_SELECTION_START = 0;
public static final int HANDLE_TYPE_SELECTION_END = 1;
@@ -6129,7 +6132,11 @@
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef({MERGE_EDIT_MODE_FORCE_MERGE, MERGE_EDIT_MODE_NEVER_MERGE, MERGE_EDIT_MODE_NORMAL})
+ @IntDef(prefix = { "MERGE_EDIT_MODE_" }, value = {
+ MERGE_EDIT_MODE_FORCE_MERGE,
+ MERGE_EDIT_MODE_NEVER_MERGE,
+ MERGE_EDIT_MODE_NORMAL
+ })
private @interface MergeMode {}
private static final int MERGE_EDIT_MODE_FORCE_MERGE = 0;
private static final int MERGE_EDIT_MODE_NEVER_MERGE = 1;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index cbd1e0a..012b918 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -172,7 +172,10 @@
// Public constants
/** @hide */
- @IntDef({HORIZONTAL, VERTICAL})
+ @IntDef(prefix = { "HORIZONTAL", "VERTICAL" }, value = {
+ HORIZONTAL,
+ VERTICAL
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Orientation {}
@@ -198,7 +201,10 @@
public static final int UNDEFINED = Integer.MIN_VALUE;
/** @hide */
- @IntDef({ALIGN_BOUNDS, ALIGN_MARGINS})
+ @IntDef(prefix = { "ALIGN_" }, value = {
+ ALIGN_BOUNDS,
+ ALIGN_MARGINS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AlignmentMode {}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index fcb44af..1ec9b2f 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -65,7 +65,12 @@
@RemoteView
public class GridView extends AbsListView {
/** @hide */
- @IntDef({NO_STRETCH, STRETCH_SPACING, STRETCH_COLUMN_WIDTH, STRETCH_SPACING_UNIFORM})
+ @IntDef(prefix = { "NO_STRETCH", "STRETCH_" }, value = {
+ NO_STRETCH,
+ STRETCH_SPACING,
+ STRETCH_COLUMN_WIDTH,
+ STRETCH_SPACING_UNIFORM
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface StretchMode {}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 380bf7a..7ea1f1e 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -95,13 +95,12 @@
public static final int VERTICAL = 1;
/** @hide */
- @IntDef(flag = true,
- value = {
- SHOW_DIVIDER_NONE,
- SHOW_DIVIDER_BEGINNING,
- SHOW_DIVIDER_MIDDLE,
- SHOW_DIVIDER_END
- })
+ @IntDef(flag = true, prefix = { "SHOW_DIVIDER_" }, value = {
+ SHOW_DIVIDER_NONE,
+ SHOW_DIVIDER_BEGINNING,
+ SHOW_DIVIDER_MIDDLE,
+ SHOW_DIVIDER_END
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface DividerMode {}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 4d3189e..d98b865 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -510,7 +510,11 @@
*/
public interface OnScrollListener {
/** @hide */
- @IntDef({SCROLL_STATE_IDLE, SCROLL_STATE_TOUCH_SCROLL, SCROLL_STATE_FLING})
+ @IntDef(prefix = { "SCROLL_STATE_" }, value = {
+ SCROLL_STATE_IDLE,
+ SCROLL_STATE_TOUCH_SCROLL,
+ SCROLL_STATE_FLING
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface ScrollState {}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f8083ba..903d3ca 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -751,7 +751,10 @@
public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1;
/** @hide */
- @IntDef({AUTO_SIZE_TEXT_TYPE_NONE, AUTO_SIZE_TEXT_TYPE_UNIFORM})
+ @IntDef(prefix = { "AUTO_SIZE_TEXT_TYPE_" }, value = {
+ AUTO_SIZE_TEXT_TYPE_NONE,
+ AUTO_SIZE_TEXT_TYPE_UNIFORM
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface AutoSizeTextType {}
// Default minimum size for auto-sizing text in scaled pixels.
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index ae6881e..cfec3f2 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -77,7 +77,10 @@
public static final int MODE_CLOCK = 2;
/** @hide */
- @IntDef({MODE_SPINNER, MODE_CLOCK})
+ @IntDef(prefix = { "MODE_" }, value = {
+ MODE_SPINNER,
+ MODE_CLOCK
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface TimePickerMode {}
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index d807120..edcf209 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -71,7 +71,10 @@
static final boolean localLOGV = false;
/** @hide */
- @IntDef({LENGTH_SHORT, LENGTH_LONG})
+ @IntDef(prefix = { "LENGTH_" }, value = {
+ LENGTH_SHORT,
+ LENGTH_LONG
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface Duration {}
diff --git a/packages/SystemUI/res/layout/output_chooser.xml b/packages/SystemUI/res/layout/output_chooser.xml
new file mode 100644
index 0000000..22c3bcf
--- /dev/null
+++ b/packages/SystemUI/res/layout/output_chooser.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 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.
+-->
+<!-- extends FrameLayout -->
+<com.android.systemui.volume.OutputChooserLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/output_chooser"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="20dp" >
+
+ <com.android.systemui.qs.AutoSizingList
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ sysui:itemHeight="@dimen/qs_detail_item_height"
+ style="@style/AutoSizingList"/>
+
+ <LinearLayout
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:tint="?android:attr/textColorSecondary" />
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/>
+ </LinearLayout>
+</com.android.systemui.volume.OutputChooserLayout>
diff --git a/packages/SystemUI/res/layout/output_chooser_item.xml b/packages/SystemUI/res/layout/output_chooser_item.xml
new file mode 100644
index 0000000..ed7df4b
--- /dev/null
+++ b/packages/SystemUI/res/layout/output_chooser_item.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/qs_detail_item_height"
+ android:background="@drawable/btn_borderless_rect"
+ android:clickable="true"
+ android:focusable="true"
+ android:gravity="center_vertical"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/qs_detail_item_icon_width"
+ android:layout_height="@dimen/qs_detail_item_icon_size"
+ android:layout_marginStart="@dimen/qs_detail_item_icon_marginStart"
+ android:layout_marginEnd="@dimen/qs_detail_item_icon_marginEnd"
+ android:tint="?android:attr/textColorPrimary"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_weight="1"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:ellipsize="end"
+ android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" />
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:layout_marginTop="2dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" />
+ </LinearLayout>
+
+ <ImageView
+ android:id="@android:id/icon2"
+ style="@style/QSBorderlessButton"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="30dp"
+ android:clickable="true"
+ android:focusable="true"
+ android:scaleType="center"
+ android:contentDescription="@*android:string/media_route_controller_disconnect"
+ android:tint="?android:attr/textColorPrimary" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index bab1e5e..f0d2346 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -70,58 +70,77 @@
android:layout_height="@dimen/volume_button_size"
android:clickable="true"
android:soundEffectsEnabled="false"
- android:src="@drawable/ic_volume_collapse_animation"
+ android:src="@drawable/ic_volume_expand_animation"
android:background="@drawable/ripple_drawable"
tools:ignore="RtlHardcoded" />
</LinearLayout>
- <!-- special row for ringer mode -->
<RelativeLayout
- android:id="@+id/ringer_mode"
+ android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/rounded_bg_full"
android:clipChildren="false"
android:clipToPadding="false"
android:layout_below="@id/volume_dialog_content"
android:layout_margin="10dp">
+ <!-- special row for ringer mode -->
+ <RelativeLayout
+ android:id="@+id/ringer_mode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/rounded_bg_full"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:layout_toStartOf="@id/output_chooser"
+ android:layout_margin="10dp">
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/ringer_icon"
+ style="@style/VolumeButtons"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:layout_width="@dimen/volume_button_size"
+ android:layout_height="@dimen/volume_button_size"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:soundEffectsEnabled="false" />
+
+ <TextView
+ android:id="@+id/ringer_title"
+ android:text="@string/ring_toggle_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:layout_toEndOf="@+id/ringer_icon"
+ android:layout_marginStart="64dp"
+ android:textColor="?android:attr/colorControlNormal"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:paddingStart="@dimen/volume_row_header_padding_start" />
+
+ <TextView
+ android:id="@+id/ringer_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:layout_marginEnd="14dp"
+ android:maxLines="1"
+ android:textColor="?android:attr/colorControlNormal"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ </RelativeLayout>
<com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/ringer_icon"
+ android:id="@+id/output_chooser"
style="@style/VolumeButtons"
android:background="?android:selectableItemBackgroundBorderless"
android:layout_width="@dimen/volume_button_size"
android:layout_height="@dimen/volume_button_size"
- android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
- android:soundEffectsEnabled="false" />
-
- <TextView
- android:id="@+id/ringer_title"
- android:text="@string/stream_ring"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:maxLines="1"
- android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
- android:layout_toEndOf="@+id/ringer_icon"
- android:layout_marginStart="64dp"
- android:textColor="?android:attr/colorControlNormal"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:paddingStart="@dimen/volume_row_header_padding_start" />
-
- <TextView
- android:id="@+id/ringer_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
- android:layout_marginEnd="14dp"
- android:maxLines="1"
- android:textColor="?android:attr/colorControlNormal"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
+ android:src="@drawable/ic_settings_bluetooth"
+ android:soundEffectsEnabled="false" />
</RelativeLayout>
</RelativeLayout>
</com.android.systemui.volume.VolumeUiLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 62ab74d..78e621e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1248,6 +1248,7 @@
<string name="stream_tts" translatable="false">Transmitted Through Speaker</string> <!-- STREAM_TTS -->
<string name="stream_accessibility">Accessibility</string> <!-- STREAM_ACCESSIBILITY -->
+ <string name="ring_toggle_title">Calls</string>
<string name="volume_ringer_status_normal">Ring</string>
<string name="volume_ringer_status_vibrate">Vibrate</string>
<string name="volume_ringer_status_silent">Mute</string>
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 49a12f4..e1376ca 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -80,6 +80,7 @@
public static final int DISMISS_REASON_SETTINGS_CLICKED = 5;
public static final int DISMISS_REASON_DONE_CLICKED = 6;
public static final int DISMISS_STREAM_GONE = 7;
+ public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8;
public static final String[] DISMISS_REASONS = {
"unknown",
"touch_outside",
@@ -88,7 +89,8 @@
"screen_off",
"settings_clicked",
"done_clicked",
- "a11y_stream_changed"
+ "a11y_stream_changed",
+ "output_chooser"
};
public static final int SHOW_REASON_UNKNOWN = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
new file mode 100644
index 0000000..fa82e33
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2015 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.systemui.volume;
+
+import static com.android.settingslib.bluetooth.Utils.getBtClassDrawableWithDescription;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.settingslib.Utils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.BluetoothController;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class OutputChooserDialog extends SystemUIDialog
+ implements DialogInterface.OnDismissListener, OutputChooserLayout.Callback {
+
+ private static final String TAG = Util.logTag(OutputChooserDialog.class);
+ private static final int MAX_DEVICES = 10;
+
+ private final Context mContext;
+ private final BluetoothController mController;
+ private OutputChooserLayout mView;
+
+
+ public OutputChooserDialog(Context context) {
+ super(context);
+ mContext = context;
+ mController = Dependency.get(BluetoothController.class);
+
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ context.registerReceiver(mReceiver, filter);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.output_chooser);
+ setCanceledOnTouchOutside(true);
+ setOnDismissListener(this::onDismiss);
+ mView = findViewById(R.id.output_chooser);
+ mView.setCallback(this);
+ updateItems();
+ mController.addCallback(mCallback);
+ }
+
+ protected void cleanUp() {}
+
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ }
+
+ @Override
+ public void onDismiss(DialogInterface unused) {
+ mContext.unregisterReceiver(mReceiver);
+ mController.removeCallback(mCallback);
+ cleanUp();
+ }
+
+ @Override
+ public void onDetailItemClick(OutputChooserLayout.Item item) {
+ if (item == null || item.tag == null) return;
+ final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
+ if (device != null && device.getMaxConnectionState()
+ == BluetoothProfile.STATE_DISCONNECTED) {
+ mController.connect(device);
+ }
+ }
+
+ @Override
+ public void onDetailItemDisconnect(OutputChooserLayout.Item item) {
+ if (item == null || item.tag == null) return;
+ final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
+ if (device != null) {
+ mController.disconnect(device);
+ }
+ }
+
+ private void updateItems() {
+ if (mView == null) return;
+ if (mController.isBluetoothEnabled()) {
+ mView.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
+ R.string.quick_settings_bluetooth_detail_empty_text);
+ mView.setItemsVisible(true);
+ } else {
+ mView.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
+ R.string.bt_is_off);
+ mView.setItemsVisible(false);
+ }
+ ArrayList<OutputChooserLayout.Item> items = new ArrayList<>();
+ final Collection<CachedBluetoothDevice> devices = mController.getDevices();
+ if (devices != null) {
+ int connectedDevices = 0;
+ int count = 0;
+ for (CachedBluetoothDevice device : devices) {
+ if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
+ final int majorClass = device.getBtClass().getMajorDeviceClass();
+ if (majorClass != BluetoothClass.Device.Major.AUDIO_VIDEO
+ && majorClass != BluetoothClass.Device.Major.UNCATEGORIZED) {
+ continue;
+ }
+ final OutputChooserLayout.Item item = new OutputChooserLayout.Item();
+ item.iconResId = R.drawable.ic_qs_bluetooth_on;
+ item.line1 = device.getName();
+ item.tag = device;
+ int state = device.getMaxConnectionState();
+ if (state == BluetoothProfile.STATE_CONNECTED) {
+ item.iconResId = R.drawable.ic_qs_bluetooth_connected;
+ int batteryLevel = device.getBatteryLevel();
+ if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+ Pair<Drawable, String> pair =
+ getBtClassDrawableWithDescription(getContext(), device);
+ item.icon = pair.first;
+ item.line2 = mContext.getString(
+ R.string.quick_settings_connected_battery_level,
+ Utils.formatPercentage(batteryLevel));
+ } else {
+ item.line2 = mContext.getString(R.string.quick_settings_connected);
+ }
+ item.canDisconnect = true;
+ items.add(connectedDevices, item);
+ connectedDevices++;
+ } else if (state == BluetoothProfile.STATE_CONNECTING) {
+ item.iconResId = R.drawable.ic_qs_bluetooth_connecting;
+ item.line2 = mContext.getString(R.string.quick_settings_connecting);
+ items.add(connectedDevices, item);
+ } else {
+ items.add(item);
+ }
+ if (++count == MAX_DEVICES) {
+ break;
+ }
+ }
+ }
+ mView.setItems(items.toArray(new OutputChooserLayout.Item[items.size()]));
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+ if (D.BUG) Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
+ cancel();
+ cleanUp();
+ }
+ }
+ };
+
+ private final BluetoothController.Callback mCallback = new BluetoothController.Callback() {
+ @Override
+ public void onBluetoothStateChange(boolean enabled) {
+ updateItems();
+ }
+
+ @Override
+ public void onBluetoothDevicesChanged() {
+ updateItems();
+ }
+ };
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserLayout.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserLayout.java
new file mode 100644
index 0000000..e8be4fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserLayout.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2017 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.systemui.volume;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.qs.AutoSizingList;
+
+/**
+ * Limited height list of devices.
+ */
+public class OutputChooserLayout extends FrameLayout {
+ private static final String TAG = "OutputChooserLayout";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final int mQsDetailIconOverlaySize;
+ private final Context mContext;
+ private final H mHandler = new H();
+ private final Adapter mAdapter = new Adapter();
+
+ private String mTag;
+ private Callback mCallback;
+ private boolean mItemsVisible = true;
+ private AutoSizingList mItemList;
+ private View mEmpty;
+ private TextView mEmptyText;
+ private ImageView mEmptyIcon;
+
+ private Item[] mItems;
+
+ public OutputChooserLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ mTag = TAG;
+ mQsDetailIconOverlaySize = (int) getResources().getDimension(
+ R.dimen.qs_detail_icon_overlay_size);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mItemList = findViewById(android.R.id.list);
+ mItemList.setVisibility(GONE);
+ mItemList.setAdapter(mAdapter);
+ mEmpty = findViewById(android.R.id.empty);
+ mEmpty.setVisibility(GONE);
+ mEmptyText = mEmpty.findViewById(android.R.id.title);
+ mEmptyIcon = mEmpty.findViewById(android.R.id.icon);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ FontSizeUtils.updateFontSize(mEmptyText, R.dimen.qs_detail_empty_text_size);
+ int count = mItemList.getChildCount();
+ for (int i = 0; i < count; i++) {
+ View item = mItemList.getChildAt(i);
+ FontSizeUtils.updateFontSize(item, android.R.id.title,
+ R.dimen.qs_detail_item_primary_text_size);
+ FontSizeUtils.updateFontSize(item, android.R.id.summary,
+ R.dimen.qs_detail_item_secondary_text_size);
+ }
+ }
+
+ public void setEmptyState(int icon, int text) {
+ mEmpty.post(() -> {
+ mEmptyIcon.setImageResource(icon);
+ mEmptyText.setText(text);
+ });
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (DEBUG) Log.d(mTag, "onAttachedToWindow");
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
+ mCallback = null;
+ }
+
+ public void setCallback(Callback callback) {
+ mHandler.removeMessages(H.SET_CALLBACK);
+ mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget();
+ }
+
+ public void setItems(Item[] items) {
+ mHandler.removeMessages(H.SET_ITEMS);
+ mHandler.obtainMessage(H.SET_ITEMS, items).sendToTarget();
+ }
+
+ public void setItemsVisible(boolean visible) {
+ mHandler.removeMessages(H.SET_ITEMS_VISIBLE);
+ mHandler.obtainMessage(H.SET_ITEMS_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
+ }
+
+ private void handleSetCallback(Callback callback) {
+ mCallback = callback;
+ }
+
+ private void handleSetItems(Item[] items) {
+ final int itemCount = items != null ? items.length : 0;
+ mEmpty.setVisibility(itemCount == 0 ? VISIBLE : GONE);
+ mItemList.setVisibility(itemCount == 0 ? GONE : VISIBLE);
+ mItems = items;
+ mAdapter.notifyDataSetChanged();
+ }
+
+ private void handleSetItemsVisible(boolean visible) {
+ if (mItemsVisible == visible) return;
+ mItemsVisible = visible;
+ for (int i = 0; i < mItemList.getChildCount(); i++) {
+ mItemList.getChildAt(i).setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
+ }
+ }
+
+ private class Adapter extends BaseAdapter {
+
+ @Override
+ public int getCount() {
+ return mItems != null ? mItems.length : 0;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mItems[position];
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ final Item item = mItems[position];
+ if (view == null) {
+ view = LayoutInflater.from(mContext).inflate(R.layout.output_chooser_item, parent,
+ false);
+ }
+ view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
+ final ImageView iv = view.findViewById(android.R.id.icon);
+ if (item.icon != null) {
+ iv.setImageDrawable(item.icon);
+ } else {
+ iv.setImageResource(item.iconResId);
+ }
+ iv.getOverlay().clear();
+ if (item.overlay != null) {
+ item.overlay.setBounds(0, 0, mQsDetailIconOverlaySize, mQsDetailIconOverlaySize);
+ iv.getOverlay().add(item.overlay);
+ }
+ final TextView title = view.findViewById(android.R.id.title);
+ title.setText(item.line1);
+ final TextView summary = view.findViewById(android.R.id.summary);
+ final boolean twoLines = !TextUtils.isEmpty(item.line2);
+ title.setMaxLines(twoLines ? 1 : 2);
+ summary.setVisibility(twoLines ? VISIBLE : GONE);
+ summary.setText(twoLines ? item.line2 : null);
+ view.setOnClickListener(v -> {
+ if (mCallback != null) {
+ mCallback.onDetailItemClick(item);
+ }
+ });
+
+ final ImageView icon2 = view.findViewById(android.R.id.icon2);
+ if (item.canDisconnect) {
+ icon2.setImageResource(R.drawable.ic_qs_cancel);
+ icon2.setVisibility(VISIBLE);
+ icon2.setClickable(true);
+ icon2.setOnClickListener(v -> {
+ if (mCallback != null) {
+ mCallback.onDetailItemDisconnect(item);
+ }
+ });
+ } else if (item.icon2 != -1) {
+ icon2.setVisibility(VISIBLE);
+ icon2.setImageResource(item.icon2);
+ icon2.setClickable(false);
+ } else {
+ icon2.setVisibility(GONE);
+ }
+
+ return view;
+ }
+ };
+
+ private class H extends Handler {
+ private static final int SET_ITEMS = 1;
+ private static final int SET_CALLBACK = 2;
+ private static final int SET_ITEMS_VISIBLE = 3;
+
+ public H() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == SET_ITEMS) {
+ handleSetItems((Item[]) msg.obj);
+ } else if (msg.what == SET_CALLBACK) {
+ handleSetCallback((OutputChooserLayout.Callback) msg.obj);
+ } else if (msg.what == SET_ITEMS_VISIBLE) {
+ handleSetItemsVisible(msg.arg1 != 0);
+ }
+ }
+ }
+
+ public static class Item {
+ public int iconResId;
+ public Drawable icon;
+ public Drawable overlay;
+ public CharSequence line1;
+ public CharSequence line2;
+ public Object tag;
+ public boolean canDisconnect;
+ public int icon2 = -1;
+ }
+
+ public interface Callback {
+ void onDetailItemClick(Item item);
+ void onDetailItemDisconnect(Item item);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7959b72..d7c8010 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -19,6 +19,7 @@
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
+import static com.android.systemui.volume.Events.DISMISS_REASON_OUTPUT_CHOOSER;
import static com.android.systemui.volume.Events.DISMISS_REASON_TOUCH_OUTSIDE;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -37,7 +38,6 @@
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.TransitionDrawable;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.os.Debug;
@@ -106,6 +106,7 @@
private ViewGroup mDialogRowsView;
private ImageButton mExpandButton;
private ImageButton mRingerIcon;
+ private ImageButton mOutputChooser;
private TextView mRingerStatus;
private final List<VolumeRow> mRows = new ArrayList<>();
private ConfigurableTexts mConfigurableTexts;
@@ -113,6 +114,7 @@
private final KeyguardManager mKeyguard;
private final AccessibilityManager mAccessibilityMgr;
private final Object mSafetyWarningLock = new Object();
+ private final Object mOutputChooserLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
private final ColorStateList mActiveSliderTint;
private final ColorStateList mInactiveSliderTint;
@@ -128,6 +130,7 @@
private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
private State mState;
private SafetyWarningDialog mSafetyWarning;
+ private OutputChooserDialog mOutputChooserDialog;
private boolean mHovering = false;
public VolumeDialogImpl(Context context) {
@@ -213,6 +216,9 @@
mExpandButton.setVisibility(
AudioSystem.isSingleVolume(mContext) ? View.GONE : View.VISIBLE);
+ mOutputChooser = mDialogView.findViewById(R.id.output_chooser);
+ mOutputChooser.setOnClickListener(mClickOutputChooser);
+
if (mRows.isEmpty()) {
addRow(AudioManager.STREAM_MUSIC,
R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true, true);
@@ -913,6 +919,23 @@
rescheduleTimeoutH();
}
+ private void showOutputChooserH() {
+ synchronized (mOutputChooserLock) {
+ if (mOutputChooserDialog != null) {
+ return;
+ }
+ mOutputChooserDialog = new OutputChooserDialog(mContext) {
+ @Override
+ protected void cleanUp() {
+ synchronized (mOutputChooserLock) {
+ mOutputChooserDialog = null;
+ }
+ }
+ };
+ mOutputChooserDialog.show();
+ }
+ }
+
private String getStreamLabelH(StreamState ss) {
if (ss.remoteLabel != null) {
return ss.remoteLabel;
@@ -935,6 +958,15 @@
}
};
+ private final OnClickListener mClickOutputChooser = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // TODO: log
+ dismissH(DISMISS_REASON_OUTPUT_CHOOSER);
+ showOutputChooserH();
+ }
+ };
+
private final VolumeDialogController.Callbacks mControllerCallbackH
= new VolumeDialogController.Callbacks() {
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ac0cdd7..5ec3850 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -28,6 +28,7 @@
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.AlertDialog;
+import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManagerInternal;
import android.content.BroadcastReceiver;
@@ -193,6 +194,8 @@
private final SecurityPolicy mSecurityPolicy;
+ private final AppOpsManager mAppOpsManager;
+
private final MainHandler mMainHandler;
private final GlobalActionPerformer mGlobalActionPerformer;
@@ -261,6 +264,7 @@
mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mSecurityPolicy = new SecurityPolicy();
+ mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mMainHandler = new MainHandler(mContext.getMainLooper());
mGlobalActionPerformer = new GlobalActionPerformer(mContext, mWindowManagerService);
@@ -1223,14 +1227,11 @@
for (int i = 0, count = installedServices.size(); i < count; i++) {
ResolveInfo resolveInfo = installedServices.get(i);
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
- if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
- serviceInfo.permission)) {
- Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName(
- serviceInfo.packageName, serviceInfo.name).flattenToShortString()
- + ": it does not require the permission "
- + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
+
+ if (!canRegisterService(serviceInfo)) {
continue;
}
+
AccessibilityServiceInfo accessibilityServiceInfo;
try {
accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
@@ -1251,6 +1252,28 @@
return false;
}
+ private boolean canRegisterService(ServiceInfo serviceInfo) {
+ if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
+ serviceInfo.permission)) {
+ Slog.w(LOG_TAG, "Skipping accessibility service " + new ComponentName(
+ serviceInfo.packageName, serviceInfo.name).flattenToShortString()
+ + ": it does not require the permission "
+ + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
+ return false;
+ }
+
+ int servicePackageUid = serviceInfo.applicationInfo.uid;
+ if (mAppOpsManager.noteOpNoThrow(AppOpsManager.OP_BIND_ACCESSIBILITY_SERVICE,
+ servicePackageUid, serviceInfo.packageName) != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(LOG_TAG, "Skipping accessibility service " + new ComponentName(
+ serviceInfo.packageName, serviceInfo.name).flattenToShortString()
+ + ": disallowed by AppOps");
+ return false;
+ }
+
+ return true;
+ }
+
private boolean readEnabledAccessibilityServicesLocked(UserState userState) {
mTempComponentNameSet.clear();
readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 1dba052..4adcb99 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -3242,10 +3242,10 @@
skip = true;
}
- // Do we have a transport to fetch data for us?
- IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
- if (transport == null) {
- if (DEBUG) Slog.w(TAG, "No transport");
+ TransportClient transportClient =
+ mTransportManager.getCurrentTransportClient("BMS.restoreAtInstall()");
+ if (transportClient == null) {
+ if (DEBUG) Slog.w(TAG, "No transport client");
skip = true;
}
@@ -3262,16 +3262,26 @@
// The eventual message back into the Package Manager to run the post-install
// steps for 'token' will be issued from the restore handling code.
- // This can throw and so *must* happen before the wakelock is acquired
- String dirName = transport.transportDirName();
-
mWakelock.acquire();
+
+ OnTaskFinishedListener listener = caller -> {
+ mTransportManager.disposeOfTransportClient(transportClient, caller);
+ mWakelock.release();
+ };
+
if (MORE_DEBUG) {
Slog.d(TAG, "Restore at install of " + packageName);
}
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(transport, dirName, null, null,
- restoreSet, packageName, token);
+ msg.obj =
+ RestoreParams.createForRestoreAtInstall(
+ transportClient,
+ /* observer */ null,
+ /* monitor */ null,
+ restoreSet,
+ packageName,
+ token,
+ listener);
mBackupHandler.sendMessage(msg);
} catch (Exception e) {
// Calling into the transport broke; back off and proceed with the installation.
@@ -3281,8 +3291,14 @@
}
if (skip) {
- // Auto-restore disabled or no way to attempt a restore; just tell the Package
- // Manager to proceed with the post-install handling for this package.
+ // Auto-restore disabled or no way to attempt a restore
+
+ if (transportClient != null) {
+ mTransportManager.disposeOfTransportClient(
+ transportClient, "BMS.restoreAtInstall()");
+ }
+
+ // Tell the PackageManager to proceed with the post-install handling for this package.
if (DEBUG) Slog.v(TAG, "Finishing install immediately");
try {
mPackageManagerBinder.finishPackageInstall(token, false);
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index f8f1448..1f3ebf9 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -308,6 +308,12 @@
}
}
+ public boolean isTransportRegistered(String transportName) {
+ synchronized (mTransportLock) {
+ return getRegisteredTransportEntryLocked(transportName) != null;
+ }
+ }
+
/**
* Returns a {@link TransportClient} for the current transport or null if not found.
*
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 477724d..4c78348 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -189,7 +189,7 @@
}
task.execute();
} catch (ClassCastException e) {
- Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj);
+ Slog.e(TAG, "Invalid backup/restore task in flight, obj=" + msg.obj);
}
break;
}
@@ -229,10 +229,18 @@
RestoreParams params = (RestoreParams) msg.obj;
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
- PerformUnifiedRestoreTask task = new PerformUnifiedRestoreTask(backupManagerService,
- params.transport,
- params.observer, params.monitor, params.token, params.pkgInfo,
- params.pmToken, params.isSystemRestore, params.filterSet);
+ PerformUnifiedRestoreTask task =
+ new PerformUnifiedRestoreTask(
+ backupManagerService,
+ params.transportClient,
+ params.observer,
+ params.monitor,
+ params.token,
+ params.packageInfo,
+ params.pmToken,
+ params.isSystemRestore,
+ params.filterSet,
+ params.listener);
synchronized (backupManagerService.getPendingRestores()) {
if (backupManagerService.isRestoreInProgress()) {
@@ -299,8 +307,11 @@
// Like other async operations, this is entered with the wakelock held
RestoreSet[] sets = null;
RestoreGetSetsParams params = (RestoreGetSetsParams) msg.obj;
+ String callerLogString = "BH/MSG_RUN_GET_RESTORE_SETS";
try {
- sets = params.transport.getAvailableRestoreSets();
+ IBackupTransport transport =
+ params.transportClient.connectOrThrow(callerLogString);
+ sets = transport.getAvailableRestoreSets();
// cache the result in the active session
synchronized (params.session) {
params.session.mRestoreSets = sets;
@@ -325,7 +336,7 @@
removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
- backupManagerService.getWakelock().release();
+ params.listener.onFinished(callerLogString);
}
break;
}
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index e65eb28..a002334 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -907,7 +907,7 @@
mStatus = BackupTransport.TRANSPORT_OK;
long size = 0;
try {
- TransportUtils.checkTransport(transport);
+ TransportUtils.checkTransportNotNull(transport);
size = mBackupDataName.length();
if (size > 0) {
if (mStatus == BackupTransport.TRANSPORT_OK) {
@@ -997,7 +997,7 @@
}
if (mAgentBinder != null) {
try {
- TransportUtils.checkTransport(transport);
+ TransportUtils.checkTransportNotNull(transport);
long quota = transport.getBackupQuota(mCurrentPackage.packageName, false);
mAgentBinder.doQuotaExceeded(size, quota);
} catch (Exception e) {
diff --git a/services/backup/java/com/android/server/backup/params/RestoreGetSetsParams.java b/services/backup/java/com/android/server/backup/params/RestoreGetSetsParams.java
index bff476b..914e9ea 100644
--- a/services/backup/java/com/android/server/backup/params/RestoreGetSetsParams.java
+++ b/services/backup/java/com/android/server/backup/params/RestoreGetSetsParams.java
@@ -20,20 +20,24 @@
import android.app.backup.IRestoreObserver;
import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.restore.ActiveRestoreSession;
+import com.android.server.backup.transport.TransportClient;
public class RestoreGetSetsParams {
+ public final TransportClient transportClient;
+ public final ActiveRestoreSession session;
+ public final IRestoreObserver observer;
+ public final IBackupManagerMonitor monitor;
+ public final OnTaskFinishedListener listener;
- public IBackupTransport transport;
- public ActiveRestoreSession session;
- public IRestoreObserver observer;
- public IBackupManagerMonitor monitor;
-
- public RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
- IRestoreObserver _observer, IBackupManagerMonitor _monitor) {
- transport = _transport;
+ public RestoreGetSetsParams(TransportClient _transportClient, ActiveRestoreSession _session,
+ IRestoreObserver _observer, IBackupManagerMonitor _monitor,
+ OnTaskFinishedListener _listener) {
+ transportClient = _transportClient;
session = _session;
observer = _observer;
monitor = _monitor;
+ listener = _listener;
}
}
diff --git a/services/backup/java/com/android/server/backup/params/RestoreParams.java b/services/backup/java/com/android/server/backup/params/RestoreParams.java
index 93ce00d..e500d6e 100644
--- a/services/backup/java/com/android/server/backup/params/RestoreParams.java
+++ b/services/backup/java/com/android/server/backup/params/RestoreParams.java
@@ -20,84 +20,128 @@
import android.app.backup.IRestoreObserver;
import android.content.pm.PackageInfo;
-import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.internal.OnTaskFinishedListener;
+import com.android.server.backup.transport.TransportClient;
public class RestoreParams {
-
- public IBackupTransport transport;
- public String dirName;
- public IRestoreObserver observer;
- public IBackupManagerMonitor monitor;
- public long token;
- public PackageInfo pkgInfo;
- public int pmToken; // in post-install restore, the PM's token for this transaction
- public boolean isSystemRestore;
- public String[] filterSet;
+ public final TransportClient transportClient;
+ public final IRestoreObserver observer;
+ public final IBackupManagerMonitor monitor;
+ public final long token;
+ public final PackageInfo packageInfo;
+ public final int pmToken; // in post-install restore, the PM's token for this transaction
+ public final boolean isSystemRestore;
+ public final String[] filterSet;
+ public final OnTaskFinishedListener listener;
/**
- * Restore a single package; no kill after restore
+ * No kill after restore.
*/
- public RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- IBackupManagerMonitor _monitor, long _token, PackageInfo _pkg) {
- transport = _transport;
- dirName = _dirName;
- observer = _obs;
- monitor = _monitor;
- token = _token;
- pkgInfo = _pkg;
- pmToken = 0;
- isSystemRestore = false;
- filterSet = null;
+ public static RestoreParams createForSinglePackage(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ PackageInfo packageInfo,
+ OnTaskFinishedListener listener) {
+ return new RestoreParams(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ packageInfo,
+ /* pmToken */ 0,
+ /* isSystemRestore */ false,
+ /* filterSet */ null,
+ listener);
}
/**
- * Restore at install: PM token needed, kill after restore
+ * Kill after restore.
*/
- public RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- IBackupManagerMonitor _monitor, long _token, String _pkgName, int _pmToken) {
- transport = _transport;
- dirName = _dirName;
- observer = _obs;
- monitor = _monitor;
- token = _token;
- pkgInfo = null;
- pmToken = _pmToken;
- isSystemRestore = false;
- filterSet = new String[]{_pkgName};
+ public static RestoreParams createForRestoreAtInstall(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ String packageName,
+ int pmToken,
+ OnTaskFinishedListener listener) {
+ String[] filterSet = {packageName};
+ return new RestoreParams(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ /* packageInfo */ null,
+ pmToken,
+ /* isSystemRestore */ false,
+ filterSet,
+ listener);
}
/**
- * Restore everything possible. This is the form that Setup Wizard or similar
- * restore UXes use.
+ * This is the form that Setup Wizard or similar restore UXes use.
*/
- public RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- IBackupManagerMonitor _monitor, long _token) {
- transport = _transport;
- dirName = _dirName;
- observer = _obs;
- monitor = _monitor;
- token = _token;
- pkgInfo = null;
- pmToken = 0;
- isSystemRestore = true;
- filterSet = null;
+ public static RestoreParams createForRestoreAll(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ OnTaskFinishedListener listener) {
+ return new RestoreParams(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ /* packageInfo */ null,
+ /* pmToken */ 0,
+ /* isSystemRestore */ true,
+ /* filterSet */ null,
+ listener);
}
/**
- * Restore some set of packages. Leave this one up to the caller to specify
- * whether it's to be considered a system-level restore.
+ * Caller specifies whether is considered a system-level restore.
*/
- public RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- IBackupManagerMonitor _monitor, long _token,
- String[] _filterSet, boolean _isSystemRestore) {
- transport = _transport;
- dirName = _dirName;
- observer = _obs;
- monitor = _monitor;
- token = _token;
- pkgInfo = null;
- pmToken = 0;
- isSystemRestore = _isSystemRestore;
- filterSet = _filterSet;
+ public static RestoreParams createForRestoreSome(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ String[] filterSet,
+ boolean isSystemRestore,
+ OnTaskFinishedListener listener) {
+ return new RestoreParams(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ /* packageInfo */ null,
+ /* pmToken */ 0,
+ isSystemRestore,
+ filterSet,
+ listener);
+ }
+
+ private RestoreParams(
+ TransportClient transportClient,
+ IRestoreObserver observer,
+ IBackupManagerMonitor monitor,
+ long token,
+ PackageInfo packageInfo,
+ int pmToken,
+ boolean isSystemRestore,
+ String[] filterSet,
+ OnTaskFinishedListener listener) {
+ this.transportClient = transportClient;
+ this.observer = observer;
+ this.monitor = monitor;
+ this.token = token;
+ this.packageInfo = packageInfo;
+ this.pmToken = pmToken;
+ this.isSystemRestore = isSystemRestore;
+ this.filterSet = filterSet;
+ this.listener = listener;
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index a08c19e..7ae5b43 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -31,33 +31,39 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.Message;
+import android.os.PowerManager;
import android.util.Slog;
-import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.RefactoredBackupManagerService;
+import com.android.server.backup.TransportManager;
+import com.android.server.backup.internal.BackupHandler;
+import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.params.RestoreGetSetsParams;
import com.android.server.backup.params.RestoreParams;
+import com.android.server.backup.transport.TransportClient;
+
+import java.util.function.BiFunction;
/**
* Restore session.
*/
public class ActiveRestoreSession extends IRestoreSession.Stub {
-
private static final String TAG = "RestoreSession";
- private RefactoredBackupManagerService backupManagerService;
- private String mPackageName;
- private IBackupTransport mRestoreTransport = null;
+ private final TransportManager mTransportManager;
+ private final String mTransportName;
+ private final RefactoredBackupManagerService mBackupManagerService;
+ private final String mPackageName;
public RestoreSet[] mRestoreSets = null;
boolean mEnded = false;
boolean mTimedOut = false;
public ActiveRestoreSession(RefactoredBackupManagerService backupManagerService,
- String packageName, String transport) {
- this.backupManagerService = backupManagerService;
+ String packageName, String transportName) {
+ mBackupManagerService = backupManagerService;
mPackageName = packageName;
- mRestoreTransport = backupManagerService.getTransportManager().getTransportBinder(
- transport);
+ mTransportManager = backupManagerService.getTransportManager();
+ mTransportName = transportName;
}
public void markTimedOut() {
@@ -67,7 +73,7 @@
// --- Binder interface ---
public synchronized int getAvailableRestoreSets(IRestoreObserver observer,
IBackupManagerMonitor monitor) {
- backupManagerService.getContext().enforceCallingOrSelfPermission(
+ mBackupManagerService.getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP,
"getAvailableRestoreSets");
if (observer == null) {
@@ -85,23 +91,32 @@
long oldId = Binder.clearCallingIdentity();
try {
- if (mRestoreTransport == null) {
- Slog.w(TAG, "Null transport getting restore sets");
+ TransportClient transportClient =
+ mTransportManager.getTransportClient(
+ mTransportName, "RestoreSession.getAvailableRestoreSets()");
+ if (transportClient == null) {
+ Slog.w(TAG, "Null transport client getting restore sets");
return -1;
}
// We know we're doing legit work now, so halt the timeout
// until we're done. It gets started again when the result
// comes in.
- backupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
+ mBackupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
- // spin off the transport request to our service thread
- backupManagerService.getWakelock().acquire();
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
+ PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+ wakelock.acquire();
+
+ // Prevent lambda from leaking 'this'
+ TransportManager transportManager = mTransportManager;
+ OnTaskFinishedListener listener = caller -> {
+ transportManager.disposeOfTransportClient(transportClient, caller);
+ wakelock.release();
+ };
+ Message msg = mBackupManagerService.getBackupHandler().obtainMessage(
MSG_RUN_GET_RESTORE_SETS,
- new RestoreGetSetsParams(mRestoreTransport, this, observer,
- monitor));
- backupManagerService.getBackupHandler().sendMessage(msg);
+ new RestoreGetSetsParams(transportClient, this, observer, monitor, listener));
+ mBackupManagerService.getBackupHandler().sendMessage(msg);
return 0;
} catch (Exception e) {
Slog.e(TAG, "Error in getAvailableRestoreSets", e);
@@ -113,7 +128,7 @@
public synchronized int restoreAll(long token, IRestoreObserver observer,
IBackupManagerMonitor monitor) {
- backupManagerService.getContext().enforceCallingOrSelfPermission(
+ mBackupManagerService.getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP,
"performRestore");
@@ -131,7 +146,7 @@
return -1;
}
- if (mRestoreTransport == null || mRestoreSets == null) {
+ if (mRestoreSets == null) {
Slog.e(TAG, "Ignoring restoreAll() with no restore set");
return -1;
}
@@ -141,37 +156,28 @@
return -1;
}
- String dirName;
- try {
- dirName = mRestoreTransport.transportDirName();
- } catch (Exception e) {
- // Transport went AWOL; fail.
- Slog.e(TAG, "Unable to get transport dir for restore: " + e.getMessage());
+ if (!mTransportManager.isTransportRegistered(mTransportName)) {
+ Slog.e(TAG, "Transport " + mTransportName + " not registered");
return -1;
}
- synchronized (backupManagerService.getQueueLock()) {
+ synchronized (mBackupManagerService.getQueueLock()) {
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
- // Real work, so stop the session timeout until we finalize the restore
- backupManagerService.getBackupHandler().removeMessages(
- MSG_RESTORE_SESSION_TIMEOUT);
-
long oldId = Binder.clearCallingIdentity();
try {
- backupManagerService.getWakelock().acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restoreAll() kicking off");
- }
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
- MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName,
- observer, monitor, token);
- backupManagerService.getBackupHandler().sendMessage(msg);
+ return sendRestoreToHandlerLocked(
+ (transportClient, listener) ->
+ RestoreParams.createForRestoreAll(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ listener),
+ "RestoreSession.restoreAll()");
} finally {
Binder.restoreCallingIdentity(oldId);
}
- return 0;
}
}
}
@@ -183,7 +189,7 @@
// Restores of more than a single package are treated as 'system' restores
public synchronized int restoreSome(long token, IRestoreObserver observer,
IBackupManagerMonitor monitor, String[] packages) {
- backupManagerService.getContext().enforceCallingOrSelfPermission(
+ mBackupManagerService.getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP,
"performRestore");
@@ -227,7 +233,7 @@
return -1;
}
- if (mRestoreTransport == null || mRestoreSets == null) {
+ if (mRestoreSets == null) {
Slog.e(TAG, "Ignoring restoreAll() with no restore set");
return -1;
}
@@ -237,34 +243,30 @@
return -1;
}
- String dirName;
- try {
- dirName = mRestoreTransport.transportDirName();
- } catch (Exception e) {
- // Transport went AWOL; fail.
- Slog.e(TAG, "Unable to get transport name for restoreSome: " + e.getMessage());
+ if (!mTransportManager.isTransportRegistered(mTransportName)) {
+ Slog.e(TAG, "Transport " + mTransportName + " not registered");
return -1;
}
- synchronized (backupManagerService.getQueueLock()) {
+ synchronized (mBackupManagerService.getQueueLock()) {
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
- // Stop the session timeout until we finalize the restore
- backupManagerService.getBackupHandler().removeMessages(
- MSG_RESTORE_SESSION_TIMEOUT);
-
long oldId = Binder.clearCallingIdentity();
- backupManagerService.getWakelock().acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restoreSome() of " + packages.length + " packages");
+ try {
+ return sendRestoreToHandlerLocked(
+ (transportClient, listener) ->
+ RestoreParams.createForRestoreSome(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ packages,
+ /* isSystemRestore */ packages.length > 1,
+ listener),
+ "RestoreSession.restoreSome(" + packages.length + " packages)");
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
- MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, monitor,
- token, packages, packages.length > 1);
- backupManagerService.getBackupHandler().sendMessage(msg);
- Binder.restoreCallingIdentity(oldId);
- return 0;
}
}
}
@@ -297,9 +299,9 @@
}
}
- PackageInfo app = null;
+ final PackageInfo app;
try {
- app = backupManagerService.getPackageManager().getPackageInfo(packageName, 0);
+ app = mBackupManagerService.getPackageManager().getPackageInfo(packageName, 0);
} catch (NameNotFoundException nnf) {
Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
return -1;
@@ -307,7 +309,7 @@
// If the caller is not privileged and is not coming from the target
// app's uid, throw a permission exception back to the caller.
- int perm = backupManagerService.getContext().checkPermission(
+ int perm = mBackupManagerService.getContext().checkPermission(
android.Manifest.permission.BACKUP,
Binder.getCallingPid(), Binder.getCallingUid());
if ((perm == PackageManager.PERMISSION_DENIED) &&
@@ -317,12 +319,17 @@
throw new SecurityException("No permission to restore other packages");
}
+ if (!mTransportManager.isTransportRegistered(mTransportName)) {
+ Slog.e(TAG, "Transport " + mTransportName + " not registered");
+ return -1;
+ }
+
// So far so good; we're allowed to try to restore this package.
long oldId = Binder.clearCallingIdentity();
try {
// Check whether there is data for it in the current dataset, falling back
// to the ancestral dataset if not.
- long token = backupManagerService.getAvailableRestoreToken(packageName);
+ long token = mBackupManagerService.getAvailableRestoreToken(packageName);
if (DEBUG) {
Slog.v(TAG, "restorePackage pkg=" + packageName
+ " token=" + Long.toHexString(token));
@@ -338,30 +345,53 @@
return -1;
}
- String dirName;
- try {
- dirName = mRestoreTransport.transportDirName();
- } catch (Exception e) {
- // Transport went AWOL; fail.
- Slog.e(TAG, "Unable to get transport dir for restorePackage: " + e.getMessage());
- return -1;
- }
-
- // Stop the session timeout until we finalize the restore
- backupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
-
- // Ready to go: enqueue the restore request and claim success
- backupManagerService.getWakelock().acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restorePackage() : " + packageName);
- }
- Message msg = backupManagerService.getBackupHandler().obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, monitor,
- token, app);
- backupManagerService.getBackupHandler().sendMessage(msg);
+ return sendRestoreToHandlerLocked(
+ (transportClient, listener) ->
+ RestoreParams.createForSinglePackage(
+ transportClient,
+ observer,
+ monitor,
+ token,
+ app,
+ listener),
+ "RestoreSession.restorePackage(" + packageName + ")");
} finally {
Binder.restoreCallingIdentity(oldId);
}
+ }
+
+ /**
+ * Returns 0 if operation sent or -1 otherwise.
+ */
+ private int sendRestoreToHandlerLocked(
+ BiFunction<TransportClient, OnTaskFinishedListener, RestoreParams> restoreParamsBuilder,
+ String callerLogString) {
+ TransportClient transportClient =
+ mTransportManager.getTransportClient(mTransportName, callerLogString);
+ if (transportClient == null) {
+ Slog.e(TAG, "Transport " + mTransportName + " got unregistered");
+ return -1;
+ }
+
+ // Stop the session timeout until we finalize the restore
+ BackupHandler backupHandler = mBackupManagerService.getBackupHandler();
+ backupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
+
+ PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
+ wakelock.acquire();
+ if (MORE_DEBUG) {
+ Slog.d(TAG, callerLogString);
+ }
+
+ // Prevent lambda from leaking 'this'
+ TransportManager transportManager = mTransportManager;
+ OnTaskFinishedListener listener = caller -> {
+ transportManager.disposeOfTransportClient(transportClient, caller);
+ wakelock.release();
+ };
+ Message msg = backupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = restoreParamsBuilder.apply(transportClient, listener);
+ backupHandler.sendMessage(msg);
return 0;
}
@@ -380,7 +410,6 @@
public void run() {
// clean up the session's bookkeeping
synchronized (mSession) {
- mSession.mRestoreTransport = null;
mSession.mEnded = true;
}
@@ -404,7 +433,7 @@
throw new IllegalStateException("Restore session already ended");
}
- backupManagerService.getBackupHandler().post(
- new EndRestoreRunnable(backupManagerService, this));
+ mBackupManagerService.getBackupHandler().post(
+ new EndRestoreRunnable(mBackupManagerService, this));
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 2db7430..86866dc 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -61,6 +61,8 @@
import com.android.server.backup.PackageManagerBackupAgent;
import com.android.server.backup.PackageManagerBackupAgent.Metadata;
import com.android.server.backup.RefactoredBackupManagerService;
+import com.android.server.backup.internal.OnTaskFinishedListener;
+import com.android.server.backup.transport.TransportClient;
import com.android.server.backup.utils.AppBackupUtils;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
@@ -76,8 +78,8 @@
public class PerformUnifiedRestoreTask implements BackupRestoreTask {
private RefactoredBackupManagerService backupManagerService;
- // Transport we're working with to do the restore
- private IBackupTransport mTransport;
+ // Transport client we're working with to do the restore
+ private final TransportClient mTransportClient;
// Where per-transport saved state goes
File mStateDir;
@@ -141,6 +143,9 @@
// Done?
private boolean mFinished;
+ // When finished call listener
+ private final OnTaskFinishedListener mListener;
+
// Key/value: bookkeeping about staged data and files for agent access
private File mBackupDataName;
private File mStageName;
@@ -154,15 +159,16 @@
// Invariant: mWakelock is already held, and this task is responsible for
// releasing it at the end of the restore operation.
public PerformUnifiedRestoreTask(RefactoredBackupManagerService backupManagerService,
- IBackupTransport transport, IRestoreObserver observer,
+ TransportClient transportClient, IRestoreObserver observer,
IBackupManagerMonitor monitor, long restoreSetToken, PackageInfo targetPackage,
- int pmToken, boolean isFullSystemRestore, String[] filterSet) {
+ int pmToken, boolean isFullSystemRestore, String[] filterSet,
+ OnTaskFinishedListener listener) {
this.backupManagerService = backupManagerService;
mEphemeralOpToken = backupManagerService.generateRandomIntegerToken();
mState = UnifiedRestoreState.INITIAL;
mStartRealtime = SystemClock.elapsedRealtime();
- mTransport = transport;
+ mTransportClient = transportClient;
mObserver = observer;
mMonitor = monitor;
mToken = restoreSetToken;
@@ -171,6 +177,7 @@
mIsSystemRestore = isFullSystemRestore;
mFinished = false;
mDidLaunch = false;
+ mListener = listener;
if (targetPackage != null) {
// Single package restore
@@ -342,7 +349,7 @@
}
try {
- String transportDir = mTransport.transportDirName();
+ String transportDir = mTransportClient.getTransportDirName();
mStateDir = new File(backupManagerService.getBaseStateDir(), transportDir);
// Fetch the current metadata from the dataset first
@@ -351,7 +358,11 @@
mAcceptSet.add(0, pmPackage);
PackageInfo[] packages = mAcceptSet.toArray(new PackageInfo[0]);
- mStatus = mTransport.startRestore(mToken, packages);
+
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow("PerformUnifiedRestoreTask.startRestore()");
+
+ mStatus = transport.startRestore(mToken, packages);
if (mStatus != BackupTransport.TRANSPORT_OK) {
Slog.e(TAG, "Transport error " + mStatus + "; no restore possible");
mStatus = BackupTransport.TRANSPORT_ERROR;
@@ -359,7 +370,7 @@
return;
}
- RestoreDescription desc = mTransport.nextRestorePackage();
+ RestoreDescription desc = transport.nextRestorePackage();
if (desc == null) {
Slog.e(TAG, "No restore metadata available; halting");
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
@@ -444,7 +455,10 @@
private void dispatchNextRestore() {
UnifiedRestoreState nextState = UnifiedRestoreState.FINAL;
try {
- mRestoreDescription = mTransport.nextRestorePackage();
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow(
+ "PerformUnifiedRestoreTask.dispatchNextRestore()");
+ mRestoreDescription = transport.nextRestorePackage();
final String pkgName = (mRestoreDescription != null)
? mRestoreDescription.getPackageName() : null;
if (pkgName == null) {
@@ -657,13 +671,17 @@
File downloadFile = (staging) ? mStageName : mBackupDataName;
try {
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow(
+ "PerformUnifiedRestoreTask.initiateOneRestore()");
+
// Run the transport's restore pass
stage = ParcelFileDescriptor.open(downloadFile,
ParcelFileDescriptor.MODE_READ_WRITE |
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE);
- if (mTransport.getRestoreData(stage) != BackupTransport.TRANSPORT_OK) {
+ if (transport.getRestoreData(stage) != BackupTransport.TRANSPORT_OK) {
// Transport-level failure, so we wind everything up and
// terminate the restore operation.
Slog.e(TAG, "Error getting restore data for " + packageName);
@@ -750,7 +768,7 @@
// None of this can run on the work looper here, so we spin asynchronous
// work like this:
//
- // StreamFeederThread: read data from mTransport.getNextFullRestoreDataChunk()
+ // StreamFeederThread: read data from transport.getNextFullRestoreDataChunk()
// write it into the pipe to the engine
// EngineThread: FullRestoreEngine thread communicating with the target app
//
@@ -844,10 +862,12 @@
// spin up the engine and start moving data to it
new Thread(mEngineThread, "unified-restore-engine").start();
+ String callerLogString = "PerformUnifiedRestoreTask$StreamFeederThread.run()";
try {
+ IBackupTransport transport = mTransportClient.connectOrThrow(callerLogString);
while (status == BackupTransport.TRANSPORT_OK) {
// have the transport write some of the restoring data to us
- int result = mTransport.getNextFullRestoreDataChunk(tWriteEnd);
+ int result = transport.getNextFullRestoreDataChunk(tWriteEnd);
if (result > 0) {
// The transport wrote this many bytes of restore data to the
// pipe, so pass it along to the engine.
@@ -936,7 +956,9 @@
// Something went wrong somewhere. Whether it was at the transport
// level is immaterial; we need to tell the transport to bail
try {
- mTransport.abortFullRestore();
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow(callerLogString);
+ transport.abortFullRestore();
} catch (Exception e) {
// transport itself is dead; make sure we handle this as a
// fatal error
@@ -1039,8 +1061,11 @@
Slog.d(TAG, "finishing restore mObserver=" + mObserver);
}
+ String callerLogString = "PerformUnifiedRestoreTask.finalizeRestore()";
try {
- mTransport.finishRestore();
+ IBackupTransport transport =
+ mTransportClient.connectOrThrow(callerLogString);
+ transport.finishRestore();
} catch (Exception e) {
Slog.e(TAG, "Error finishing restore", e);
}
@@ -1087,9 +1112,6 @@
backupManagerService.writeRestoreTokens();
}
- // done; we can finally release the wakelock and be legitimately done.
- Slog.i(TAG, "Restore complete.");
-
synchronized (backupManagerService.getPendingRestores()) {
if (backupManagerService.getPendingRestores().size() > 0) {
if (DEBUG) {
@@ -1108,7 +1130,8 @@
}
}
- backupManagerService.getWakelock().release();
+ Slog.i(TAG, "Restore complete.");
+ mListener.onFinished(callerLogString);
}
void keyValueAgentErrorCleanup() {
@@ -1301,13 +1324,11 @@
void sendOnRestorePackage(String name) {
if (mObserver != null) {
- if (mObserver != null) {
- try {
- mObserver.onUpdate(mCount, name);
- } catch (RemoteException e) {
- Slog.d(TAG, "Restore observer died in onUpdate");
- mObserver = null;
- }
+ try {
+ mObserver.onUpdate(mCount, name);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Restore observer died in onUpdate");
+ mObserver = null;
}
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/RestoreEngine.java b/services/backup/java/com/android/server/backup/restore/RestoreEngine.java
index b2fdbb8..9d3ae86 100644
--- a/services/backup/java/com/android/server/backup/restore/RestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/RestoreEngine.java
@@ -30,8 +30,8 @@
public static final int TARGET_FAILURE = -2;
public static final int TRANSPORT_FAILURE = -3;
- private AtomicBoolean mRunning = new AtomicBoolean(false);
- private AtomicInteger mResult = new AtomicInteger(SUCCESS);
+ private final AtomicBoolean mRunning = new AtomicBoolean(false);
+ private final AtomicInteger mResult = new AtomicInteger(SUCCESS);
public boolean isRunning() {
return mRunning.get();
diff --git a/services/backup/java/com/android/server/backup/transport/TransportUtils.java b/services/backup/java/com/android/server/backup/transport/TransportUtils.java
index 85599b7..92bba9b 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportUtils.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportUtils.java
@@ -31,7 +31,7 @@
* Throws {@link TransportNotAvailableException} if {@param transport} is null. The semantics is
* similar to a {@link DeadObjectException} coming from a dead transport binder.
*/
- public static IBackupTransport checkTransport(@Nullable IBackupTransport transport)
+ public static IBackupTransport checkTransportNotNull(@Nullable IBackupTransport transport)
throws TransportNotAvailableException {
if (transport == null) {
log(Log.ERROR, TAG, "Transport not available");
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 9bfdd0c..af5cf1e 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -409,15 +409,16 @@
otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
} finally {
- if (mHomeStack != null && !isTopStack(mHomeStack)) {
+ final ActivityStack topFullscreenStack =
+ getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
// Whenever split-screen is dismissed we want the home stack directly behind the
- // currently top stack so it shows up when the top stack is finished.
- final ActivityStack topStack = getTopStack();
+ // current top fullscreen stack so it shows up when the top stack is finished.
// TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
// ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
// once we have that.
mHomeStack.moveToFront("onSplitScreenModeDismissed");
- topStack.moveToFront("onSplitScreenModeDismissed");
+ topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
}
mSupervisor.mWindowManager.continueSurfaceLayout();
}
@@ -435,7 +436,7 @@
}
otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
false /* animate */, false /* showRecents */,
- false /* sendNonResizeableNotification */);
+ true /* enteringSplitScreenMode */);
}
} finally {
mSupervisor.mWindowManager.continueSurfaceLayout();
@@ -555,6 +556,16 @@
return stack == getTopStack();
}
+ boolean isTopFullscreenStack(ActivityStack stack) {
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack current = mStacks.get(i);
+ if (current.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+ return current == stack;
+ }
+ }
+ return false;
+ }
+
int getIndexOf(ActivityStack stack) {
return mStacks.indexOf(stack);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bcb489d..9366f6e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10591,7 +10591,7 @@
stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task);
}
stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate, showRecents,
- true /* sendNonResizeableNotification */);
+ false /* enteringSplitScreenMode */);
return windowingMode != task.getWindowingMode();
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d42c5de..69f6d5e 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -2731,7 +2731,8 @@
* {@link #mShowWhenLocked}.
*/
boolean canShowWhenLocked() {
- return mShowWhenLocked || service.mWindowManager.containsShowWhenLockedWindow(appToken);
+ return !inMultiWindowMode() && (mShowWhenLocked
+ || service.mWindowManager.containsShowWhenLockedWindow(appToken));
}
void setTurnScreenOn(boolean turnScreenOn) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index cf40be5..10c801d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -484,20 +484,24 @@
@Override
public void setWindowingMode(int windowingMode) {
setWindowingMode(windowingMode, false /* animate */, true /* showRecents */,
- true /* sendNonResizeableNotification */);
+ false /* enteringSplitScreenMode */);
}
void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents,
- boolean sendNonResizeableNotification) {
+ boolean enteringSplitScreenMode) {
+ final boolean creating = mWindowContainerController == null;
final int currentMode = getWindowingMode();
final ActivityDisplay display = getDisplay();
final TaskRecord topTask = topTask();
final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
mTmpOptions.setLaunchWindowingMode(preferredWindowingMode);
- // Need to make sure windowing mode is supported.
- int windowingMode = display.resolveWindowingMode(
- null /* ActivityRecord */, mTmpOptions, topTask, getActivityType());
+ // Need to make sure windowing mode is supported. If we in the process of creating the stack
+ // no need to resolve the windowing mode again as it is already resolved to the right mode.
+ int windowingMode = creating
+ ? preferredWindowingMode
+ : display.resolveWindowingMode(
+ null /* ActivityRecord */, mTmpOptions, topTask, getActivityType());
if (splitScreenStack == this && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
// Resolution to split-screen secondary for the primary split-screen stack means we want
// to go fullscreen.
@@ -506,14 +510,19 @@
final boolean alreadyInSplitScreenMode = display.hasSplitScreenPrimaryStack();
+ // Don't send non-resizeable notifications if the windowing mode changed was a side effect
+ // of us entering split-screen mode.
+ final boolean sendNonResizeableNotification = !enteringSplitScreenMode;
// Take any required action due to us not supporting the preferred windowing mode.
- if (sendNonResizeableNotification
- && windowingMode != preferredWindowingMode && isActivityTypeStandardOrUndefined()) {
- if (alreadyInSplitScreenMode
- && (preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
- // Looks like we can't launch in split screen mode, go ahead an dismiss split-screen
- // and display a warning toast about it.
+ if (alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
+ && sendNonResizeableNotification && isActivityTypeStandardOrUndefined()) {
+ final boolean preferredSplitScreen =
+ preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ if (preferredSplitScreen || creating) {
+ // Looks like we can't launch in split screen mode or the stack we are launching
+ // doesn't support split-screen mode, go ahead an dismiss split-screen and display a
+ // warning toast about it.
mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
display.getSplitScreenPrimaryStack().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
@@ -544,7 +553,7 @@
}
super.setWindowingMode(windowingMode);
- if (mWindowContainerController == null) {
+ if (creating) {
// Nothing else to do if we don't have a window container yet. E.g. call from ctor.
return;
}
@@ -594,16 +603,22 @@
// the one where the home stack is visible since recents isn't visible yet, but the
// divider will be off. I think we should just make the initial bounds that of home
// so that the divider matches and remove this logic.
- display.getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
- ACTIVITY_TYPE_RECENTS, true /* onTop */);
+ final ActivityStack recentStack = display.getOrCreateStack(
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS,
+ true /* onTop */);
+ recentStack.moveToFront("setWindowingMode");
// If task moved to docked stack - show recents if needed.
mService.mWindowManager.showRecentApps(false /* fromHome */);
}
wm.continueSurfaceLayout();
}
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ // Don't ensure visible activities if the windowing mode change was a side effect of us
+ // entering split-screen mode.
+ if (!enteringSplitScreenMode) {
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ }
}
@Override
@@ -1668,7 +1683,7 @@
continue;
}
- if (!r.visible && r != starting) {
+ if (!r.visibleIgnoringKeyguard && r != starting) {
// Also ignore invisible activities that are not the currently starting
// activity (about to be visible).
continue;
@@ -1796,6 +1811,7 @@
boolean behindFullscreenActivity = !stackShouldBeVisible;
boolean resumeNextActivity = mStackSupervisor.isFocusedStack(this)
&& (isInStackLocked(starting) == null);
+ final boolean isTopFullscreenStack = getDisplay().isTopFullscreenStack(this);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -1817,7 +1833,7 @@
// Now check whether it's really visible depending on Keyguard state.
final boolean reallyVisible = checkKeyguardVisibility(r,
- visibleIgnoringKeyguard, isTop);
+ visibleIgnoringKeyguard, isTop && isTopFullscreenStack);
if (visibleIgnoringKeyguard) {
behindFullscreenActivity = updateBehindFullscreen(!stackShouldBeVisible,
behindFullscreenActivity, r);
@@ -1943,13 +1959,11 @@
*
* @return true if {@param r} is visible taken Keyguard state into account, false otherwise
*/
- boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible,
- boolean isTop) {
- final boolean isInPinnedStack = r.inPinnedWindowingMode();
+ boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) {
final boolean keyguardShowing = mStackSupervisor.getKeyguardController().isKeyguardShowing(
mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked();
- final boolean showWhenLocked = r.canShowWhenLocked() && !isInPinnedStack;
+ final boolean showWhenLocked = r.canShowWhenLocked();
final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
if (shouldBeVisible) {
if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index c39ce98..94a0cb7 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -66,6 +66,7 @@
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.view.animation.Transformation;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputApplicationHandle;
@@ -75,6 +76,7 @@
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.LinkedList;
class AppTokenList extends ArrayList<AppWindowToken> {
}
@@ -231,7 +233,7 @@
// If this initial window is animating, stop it -- we will do an animation to reveal
// it from behind the starting window, so there is no need for it to also be doing its
// own stuff.
- winAnimator.clearAnimation();
+ win.cancelAnimation();
if (getController() != null) {
getController().removeStartingWindow();
}
@@ -389,7 +391,7 @@
}
for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
- if ((mChildren.get(i)).isWindowAnimationSet()) {
+ if ((mChildren.get(i)).isSelfOrChildAnimating()) {
delayed = true;
}
}
@@ -610,8 +612,12 @@
*/
private void destroySurfaces(boolean cleanupOnResume) {
boolean destroyedSomething = false;
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState win = mChildren.get(i);
+
+ // Copying to a different list as multiple children can be removed.
+ // TODO: Not sure why this is needed.
+ final LinkedList<WindowState> children = new LinkedList<>(mChildren);
+ for (int i = children.size() - 1; i >= 0; i--) {
+ final WindowState win = children.get(i);
destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
}
if (destroyedSomething) {
@@ -1320,7 +1326,7 @@
+ " pv=" + w.mPolicyVisibility
+ " mDrawState=" + winAnimator.drawStateToString()
+ " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
- + " a=" + winAnimator.mAnimating);
+ + " a=" + winAnimator.isAnimationSet());
}
}
@@ -1520,6 +1526,11 @@
}
@Override
+ boolean isSelfAnimating() {
+ return mAppAnimator.isAnimating();
+ }
+
+ @Override
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index eda8fec..f458457 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -146,6 +146,7 @@
import android.view.MagnificationSpec;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import com.android.internal.annotations.VisibleForTesting;
@@ -339,6 +340,7 @@
new ApplySurfaceChangesTransactionState();
private final ScreenshotApplicationState mScreenshotApplicationState =
new ScreenshotApplicationState();
+ private final Transaction mTmpTransaction = new Transaction();
// True if this display is in the process of being removed. Used to determine if the removal of
// the display's direct children should be allowed.
@@ -379,29 +381,11 @@
*/
private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
+ /** Temporary float array to retrieve 3x3 matrix values. */
+ private final float[] mTmpFloats = new float[9];
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
- if (winAnimator.hasSurface()) {
- final boolean wasAnimating = winAnimator.mWasAnimating;
- final boolean nowAnimating = winAnimator.stepAnimationLocked(
- mTmpWindowAnimator.mCurrentTime);
- winAnimator.mWasAnimating = nowAnimating;
- mTmpWindowAnimator.orAnimating(nowAnimating);
-
- if (DEBUG_WALLPAPER) Slog.v(TAG,
- w + ": wasAnimating=" + wasAnimating + ", nowAnimating=" + nowAnimating);
-
- if (wasAnimating && !winAnimator.mAnimating
- && mWallpaperController.isWallpaperTarget(w)) {
- mTmpWindowAnimator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
- pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- if (DEBUG_LAYOUT_REPEATS) {
- mService.mWindowPlacerLocked.debugLayoutRepeats(
- "updateWindowsAndWallpaperLocked 2", pendingLayoutChanges);
- }
- }
- }
-
final AppWindowToken atoken = w.mAppToken;
if (winAnimator.mDrawState == READY_TO_SHOW) {
if (atoken == null || atoken.allDrawn) {
@@ -434,13 +418,13 @@
// If this window is animating, make a note that we have an animating window and take
// care of a request to run a detached wallpaper animation.
- if (winAnimator.mAnimating) {
- if (winAnimator.mAnimation != null) {
- if ((flags & FLAG_SHOW_WALLPAPER) != 0
- && winAnimator.mAnimation.getDetachWallpaper()) {
+ if (winAnimator.isAnimationSet()) {
+ final AnimationAdapter anim = w.getAnimation();
+ if (anim != null) {
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0 && anim.getDetachWallpaper()) {
mTmpWindow = w;
}
- final int color = winAnimator.mAnimation.getBackgroundColor();
+ final int color = anim.getBackgroundColor();
if (color != 0) {
final TaskStack stack = w.getStack();
if (stack != null) {
@@ -448,7 +432,6 @@
}
}
}
- mTmpWindowAnimator.setAnimating(true);
}
// If this window's app token is running a detached wallpaper animation, make a note so
@@ -684,7 +667,10 @@
mWallpaperController.updateWallpaperVisibility();
}
- w.handleWindowMovedIfNeeded();
+ // Use mTmpTransaction instead of mPendingTransaction because we don't want to commit
+ // other changes in mPendingTransaction at this point.
+ w.handleWindowMovedIfNeeded(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
final WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -720,7 +706,7 @@
}
}
final TaskStack stack = w.getStack();
- if ((!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening())
+ if ((!winAnimator.isWaitingForOpening())
|| (stack != null && stack.isAnimatingBounds())) {
// Updates the shown frame before we set up the surface. This is needed
// because the resizing could change the top-left position (in addition to
@@ -736,6 +722,12 @@
winAnimator.computeShownFrameLocked();
}
winAnimator.setSurfaceBoundariesLocked(mTmpRecoveringMemory /* recoveringMemory */);
+
+ // Since setSurfaceBoundariesLocked applies the clipping, we need to apply the position
+ // to the surface of the window container as well. Use mTmpTransaction instead of
+ // mPendingTransaction to avoid committing any existing changes in there.
+ w.updateSurfacePosition(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
}
final AppWindowToken atoken = w.mAppToken;
@@ -2617,8 +2609,7 @@
forAllWindows(w -> {
if (w.mAppToken == null && policy.canBeHiddenByKeyguardLw(w)
&& w.wouldBeVisibleIfPolicyIgnored() && !w.isVisible()) {
- w.mWinAnimator.setAnimation(
- policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
+ w.startAnimation(policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
}
}, true /* traverseTopToBottom */);
}
@@ -3775,13 +3766,13 @@
}
@Override
- void destroyAfterPendingTransaction(SurfaceControl surface) {
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
mPendingDestroyingSurfaces.add(surface);
}
/**
* Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterTransaction}.
+ * {@link #destroyAfterPendingTransaction}.
*/
void onPendingTransactionApplied() {
for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
@@ -3789,4 +3780,21 @@
}
mPendingDestroyingSurfaces.clear();
}
+
+ @Override
+ void prepareSurfaces() {
+ final ScreenRotationAnimation screenRotationAnimation =
+ mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
+ if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+ screenRotationAnimation.getEnterTransformation().getMatrix().getValues(mTmpFloats);
+ mPendingTransaction.setMatrix(mWindowingLayer,
+ mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
+ mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
+ mPendingTransaction.setPosition(mWindowingLayer,
+ mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
+ mPendingTransaction.setAlpha(mWindowingLayer,
+ screenRotationAnimation.getEnterTransformation().getAlpha());
+ }
+ super.prepareSurfaces();
+ }
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index a37598e..03c0768 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -751,10 +751,10 @@
// There might be an old window delaying the animation start - clear it.
if (mDelayedImeWin != null) {
- mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+ mDelayedImeWin.endDelayingAnimationStart();
}
mDelayedImeWin = imeWin;
- imeWin.mWinAnimator.startDelayingAnimationStart();
+ imeWin.startDelayingAnimationStart();
}
// If we are already waiting for something to be drawn, clear out the old one so it
@@ -765,25 +765,27 @@
mService.mWaitingForDrawnCallback.run();
}
mService.mWaitingForDrawnCallback = () -> {
- mAnimationStartDelayed = false;
- if (mDelayedImeWin != null) {
- mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+ synchronized (mService.mWindowMap) {
+ mAnimationStartDelayed = false;
+ if (mDelayedImeWin != null) {
+ mDelayedImeWin.endDelayingAnimationStart();
+ }
+ // If the adjust status changed since this was posted, only notify
+ // the new states and don't animate.
+ long duration = 0;
+ if (mAdjustedForIme == adjustedForIme
+ && mAdjustedForDivider == adjustedForDivider) {
+ duration = IME_ADJUST_ANIM_DURATION;
+ } else {
+ Slog.w(TAG, "IME adjust changed while waiting for drawn:"
+ + " adjustedForIme=" + adjustedForIme
+ + " adjustedForDivider=" + adjustedForDivider
+ + " mAdjustedForIme=" + mAdjustedForIme
+ + " mAdjustedForDivider=" + mAdjustedForDivider);
+ }
+ notifyAdjustedForImeChanged(
+ mAdjustedForIme || mAdjustedForDivider, duration);
}
- // If the adjust status changed since this was posted, only notify
- // the new states and don't animate.
- long duration = 0;
- if (mAdjustedForIme == adjustedForIme
- && mAdjustedForDivider == adjustedForDivider) {
- duration = IME_ADJUST_ANIM_DURATION;
- } else {
- Slog.w(TAG, "IME adjust changed while waiting for drawn:"
- + " adjustedForIme=" + adjustedForIme
- + " adjustedForDivider=" + adjustedForDivider
- + " mAdjustedForIme=" + mAdjustedForIme
- + " mAdjustedForDivider=" + mAdjustedForDivider);
- }
- notifyAdjustedForImeChanged(
- mAdjustedForIme || mAdjustedForDivider, duration);
};
} else {
notifyAdjustedForImeChanged(
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 5bc2722..3ef9b3f 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -29,7 +29,6 @@
import android.view.Choreographer;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
-import android.view.animation.Transformation;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -44,12 +43,19 @@
private final Object mLock = new Object();
+ /**
+ * Lock for cancelling animations. Must be acquired on it's own, or after acquiring
+ * {@link #mLock}
+ */
+ private final Object mCancelLock = new Object();
+
@VisibleForTesting
Choreographer mChoreographer;
private final Runnable mApplyTransactionRunnable = this::applyTransaction;
private final AnimationHandler mAnimationHandler;
private final Transaction mFrameTransaction;
+ private final AnimatorFactory mAnimatorFactory;
private boolean mApplyScheduled;
@GuardedBy("mLock")
@@ -58,15 +64,15 @@
@GuardedBy("mLock")
@VisibleForTesting
- final ArrayMap<SurfaceControl, ValueAnimator> mRunningAnimations = new ArrayMap<>();
+ final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>();
SurfaceAnimationRunner() {
- this(null /* callbackProvider */, new Transaction());
+ this(null /* callbackProvider */, null /* animatorFactory */, new Transaction());
}
@VisibleForTesting
SurfaceAnimationRunner(@Nullable AnimationFrameCallbackProvider callbackProvider,
- Transaction frameTransaction) {
+ AnimatorFactory animatorFactory, Transaction frameTransaction) {
SurfaceAnimationThread.getHandler().runWithScissors(() -> mChoreographer = getSfInstance(),
0 /* timeout */);
mFrameTransaction = frameTransaction;
@@ -74,6 +80,9 @@
mAnimationHandler.setProvider(callbackProvider != null
? callbackProvider
: new SfVsyncFrameCallbackProvider(mChoreographer));
+ mAnimatorFactory = animatorFactory != null
+ ? animatorFactory
+ : SfValueAnimator::new;
}
void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
@@ -94,18 +103,17 @@
synchronized (mLock) {
if (mPendingAnimations.containsKey(leash)) {
mPendingAnimations.remove(leash);
- // TODO: Releasing the leash is problematic if reparenting hasn't happened yet.
- // Fix with transaction
- //leash.release();
return;
}
- final ValueAnimator anim = mRunningAnimations.get(leash);
+ final RunningAnimation anim = mRunningAnimations.get(leash);
if (anim != null) {
mRunningAnimations.remove(leash);
+ synchronized (mCancelLock) {
+ anim.mCancelled = true;
+ }
SurfaceAnimationThread.getHandler().post(() -> {
- anim.cancel();
+ anim.mAnim.cancel();
applyTransaction();
- //leash.release();
});
}
}
@@ -119,54 +127,51 @@
}
private void startAnimationLocked(RunningAnimation a) {
- final ValueAnimator result = new SfValueAnimator();
+ final ValueAnimator anim = mAnimatorFactory.makeAnimator();
// Animation length is already expected to be scaled.
- result.overrideDurationScale(1.0f);
- result.setDuration(a.animSpec.getDuration());
- result.addUpdateListener(animation -> {
- applyTransformation(a, mFrameTransaction, result.getCurrentPlayTime());
+ anim.overrideDurationScale(1.0f);
+ anim.setDuration(a.mAnimSpec.getDuration());
+ anim.addUpdateListener(animation -> {
+ synchronized (mCancelLock) {
+ if (!a.mCancelled) {
+ applyTransformation(a, mFrameTransaction, anim.getCurrentPlayTime());
+ }
+ }
// Transaction will be applied in the commit phase.
scheduleApplyTransaction();
});
- result.addListener(new AnimatorListenerAdapter() {
-
- private boolean mCancelled;
-
+ anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- mFrameTransaction.show(a.leash);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
+ synchronized (mCancelLock) {
+ if (!a.mCancelled) {
+ mFrameTransaction.show(a.mLeash);
+ }
+ }
}
@Override
public void onAnimationEnd(Animator animation) {
synchronized (mLock) {
- mRunningAnimations.remove(a.leash);
- }
- if (!mCancelled) {
- // Post on other thread that we can push final state without jank.
- AnimationThread.getHandler().post(() -> {
- a.finishCallback.run();
-
- // Make sure to release the leash after finishCallback has been invoked such
- // that reparenting is done already when releasing the leash.
- a.leash.release();
- });
+ mRunningAnimations.remove(a.mLeash);
+ synchronized (mCancelLock) {
+ if (!a.mCancelled) {
+ // Post on other thread that we can push final state without jank.
+ AnimationThread.getHandler().post(a.mFinishCallback);
+ }
+ }
}
}
});
- result.start();
- mRunningAnimations.put(a.leash, result);
+ anim.start();
+ a.mAnim = anim;
+ mRunningAnimations.put(a.mLeash, a);
}
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
- a.animSpec.apply(t, a.leash, currentPlayTime);
+ a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
}
private void stepAnimation(long frameTimeNanos) {
@@ -189,17 +194,26 @@
}
private static final class RunningAnimation {
- final AnimationSpec animSpec;
- final SurfaceControl leash;
- final Runnable finishCallback;
+ final AnimationSpec mAnimSpec;
+ final SurfaceControl mLeash;
+ final Runnable mFinishCallback;
+ ValueAnimator mAnim;
+
+ @GuardedBy("mCancelLock")
+ private boolean mCancelled;
RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback) {
- this.animSpec = animSpec;
- this.leash = leash;
- this.finishCallback = finishCallback;
+ mAnimSpec = animSpec;
+ mLeash = leash;
+ mFinishCallback = finishCallback;
}
}
+ @VisibleForTesting
+ interface AnimatorFactory {
+ ValueAnimator makeAnimator();
+ }
+
/**
* Value animator that uses sf-vsync signal to tick.
*/
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 713d58b..e165211 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -97,7 +97,7 @@
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
cancelAnimation(t, true /* restarting */);
mAnimation = anim;
- final SurfaceControl surface = mAnimatable.getSurface();
+ final SurfaceControl surface = mAnimatable.getSurfaceControl();
if (surface == null) {
Slog.w(TAG, "Unable to start animation, surface is null or no children.");
cancelAnimation();
@@ -105,7 +105,7 @@
}
mLeash = createAnimationLeash(surface, t,
mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), hidden);
- mAnimatable.onLeashCreated(t, mLeash);
+ mAnimatable.onAnimationLeashCreated(t, mLeash);
if (mAnimationStartDelayed) {
if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
return;
@@ -169,7 +169,16 @@
* surface is reparented to the leash. This method takes care of that.
*/
void setLayer(Transaction t, int layer) {
- t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurface(), layer);
+ t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer);
+ }
+
+ /**
+ * Sets the surface to be relatively layered.
+ *
+ * @see #setLayer
+ */
+ void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
+ t.setRelativeLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), relativeTo, layer);
}
/**
@@ -178,7 +187,7 @@
* @see #setLayer
*/
void reparent(Transaction t, SurfaceControl newParent) {
- t.reparent(mLeash != null ? mLeash : mAnimatable.getSurface(), newParent.getHandle());
+ t.reparent(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), newParent.getHandle());
}
/**
@@ -207,8 +216,8 @@
}
private void reset(Transaction t) {
- final SurfaceControl surface = mAnimatable.getSurface();
- final SurfaceControl parent = mAnimatable.getParentSurface();
+ final SurfaceControl surface = mAnimatable.getSurfaceControl();
+ final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
// If the surface was destroyed, we don't care to reparent it back.
final boolean destroy = mLeash != null && surface != null && parent != null;
@@ -216,19 +225,22 @@
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent");
t.reparent(surface, parent.getHandle());
}
+ if (mLeash != null) {
+ mAnimatable.destroyAfterPendingTransaction(mLeash);
+ }
mLeash = null;
mAnimation = null;
// Make sure to inform the animatable after the leash was destroyed.
if (destroy) {
- mAnimatable.onLeashDestroyed(t);
+ mAnimatable.onAnimationLeashDestroyed(t);
}
}
private SurfaceControl createAnimationLeash(SurfaceControl surface, Transaction t, int width,
int height, boolean hidden) {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
- final SurfaceControl.Builder builder = mAnimatable.makeLeash()
+ final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash()
.setName(surface + " - animation-leash")
.setSize(width, height);
final SurfaceControl leash = builder.build();
@@ -273,7 +285,7 @@
* @param t The transaction to use to apply any necessary changes.
* @param leash The leash that was created.
*/
- void onLeashCreated(Transaction t, SurfaceControl leash);
+ void onAnimationLeashCreated(Transaction t, SurfaceControl leash);
/**
* Called when the leash is being destroyed, and the surface was reparented back to the
@@ -281,22 +293,30 @@
*
* @param t The transaction to use to apply any necessary changes.
*/
- void onLeashDestroyed(Transaction t);
+ void onAnimationLeashDestroyed(Transaction t);
/**
- * @return A new child surface.
+ * Destroy a given surface after executing {@link #getPendingTransaction}.
+ *
+ * @see WindowContainer#destroyAfterPendingTransaction
*/
- SurfaceControl.Builder makeLeash();
+ void destroyAfterPendingTransaction(SurfaceControl surface);
+
+ /**
+ * @return A new surface to be used for the animation leash, inserted at the correct
+ * position in the hierarchy.
+ */
+ SurfaceControl.Builder makeAnimationLeash();
/**
* @return The surface of the object to be animated.
*/
- @Nullable SurfaceControl getSurface();
+ @Nullable SurfaceControl getSurfaceControl();
/**
* @return The parent of the surface object to be animated.
*/
- @Nullable SurfaceControl getParentSurface();
+ @Nullable SurfaceControl getParentSurfaceControl();
/**
* @return The width of the surface to be animated.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6ea8a47..244eb66 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -22,7 +22,6 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.res.Configuration.EMPTY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.server.EventLogTags.WM_TASK_REMOVED;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -43,7 +42,6 @@
import android.util.EventLog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import android.view.DisplayInfo;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
@@ -162,7 +160,7 @@
boolean shouldDeferRemoval() {
// TODO: This should probably return false if mChildren.isEmpty() regardless if the stack
// is animating...
- return hasWindowsAlive() && mStack.isAnimating();
+ return hasWindowsAlive() && mStack.isSelfOrChildAnimating();
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 28b1390..9946c6a 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -935,7 +935,7 @@
@Override
void removeIfPossible() {
- if (isAnimating()) {
+ if (isSelfOrChildAnimating()) {
mDeferRemoval = true;
return;
}
@@ -1643,7 +1643,7 @@
/** Returns true if a removal action is still being deferred. */
boolean checkCompleteDeferredRemoval() {
- if (isAnimating()) {
+ if (isSelfOrChildAnimating()) {
return true;
}
if (mDeferRemoval) {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index a12c0e5..3389f71 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -115,7 +115,7 @@
void startAnimation(Animation anim) {
for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) {
final WindowState windowState = mChildren.get(ndx);
- windowState.mWinAnimator.setAnimation(anim);
+ windowState.startAnimation(anim);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 56175c7..bb25297 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -31,7 +31,7 @@
private Animation mAnimation;
private final Point mPosition = new Point();
- private final ThreadLocal<Tmp> mThreadLocalTmps = ThreadLocal.withInitial(Tmp::new);
+ private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
public WindowAnimationSpec(Animation animation, Point position) {
mAnimation = animation;
@@ -55,7 +55,7 @@
@Override
public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
- final Tmp tmp = mThreadLocalTmps.get();
+ final TmpValues tmp = mThreadLocalTmps.get();
tmp.transformation.clear();
mAnimation.getTransformation(currentPlayTime, tmp.transformation);
tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
@@ -63,7 +63,7 @@
t.setAlpha(leash, tmp.transformation.getAlpha());
}
- private static class Tmp {
+ private static class TmpValues {
final Transformation transformation = new Transformation();
final float[] floats = new float[9];
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index d6329bf..b2b6119 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -19,6 +19,9 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.proto.WindowContainerProto.CONFIGURATION_CONTAINER;
import static com.android.server.wm.proto.WindowContainerProto.ORIENTATION;
import static com.android.server.wm.proto.WindowContainerProto.VISIBLE;
@@ -26,14 +29,20 @@
import android.annotation.CallSuper;
import android.content.res.Configuration;
+import android.graphics.PixelFormat.Opacity;
+import android.util.Slog;
import android.view.MagnificationSpec;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;
import android.util.Pools;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.util.ToBooleanFunction;
+import com.android.internal.util.ToBooleanFunction;
+import com.android.server.wm.SurfaceAnimator.Animatable;
+
+import java.io.PrintWriter;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.function.Consumer;
@@ -46,7 +55,9 @@
* changes are made to this class.
*/
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
- implements Comparable<WindowContainer> {
+ implements Comparable<WindowContainer>, Animatable {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
static final int POSITION_TOP = Integer.MAX_VALUE;
static final int POSITION_BOTTOM = Integer.MIN_VALUE;
@@ -56,7 +67,7 @@
* For removing or setting new parent {@link #setParent} should be used, because it also
* performs configuration updates based on new parent's settings.
*/
- private WindowContainer mParent = null;
+ private WindowContainer<WindowContainer> mParent = null;
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
@@ -69,7 +80,7 @@
new Pools.SynchronizedPool<>(3);
// The owner/creator for this container. No controller if null.
- WindowContainerController mController;
+ WindowContainerController mController;
protected SurfaceControl mSurfaceControl;
private int mLastLayer = 0;
@@ -78,12 +89,14 @@
/**
* Applied as part of the animation pass in "prepareSurfaces".
*/
- private final Transaction mPendingTransaction;
+ protected final Transaction mPendingTransaction;
+ protected final SurfaceAnimator mSurfaceAnimator;
protected final WindowManagerService mService;
WindowContainer(WindowManagerService service) {
mService = service;
mPendingTransaction = service.mTransactionFactory.make();
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
}
@Override
@@ -101,7 +114,7 @@
return mChildren.get(index);
}
- final protected void setParent(WindowContainer parent) {
+ final protected void setParent(WindowContainer<WindowContainer> parent) {
mParent = parent;
// Removing parent usually means that we've detached this entity to destroy it or to attach
// to another parent. In both cases we don't need to update the configuration now.
@@ -123,14 +136,18 @@
if (mParent == null) {
return;
}
+
if (mSurfaceControl == null) {
// If we don't yet have a surface, but we now have a parent, we should
// build a surface.
mSurfaceControl = makeSurface().build();
getPendingTransaction().show(mSurfaceControl);
} else {
- // If we have a surface but a new parent, we just need to perform a reparent.
- getPendingTransaction().reparent(mSurfaceControl, mParent.mSurfaceControl.getHandle());
+ // If we have a surface but a new parent, we just need to perform a reparent. Go through
+ // surface animator such that hierarchy is preserved when animating, i.e.
+ // mSurfaceControl stays attached to the leash and we just reparent the leash to the
+ // new parent.
+ mSurfaceAnimator.reparent(getPendingTransaction(), mParent.mSurfaceControl);
}
// Either way we need to ask the parent to assign us a Z-order.
@@ -139,8 +156,8 @@
}
// Temp. holders for a chain of containers we are currently processing.
- private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList();
- private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList();
+ private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList<>();
+ private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList<>();
/**
* Adds the input window container has a child of this container in order based on the input
@@ -214,7 +231,7 @@
@CallSuper
void removeImmediately() {
while (!mChildren.isEmpty()) {
- final WindowContainer child = mChildren.peekLast();
+ final E child = mChildren.peekLast();
child.removeImmediately();
// Need to do this after calling remove on the child because the child might try to
// remove/detach itself from its parent which will cause an exception if we remove
@@ -401,16 +418,40 @@
}
}
- boolean isAnimating() {
+ /**
+ * @return Whether our own container is running an animation or any child, no matter how deep in
+ * the hierarchy, is animating.
+ */
+ boolean isSelfOrChildAnimating() {
+ if (isSelfAnimating()) {
+ return true;
+ }
for (int j = mChildren.size() - 1; j >= 0; j--) {
final WindowContainer wc = mChildren.get(j);
- if (wc.isAnimating()) {
+ if (wc.isSelfOrChildAnimating()) {
return true;
}
}
return false;
}
+ /**
+ * @return Whether our own container is running an animation or our parent is animating. This
+ * doesn't consider whether children are animating.
+ */
+ boolean isAnimating() {
+
+ // We are animating if we ourselves are animating or if our parent is animating.
+ return isSelfAnimating() || mParent != null && mParent.isAnimating();
+ }
+
+ /**
+ * @return Whether our own container running an animation at the moment.
+ */
+ boolean isSelfAnimating() {
+ return mSurfaceAnimator.isAnimating();
+ }
+
void sendAppVisibilityToClients() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
@@ -743,6 +784,15 @@
.setParent(mSurfaceControl);
}
+ @Override
+ public SurfaceControl getParentSurfaceControl() {
+ final WindowContainer parent = getParent();
+ if (parent == null) {
+ return null;
+ }
+ return parent.getSurfaceControl();
+ }
+
/**
* @return Whether this WindowContainer should be magnified by the accessibility magnifier.
*/
@@ -765,7 +815,10 @@
void assignLayer(Transaction t, int layer) {
final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
if (mSurfaceControl != null && changed) {
- t.setLayer(mSurfaceControl, layer);
+
+ // Route through surface animator to accommodate that our surface control might be
+ // attached to the leash, and leash is attached to parent container.
+ mSurfaceAnimator.setLayer(t, layer);
mLastLayer = layer;
mLastRelativeToLayer = null;
}
@@ -774,7 +827,10 @@
void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
if (mSurfaceControl != null && changed) {
- t.setRelativeLayer(mSurfaceControl, relativeTo, layer);
+
+ // Route through surface animator to accommodate that our surface control might be
+ // attached to the leash, and leash is attached to parent container.
+ mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
mLastLayer = layer;
mLastRelativeToLayer = relativeTo;
}
@@ -897,7 +953,8 @@
}
}
- SurfaceControl getSurfaceControl() {
+ @Override
+ public SurfaceControl getSurfaceControl() {
return mSurfaceControl;
}
@@ -907,13 +964,105 @@
* rather than an intentional design, so please take care when
* expanding use.
*/
- void destroyAfterPendingTransaction(SurfaceControl surface) {
+ @Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
if (mParent != null) {
mParent.destroyAfterPendingTransaction(surface);
}
}
-
- Transaction getPendingTransaction() {
+
+ @Override
+ public Transaction getPendingTransaction() {
return mPendingTransaction;
}
+
+ /**
+ * Starts an animation on the container.
+ *
+ * @param anim The animation to run.
+ * @param hidden Whether our container is currently hidden. TODO This should use isVisible at
+ * some point but the meaning is too weird to work for all containers.
+ */
+ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
+ if (DEBUG_ANIM) Slog.v(TAG, "Starting animation on " + this + ": " + anim);
+
+ // TODO: This should use isVisible() but because isVisible has a really weird meaning at
+ // the moment this doesn't work for all animatable window containers.
+ mSurfaceAnimator.startAnimation(t, anim, hidden);
+ }
+
+ void cancelAnimation() {
+ mSurfaceAnimator.cancelAnimation();
+ }
+
+ @Override
+ public Builder makeAnimationLeash() {
+ return makeSurface();
+ }
+
+ @Override
+ public void commitPendingTransaction() {
+ scheduleAnimation();
+ }
+
+ private void reassignLayer(Transaction t) {
+ final WindowContainer parent = getParent();
+ if (parent != null) {
+ parent.assignChildLayers(t);
+ }
+ }
+
+ @Override
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+ reassignLayer(t);
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(Transaction t) {
+ reassignLayer(t);
+ }
+
+ /**
+ * Called when an animation has finished running.
+ */
+ protected void onAnimationFinished() {
+ }
+
+ /**
+ * @return The currently running animation, if any, or {@code null} otherwise.
+ */
+ AnimationAdapter getAnimation() {
+ return mSurfaceAnimator.getAnimation();
+ }
+
+ /**
+ * @see SurfaceAnimator#startDelayingAnimationStart
+ */
+ void startDelayingAnimationStart() {
+ mSurfaceAnimator.startDelayingAnimationStart();
+ }
+
+ /**
+ * @see SurfaceAnimator#endDelayingAnimationStart
+ */
+ void endDelayingAnimationStart() {
+ mSurfaceAnimator.endDelayingAnimationStart();
+ }
+
+ @Override
+ public int getSurfaceWidth() {
+ return mSurfaceControl.getWidth();
+ }
+
+ @Override
+ public int getSurfaceHeight() {
+ return mSurfaceControl.getHeight();
+ }
+
+ void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ if (mSurfaceAnimator.isAnimating()) {
+ pw.print(prefix); pw.println("ContainerAnimator:");
+ mSurfaceAnimator.dump(pw, prefix + " ");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8c9948e..7a3ba74 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -725,8 +725,6 @@
}
}
- boolean mAnimateWallpaperWithTarget;
-
// TODO: Move to RootWindowContainer
AppWindowToken mFocusedApp = null;
@@ -2182,18 +2180,15 @@
if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = isDefaultDisplay;
win.mAnimatingExit = true;
- win.mWinAnimator.mAnimating = true;
} else if (win.mWinAnimator.isAnimationSet()) {
// Currently in a hide animation... turn this into
// an exit.
win.mAnimatingExit = true;
- win.mWinAnimator.mAnimating = true;
} else if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
// If the wallpaper is currently behind this
// window, we need to change both of them inside
// of a transaction to avoid artifacts.
win.mAnimatingExit = true;
- win.mWinAnimator.mAnimating = true;
} else {
if (mInputMethodWindow == win) {
setInputMethodWindowLocked(null);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e38605d..6bebcf4 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -19,11 +19,11 @@
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.SurfaceControl.Transaction;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-import static android.view.SurfaceControl.Transaction;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
@@ -91,6 +91,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -160,10 +161,14 @@
import android.view.ViewTreeObserver;
import android.view.WindowInfo;
import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputWindowHandle;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -594,6 +599,8 @@
*/
private boolean mDrawnStateEvaluated;
+ private final Point mSurfacePosition = new Point();
+
/**
* Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
* of z-order and 1 otherwise.
@@ -1470,9 +1477,9 @@
final AppWindowToken atoken = mAppToken;
if (atoken != null) {
return ((!isParentWindowHidden() && !atoken.hiddenRequested)
- || mWinAnimator.mAnimation != null || atoken.mAppAnimator.animation != null);
+ || mWinAnimator.isAnimationSet() || atoken.mAppAnimator.animation != null);
}
- return !isParentWindowHidden() || mWinAnimator.mAnimation != null;
+ return !isParentWindowHidden() || mWinAnimator.isAnimationSet();
}
/**
@@ -1505,7 +1512,7 @@
}
return mHasSurface && mPolicyVisibility && !mDestroying
&& ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.hidden)
- || mWinAnimator.mAnimation != null
+ || mWinAnimator.isAnimationSet()
|| ((mAppToken != null) && (mAppToken.mAppAnimator.animation != null)));
}
@@ -1520,8 +1527,7 @@
// started.
final boolean appAnimationStarting = mAppToken != null
&& mAppToken.mAppAnimator.isAnimationStarting();
- final boolean exitingSelf = mAnimatingExit && (!mWinAnimator.isAnimationStarting()
- && !appAnimationStarting);
+ final boolean exitingSelf = mAnimatingExit && !appAnimationStarting;
final boolean appExiting = mAppToken != null && mAppToken.hidden && !appAnimationStarting;
final boolean exiting = exitingSelf || mDestroying || appExiting;
@@ -1544,7 +1550,7 @@
return isDrawnLw() && mPolicyVisibility
&& ((!isParentWindowHidden() &&
(atoken == null || !atoken.hiddenRequested))
- || mWinAnimator.mAnimating
+ || mWinAnimator.isAnimationSet()
|| (atoken != null && atoken.mAppAnimator.animation != null));
}
@@ -1553,7 +1559,7 @@
*/
@Override
public boolean isAnimatingLw() {
- return mWinAnimator.mAnimation != null
+ return mWinAnimator.isAnimationSet()
|| (mAppToken != null && mAppToken.mAppAnimator.animation != null);
}
@@ -1600,7 +1606,7 @@
// to determine if it's occluding apps.
return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
|| (mIsWallpaper && mWallpaperVisible))
- && isDrawnLw() && mWinAnimator.mAnimation == null
+ && isDrawnLw() && !mWinAnimator.isAnimationSet()
&& (mAppToken == null || mAppToken.mAppAnimator.animation == null);
}
@@ -1732,7 +1738,7 @@
* listeners and optionally animate it. Simply checking a change of position is not enough,
* because being move due to dock divider is not a trigger for animation.
*/
- void handleWindowMovedIfNeeded() {
+ void handleWindowMovedIfNeeded(Transaction t) {
if (!hasMoved()) {
return;
}
@@ -1750,7 +1756,7 @@
&& !isDragResizing() && !adjustedForMinimizedDockOrIme
&& getWindowConfiguration().hasMovementAnimations()
&& !mWinAnimator.mLastHidden) {
- mWinAnimator.setMoveAnimation(left, top);
+ startMoveAnimation(t, left, top);
}
//TODO (multidisplay): Accessibility supported only for the default display.
@@ -2457,10 +2463,10 @@
if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
if (doAnimation) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
- + mPolicyVisibility + " mAnimation=" + mWinAnimator.mAnimation);
+ + mPolicyVisibility + " isAnimationSet=" + mWinAnimator.isAnimationSet());
if (!mToken.okToAnimate()) {
doAnimation = false;
- } else if (mPolicyVisibility && mWinAnimator.mAnimation == null) {
+ } else if (mPolicyVisibility && !mWinAnimator.isAnimationSet()) {
// Check for the case where we are currently visible and
// not animating; we do not want to do animation at such a
// point to become visible when we already are.
@@ -2499,7 +2505,7 @@
}
if (doAnimation) {
mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
- if (mWinAnimator.mAnimation == null) {
+ if (!mWinAnimator.isAnimationSet()) {
doAnimation = false;
}
}
@@ -2599,14 +2605,6 @@
return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
}
- @Override
- boolean isAnimating() {
- if (mWinAnimator.isAnimationSet() || mAnimatingExit) {
- return true;
- }
- return super.isAnimating();
- }
-
void addWinAnimatorToList(ArrayList<WindowStateAnimator> animators) {
animators.add(mWinAnimator);
@@ -3133,6 +3131,7 @@
proto.end(token);
}
+ @Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
final TaskStack stack = getStack();
pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
@@ -3275,6 +3274,7 @@
pw.print(" cutout=" + mLastDisplayCutout);
pw.println();
}
+ super.dump(pw, prefix, dumpAll);
pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
mWinAnimator.dump(pw, prefix + " ", dumpAll);
if (mAnimatingExit || mRemoveOnExit || mDestroying || mRemoved) {
@@ -3333,7 +3333,7 @@
@Override
String getName() {
return Integer.toHexString(System.identityHashCode(this))
- + " " + getWindowTag();
+ + " " + getWindowTag();
}
CharSequence getWindowTag() {
@@ -3694,7 +3694,7 @@
+ " tok.hiddenRequested="
+ (mAppToken != null && mAppToken.hiddenRequested)
+ " tok.hidden=" + (mAppToken != null && mAppToken.hidden)
- + " animating=" + mWinAnimator.mAnimating
+ + " animationSet=" + mWinAnimator.isAnimationSet()
+ " tok animating="
+ (mWinAnimator.mAppAnimator != null && mWinAnimator.mAppAnimator.animating)
+ " Callers=" + Debug.getCallers(4));
@@ -3900,23 +3900,10 @@
return null;
}
- boolean isWindowAnimationSet() {
- if (mWinAnimator.isWindowAnimationSet()) {
- return true;
- }
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- if (c.isWindowAnimationSet()) {
- return true;
- }
- }
- return false;
- }
-
void onExitAnimationDone() {
if (DEBUG_ANIM) Slog.v(TAG, "onExitAnimationDone in " + this
+ ": exiting=" + mAnimatingExit + " remove=" + mRemoveOnExit
- + " windowAnimating=" + mWinAnimator.isWindowAnimationSet());
+ + " selfAnimating=" + isSelfAnimating());
if (!mChildren.isEmpty()) {
// Copying to a different list as multiple children can be removed.
@@ -3940,18 +3927,16 @@
}
}
- if (!mWinAnimator.isWindowAnimationSet()) {
- //TODO (multidisplay): Accessibility is supported only for the default display.
- if (mService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
- mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
- }
- }
-
- if (!mAnimatingExit) {
+ if (isSelfAnimating()) {
return;
}
- if (mWinAnimator.isWindowAnimationSet()) {
+ //TODO (multidisplay): Accessibility is supported only for the default display.
+ if (mService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
+ mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+ }
+
+ if (!mAnimatingExit) {
return;
}
@@ -4005,10 +3990,6 @@
mAnimatingExit = false;
didSomething = true;
}
- if (mWinAnimator.mAnimating) {
- mWinAnimator.mAnimating = false;
- didSomething = true;
- }
if (mDestroying) {
mDestroying = false;
mService.mDestroySurface.remove(this);
@@ -4097,7 +4078,7 @@
+ " mDrawState=" + mWinAnimator.mDrawState
+ " ph=" + isParentWindowHidden()
+ " th=" + (mAppToken != null ? mAppToken.hiddenRequested : false)
- + " a=" + mWinAnimator.mAnimating);
+ + " a=" + mWinAnimator.isAnimationSet());
}
}
@@ -4300,6 +4281,39 @@
mLastDisplayCutout = mDisplayCutout;
}
+ void startAnimation(Animation anim) {
+ final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+ anim.initialize(mFrame.width(), mFrame.height(),
+ displayInfo.appWidth, displayInfo.appHeight);
+ anim.restrictDuration(MAX_ANIMATION_DURATION);
+ anim.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
+ final AnimationAdapter adapter = new LocalAnimationAdapter(
+ new WindowAnimationSpec(anim, mSurfacePosition), mService.mSurfaceAnimationRunner);
+ startAnimation(mPendingTransaction, adapter);
+ commitPendingTransaction();
+ }
+
+ private void startMoveAnimation(Transaction t, int left, int top) {
+ if (DEBUG_ANIM) Slog.v(TAG, "Setting move animation on " + this);
+ final Point oldPosition = new Point();
+ final Point newPosition = new Point();
+ transformFrameToSurfacePosition(mLastFrame.left, mLastFrame.top, oldPosition);
+ transformFrameToSurfacePosition(left, top, newPosition);
+ final AnimationAdapter adapter = new LocalAnimationAdapter(
+ new MoveAnimationSpec(oldPosition.x, oldPosition.y, newPosition.x, newPosition.y),
+ mService.mSurfaceAnimationRunner);
+ startAnimation(t, adapter);
+ }
+
+ private void startAnimation(Transaction t, AnimationAdapter adapter) {
+ startAnimation(t, adapter, mWinAnimator.mLastHidden);
+ }
+
+ @Override
+ protected void onAnimationFinished() {
+ mWinAnimator.onAnimationFinished();
+ }
+
// TODO: Hack to work around the number of states AppWindowToken needs to access without having
// access to its windows children. Need to investigate re-writing
// {@link AppWindowToken#updateReportedVisibilityLocked} so this can be removed.
@@ -4381,11 +4395,6 @@
return getAnimLayerAdjustment() > 0 || mWillReplaceWindow;
}
- @Override
- SurfaceControl.Builder makeSurface() {
- return getParent().makeChildSurface(this);
- }
-
private void applyDims(Dimmer dimmer) {
if (!mAnimatingExit && mAppDied) {
mIsDimming = true;
@@ -4405,11 +4414,51 @@
applyDims(dimmer);
}
+ updateSurfacePosition(mPendingTransaction);
+
mWinAnimator.prepareSurfaceLocked(true);
super.prepareSurfaces();
}
@Override
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+ super.onAnimationLeashCreated(t, leash);
+
+ // Leash is now responsible for position, so set our position to 0.
+ t.setPosition(mSurfaceControl, 0, 0);
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(Transaction t) {
+ super.onAnimationLeashDestroyed(t);
+ updateSurfacePosition(t);
+ }
+
+ void updateSurfacePosition(Transaction t) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+
+ transformFrameToSurfacePosition(mFrame.left, mFrame.top, mSurfacePosition);
+ if (!mSurfaceAnimator.hasLeash()) {
+ t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ }
+ }
+
+ private void transformFrameToSurfacePosition(int left, int top, Point outPoint) {
+ outPoint.set(left, top);
+ if (isChildWindow()) {
+ // TODO: This probably falls apart at some point and we should
+ // actually compute relative coordinates.
+ final WindowState parent = getParentWindow();
+ outPoint.offset(-parent.mFrame.left, -parent.mFrame.top);
+ }
+
+ // Expand for surface insets. See WindowState.expandForSurfaceInsets.
+ outPoint.offset(-mAttrs.surfaceInsets.left, -mAttrs.surfaceInsets.top);
+ }
+
+ @Override
void assignLayer(Transaction t, int layer) {
// See comment in assignRelativeLayerForImeTargetChild
if (!isChildWindow()
@@ -4449,4 +4498,34 @@
layer++;
}
}
+
+ private final class MoveAnimationSpec implements AnimationSpec {
+
+ private final long mDuration;
+ private Interpolator mInterpolator;
+ private Point mFrom = new Point();
+ private Point mTo = new Point();
+
+ private MoveAnimationSpec(int fromX, int fromY, int toX, int toY) {
+ final Animation anim = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.window_move_from_decor);
+ mDuration = anim.computeDurationHint();
+ mInterpolator = anim.getInterpolator();
+ mFrom.set(fromX, fromY);
+ mTo.set(toX, toY);
+ }
+
+ @Override
+ public long getDuration() {
+ return mDuration;
+ }
+
+ @Override
+ public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
+ final float fraction = (float) currentPlayTime / getDuration();
+ final float v = mInterpolator.getInterpolation(fraction);
+ t.setPosition(leash, mFrom.x + (mTo.x - mFrom.x) * v,
+ mFrom.y + (mTo.y - mFrom.y) * v);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 54c84ea..0eabc89 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -23,16 +23,16 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.AppWindowAnimator.sDummyAnimation;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
@@ -40,7 +40,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
-import static com.android.server.wm.WindowManagerService.localLOGV;
import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
@@ -65,14 +64,13 @@
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import com.android.server.policy.WindowManagerPolicy;
-import java.io.PrintWriter;
import java.io.FileDescriptor;
+import java.io.PrintWriter;
/**
* Keep track of animations and surface operations for a single WindowState.
@@ -112,20 +110,9 @@
final boolean mIsWallpaper;
private final WallpaperController mWallpaperControllerLocked;
- // Currently running animation.
- boolean mAnimating;
- boolean mLocalAnimating;
- Animation mAnimation;
boolean mAnimationIsEntrance;
- boolean mHasTransformation;
- boolean mHasLocalTransformation;
- final Transformation mTransformation = new Transformation();
- boolean mWasAnimating; // Were we animating going into the most recent animation step?
int mAnimLayer;
int mLastLayer;
- long mAnimationStartTime;
- long mLastAnimationTime;
- int mStackClip = STACK_CLIP_BEFORE_ANIM;
/**
* Set when we have changed the size of the surface, to know that
@@ -168,13 +155,6 @@
private final Rect mSystemDecorRect = new Rect();
private final Rect mLastSystemDecorRect = new Rect();
- // Used to save animation distances between the time they are calculated and when they are used.
- private int mAnimDx;
- private int mAnimDy;
-
- /** Is the next animation to be started a window move animation? */
- private boolean mAnimateMove = false;
-
float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
private float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
@@ -226,8 +206,6 @@
int mAttrType;
- static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
-
boolean mForceScaleUntilResize;
// WindowState.mHScale and WindowState.mVScale contain the
@@ -247,15 +225,6 @@
mAnimator = service.mAnimator;
mPolicy = service.mPolicy;
mContext = service.mContext;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- mAnimDx = displayInfo.appWidth;
- mAnimDy = displayInfo.appHeight;
- } else {
- Slog.w(TAG, "WindowStateAnimator ctor: Display has been removed");
- // This is checked on return and dealt with.
- }
mWin = win;
mParentWinAnimator = !win.isChildWindow() ? null : win.getParentWindow().mWinAnimator;
@@ -266,54 +235,11 @@
mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
}
- public void setAnimation(Animation anim, long startTime, int stackClip) {
- if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
- mAnimating = false;
- mLocalAnimating = false;
- mAnimation = anim;
- mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
- mAnimation.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
- // Start out animation gone if window is gone, or visible if window is visible.
- mTransformation.clear();
- mTransformation.setAlpha(mLastHidden ? 0 : 1);
- mHasLocalTransformation = true;
- mAnimationStartTime = startTime;
- mStackClip = stackClip;
- }
-
- public void setAnimation(Animation anim, int stackClip) {
- setAnimation(anim, -1, stackClip);
- }
-
- public void setAnimation(Animation anim) {
- setAnimation(anim, -1, STACK_CLIP_AFTER_ANIM);
- }
-
- public void clearAnimation() {
- if (mAnimation != null) {
- mAnimating = true;
- mLocalAnimating = false;
- mAnimation.cancel();
- mAnimation = null;
- mStackClip = STACK_CLIP_BEFORE_ANIM;
- }
- }
-
/**
* Is the window or its container currently set to animate or currently animating?
*/
boolean isAnimationSet() {
- return mAnimation != null
- || (mParentWinAnimator != null && mParentWinAnimator.mAnimation != null)
- || (mAppAnimator != null && mAppAnimator.isAnimating());
- }
-
- /**
- * @return whether an animation is about to start, i.e. the animation is set already but we
- * haven't processed the first frame yet.
- */
- boolean isAnimationStarting() {
- return isAnimationSet() && !mAnimating;
+ return mWin.isAnimating();
}
/** Is the window animating the DummyAnimation? */
@@ -323,13 +249,6 @@
}
/**
- * Is this window currently set to animate or currently animating?
- */
- boolean isWindowAnimationSet() {
- return mAnimation != null;
- }
-
- /**
* Is this window currently waiting to run an opening animation?
*/
boolean isWaitingForOpening() {
@@ -341,130 +260,23 @@
if (DEBUG_ANIM) Slog.d(TAG,
"cancelExitAnimationForNextAnimationLocked: " + mWin);
- if (mAnimation != null) {
- mAnimation.cancel();
- mAnimation = null;
- mLocalAnimating = false;
- mWin.destroySurfaceUnchecked();
- }
+ mWin.cancelAnimation();
+ mWin.destroySurfaceUnchecked();
}
- private boolean stepAnimation(long currentTime) {
- if ((mAnimation == null) || !mLocalAnimating) {
- return false;
- }
- currentTime = getAnimationFrameTime(mAnimation, currentTime);
- mTransformation.clear();
- final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
- if (mAnimationStartDelayed && mAnimationIsEntrance) {
- mTransformation.setAlpha(0f);
- }
- if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
- + ", xform=" + mTransformation);
- return more;
- }
-
- // This must be called while inside a transaction. Returns true if
- // there is more animation to run.
- boolean stepAnimationLocked(long currentTime) {
- // Save the animation state as it was before this step so WindowManagerService can tell if
- // we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
- mWasAnimating = mAnimating;
- final DisplayContent displayContent = mWin.getDisplayContent();
- if (mWin.mToken.okToAnimate()) {
- // We will run animations as long as the display isn't frozen.
-
- if (mWin.isDrawnLw() && mAnimation != null) {
- mHasTransformation = true;
- mHasLocalTransformation = true;
- if (!mLocalAnimating) {
- if (DEBUG_ANIM) Slog.v(
- TAG, "Starting animation in " + this +
- " @ " + currentTime + ": ww=" + mWin.mFrame.width() +
- " wh=" + mWin.mFrame.height() +
- " dx=" + mAnimDx + " dy=" + mAnimDy +
- " scale=" + mService.getWindowAnimationScaleLocked());
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- if (mAnimateMove) {
- mAnimateMove = false;
- mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
- mAnimDx, mAnimDy);
- } else {
- mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
- displayInfo.appWidth, displayInfo.appHeight);
- }
- mAnimDx = displayInfo.appWidth;
- mAnimDy = displayInfo.appHeight;
- mAnimation.setStartTime(mAnimationStartTime != -1
- ? mAnimationStartTime
- : currentTime);
- mLocalAnimating = true;
- mAnimating = true;
- }
- if ((mAnimation != null) && mLocalAnimating) {
- mLastAnimationTime = currentTime;
- if (stepAnimation(currentTime)) {
- return true;
- }
- }
- if (DEBUG_ANIM) Slog.v(
- TAG, "Finished animation in " + this +
- " @ " + currentTime);
- //WindowManagerService.this.dump();
- }
- mHasLocalTransformation = false;
- if ((!mLocalAnimating || mAnimationIsEntrance) && mAppAnimator != null
- && mAppAnimator.animation != null) {
- // When our app token is animating, we kind-of pretend like
- // we are as well. Note the mLocalAnimating mAnimationIsEntrance
- // part of this check means that we will only do this if
- // our window is not currently exiting, or it is not
- // locally animating itself. The idea being that one that
- // is exiting and doing a local animation should be removed
- // once that animation is done.
- mAnimating = true;
- mHasTransformation = true;
- mTransformation.clear();
- return false;
- } else if (mHasTransformation) {
- // Little trick to get through the path below to act like
- // we have finished an animation.
- mAnimating = true;
- } else if (isAnimationSet()) {
- mAnimating = true;
- }
- } else if (mAnimation != null) {
- // If the display is frozen, and there is a pending animation,
- // clear it and make sure we run the cleanup code.
- mAnimating = true;
- }
-
- if (!mAnimating && !mLocalAnimating) {
- return false;
- }
-
+ void onAnimationFinished() {
// Done animating, clean up.
if (DEBUG_ANIM) Slog.v(
- TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
- + ", reportedVisible="
- + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
+ TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
+ + ", reportedVisible="
+ + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
- mAnimating = false;
- mLocalAnimating = false;
- if (mAnimation != null) {
- mAnimation.cancel();
- mAnimation = null;
- }
if (mAnimator.mWindowDetachedWallpaper == mWin) {
mAnimator.mWindowDetachedWallpaper = null;
}
- mAnimLayer = mWin.getSpecialWindowAnimLayerAdjustment();
- if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
- mHasTransformation = false;
- mHasLocalTransformation = false;
- mStackClip = STACK_CLIP_BEFORE_ANIM;
+
mWin.checkPolicyVisibilityChange();
- mTransformation.clear();
+ final DisplayContent displayContent = mWin.getDisplayContent();
if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
// Upon completion of a not-visible to visible status bar animation a relayout is
// required.
@@ -475,7 +287,11 @@
mWin.onExitAnimationDone();
final int displayId = mWin.getDisplayId();
- mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
+ int pendingLayoutChanges = FINISH_LAYOUT_REDO_ANIM;
+ if (displayContent.mWallpaperController.isWallpaperTarget(mWin)) {
+ pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ }
+ mAnimator.setPendingLayoutChanges(displayId, pendingLayoutChanges);
if (DEBUG_LAYOUT_REPEATS)
mService.mWindowPlacerLocked.debugLayoutRepeats(
"WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
@@ -483,8 +299,6 @@
if (mWin.mAppToken != null) {
mWin.mAppToken.updateReportedVisibilityLocked();
}
-
- return false;
}
void hide(String reason) {
@@ -683,8 +497,8 @@
}
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
- attrs.getTitle().toString(),
- width, height, format, flags, this, windowType, ownerUid);
+ attrs.getTitle().toString(), width, height, format, flags, this,
+ windowType, ownerUid);
mSurfaceFormat = format;
w.setHasSurface(true);
@@ -853,35 +667,8 @@
}
void computeShownFrameLocked() {
- final boolean selfTransformation = mHasLocalTransformation;
Transformation appTransformation = (mAppAnimator != null && mAppAnimator.hasTransformation)
? mAppAnimator.transformation : null;
- Transformation wallpaperTargetTransformation = null;
-
- // Wallpapers are animated based on the "real" window they
- // are currently targeting.
- final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
- if (mIsWallpaper && wallpaperTarget != null && mService.mAnimateWallpaperWithTarget) {
- final WindowStateAnimator wallpaperAnimator = wallpaperTarget.mWinAnimator;
- if (wallpaperAnimator.mHasLocalTransformation &&
- wallpaperAnimator.mAnimation != null &&
- !wallpaperAnimator.mAnimation.getDetachWallpaper()) {
- wallpaperTargetTransformation = wallpaperAnimator.mTransformation;
- if (DEBUG_WALLPAPER && wallpaperTargetTransformation != null) {
- Slog.v(TAG, "WP target attached xform: " + wallpaperTargetTransformation);
- }
- }
- final AppWindowAnimator wpAppAnimator = wallpaperTarget.mAppToken == null ?
- null : wallpaperTarget.mAppToken.mAppAnimator;
- if (wpAppAnimator != null && wpAppAnimator.hasTransformation
- && wpAppAnimator.animation != null
- && !wpAppAnimator.animation.getDetachWallpaper()) {
- appTransformation = wpAppAnimator.transformation;
- if (DEBUG_WALLPAPER && appTransformation != null) {
- Slog.v(TAG, "WP target app xform: " + appTransformation);
- }
- }
- }
final int displayId = mWin.getDisplayId();
final ScreenRotationAnimation screenRotationAnimation =
@@ -890,8 +677,7 @@
screenRotationAnimation != null && screenRotationAnimation.isAnimating();
mHasClipRect = false;
- if (selfTransformation || wallpaperTargetTransformation != null
- || appTransformation != null || screenAnimation) {
+ if (appTransformation != null || screenAnimation) {
// cache often used attributes locally
final Rect frame = mWin.mFrame;
final float tmpFloats[] = mService.mTmpFloats;
@@ -917,34 +703,16 @@
tmpMatrix.reset();
}
tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
- if (selfTransformation) {
- tmpMatrix.postConcat(mTransformation.getMatrix());
- }
- if (wallpaperTargetTransformation != null) {
- tmpMatrix.postConcat(wallpaperTargetTransformation.getMatrix());
- }
+ // WindowState.prepareSurfaces expands for surface insets (in order they don't get
+ // clipped by the WindowState surface), so we need to go into the other direction here.
+ tmpMatrix.postTranslate(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
+ mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
+
if (appTransformation != null) {
tmpMatrix.postConcat(appTransformation.getMatrix());
}
- int left = frame.left;
- int top = frame.top;
- if (mWin.isChildWindow()) {
- WindowState parent = mWin.getParentWindow();
- left -= parent.mFrame.left;
- top -= parent.mFrame.top;
- }
-
- // The translation that applies the position of the window needs to be applied at the
- // end in case that other translations include scaling. Otherwise the scaling will
- // affect this translation. But it needs to be set before the screen rotation animation
- // so the pivot point is at the center of the screen for all windows.
- tmpMatrix.postTranslate(left + mWin.mXOffset, top + mWin.mYOffset);
- if (screenAnimation) {
- tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
- }
-
// "convert" it into SurfaceFlinger's format
// (a 2x2 matrix + an offset)
// Here we must not transform the position of the surface
@@ -972,12 +740,6 @@
|| (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
&& x == frame.left && y == frame.top))) {
//Slog.i(TAG_WM, "Applying alpha transform");
- if (selfTransformation) {
- mShownAlpha *= mTransformation.getAlpha();
- }
- if (wallpaperTargetTransformation != null) {
- mShownAlpha *= wallpaperTargetTransformation.getAlpha();
- }
if (appTransformation != null) {
mShownAlpha *= appTransformation.getAlpha();
if (appTransformation.hasClipRect()) {
@@ -1006,9 +768,6 @@
if ((DEBUG_ANIM || WindowManagerService.localLOGV)
&& (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
- + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
- + " attached=" + (wallpaperTargetTransformation == null ?
- "null" : wallpaperTargetTransformation.getAlpha())
+ " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())
+ " screen=" + (screenAnimation ?
screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
@@ -1028,10 +787,10 @@
TAG, "computeShownFrameLocked: " + this +
" not attached, mAlpha=" + mAlpha);
- mWin.mShownPosition.set(mWin.mFrame.left, mWin.mFrame.top);
- if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
- mWin.mShownPosition.offset(mWin.mXOffset, mWin.mYOffset);
- }
+ // WindowState.prepareSurfaces expands for surface insets (in order they don't get
+ // clipped by the WindowState surface), so we need to go into the other direction here.
+ mWin.mShownPosition.set(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
+ mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
mShownAlpha = mAlpha;
mHaveMatrix = false;
mDsDx = mWin.mGlobalScale;
@@ -1182,7 +941,7 @@
if (mAppAnimator != null && mAppAnimator.animation != null) {
return mAppAnimator.getStackClip();
} else {
- return mStackClip;
+ return STACK_CLIP_AFTER_ANIM;
}
}
@@ -1434,7 +1193,7 @@
if (mSurfaceResized) {
mReportSurfaceResized = true;
mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
+ FINISH_LAYOUT_REDO_WALLPAPER);
}
}
@@ -1546,7 +1305,7 @@
// Run another pass through performLayout to set mHasContent in the
// LogicalDisplay.
mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
+ FINISH_LAYOUT_REDO_ANIM);
} else {
w.setOrientationChanging(false);
}
@@ -1720,12 +1479,18 @@
* @return true if an animation has been loaded.
*/
boolean applyAnimationLocked(int transit, boolean isEntrance) {
- if (mLocalAnimating && mAnimationIsEntrance == isEntrance) {
+ if (mWin.isSelfAnimating() && mAnimationIsEntrance == isEntrance) {
// If we are trying to apply an animation, but already running
// an animation of the same type, then just leave that one alone.
return true;
}
+ if (isEntrance && mWin.mAttrs.type == TYPE_INPUT_METHOD) {
+ mWin.getDisplayContent().adjustForImeIfNeeded();
+ mWin.setDisplayLayoutNeeded();
+ mService.mWindowPlacerLocked.requestTraversal();
+ }
+
// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
@@ -1764,44 +1529,19 @@
+ " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
if (a != null) {
if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
- setAnimation(a);
+ mWin.startAnimation(a);
mAnimationIsEntrance = isEntrance;
}
} else {
- clearAnimation();
+ mWin.cancelAnimation();
}
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
+ if (!isEntrance && mWin.mAttrs.type == TYPE_INPUT_METHOD) {
mWin.getDisplayContent().adjustForImeIfNeeded();
- if (isEntrance) {
- mWin.setDisplayLayoutNeeded();
- mService.mWindowPlacerLocked.requestTraversal();
- }
}
- return mAnimation != null;
- }
- private void applyFadeoutDuringKeyguardExitAnimation() {
- long startTime = mAnimation.getStartTime();
- long duration = mAnimation.getDuration();
- long elapsed = mLastAnimationTime - startTime;
- long fadeDuration = duration - elapsed;
- if (fadeDuration <= 0) {
- // Never mind, this would be no visible animation, so abort the animation change.
- return;
- }
- AnimationSet newAnimation = new AnimationSet(false /* shareInterpolator */);
- newAnimation.setDuration(duration);
- newAnimation.setStartTime(startTime);
- newAnimation.addAnimation(mAnimation);
- Animation fadeOut = AnimationUtils.loadAnimation(
- mContext, com.android.internal.R.anim.app_starting_exit);
- fadeOut.setDuration(fadeDuration);
- fadeOut.setStartOffset(elapsed);
- newAnimation.addAnimation(fadeOut);
- newAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mAnimDx, mAnimDy);
- mAnimation = newAnimation;
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ return isAnimationSet();
}
void writeToProto(ProtoOutputStream proto, long fieldId) {
@@ -1814,20 +1554,8 @@
}
public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
- if (mAnimating || mLocalAnimating || mAnimationIsEntrance
- || mAnimation != null) {
- pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
- pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
- pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
- pw.print(" mAnimation="); pw.print(mAnimation);
- pw.print(" mStackClip="); pw.println(mStackClip);
- }
- if (mHasTransformation || mHasLocalTransformation) {
- pw.print(prefix); pw.print("XForm: has=");
- pw.print(mHasTransformation);
- pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
- pw.print(" "); mTransformation.printShortString(pw);
- pw.println();
+ if (mAnimationIsEntrance) {
+ pw.print(prefix); pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
}
if (mSurfaceController != null) {
mSurfaceController.dump(pw, prefix, dumpAll);
@@ -1907,44 +1635,6 @@
}
}
- void setMoveAnimation(int left, int top) {
- final Animation a = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.window_move_from_decor);
- setAnimation(a);
- mAnimDx = mWin.mLastFrame.left - left;
- mAnimDy = mWin.mLastFrame.top - top;
- mAnimateMove = true;
- }
-
- void deferTransactionUntilParentFrame(long frameNumber) {
- if (!mWin.isChildWindow()) {
- return;
- }
- mSurfaceController.deferTransactionUntil(
- mWin.getParentWindow().mWinAnimator.mSurfaceController.getHandle(), frameNumber);
- }
-
- /**
- * Sometimes we need to synchronize the first frame of animation with some external event.
- * To achieve this, we prolong the start of the animation and keep producing the first frame of
- * the animation.
- */
- private long getAnimationFrameTime(Animation animation, long currentTime) {
- if (mAnimationStartDelayed) {
- animation.setStartTime(currentTime);
- return currentTime + 1;
- }
- return currentTime;
- }
-
- void startDelayingAnimationStart() {
- mAnimationStartDelayed = true;
- }
-
- void endDelayingAnimationStart() {
- mAnimationStartDelayed = false;
- }
-
void seamlesslyRotateWindow(int oldRotation, int newRotation) {
final WindowState w = mWin;
if (!w.isVisibleNow() || w.mIsWallpaper) {
@@ -2026,4 +1716,8 @@
mSurfaceController.detachChildren();
}
}
+
+ int getLayer() {
+ return mLastLayer;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 6746754..e26a362 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -59,8 +59,8 @@
private boolean mSurfaceShown = false;
private float mSurfaceX = 0;
private float mSurfaceY = 0;
- private float mSurfaceW = 0;
- private float mSurfaceH = 0;
+ private int mSurfaceW = 0;
+ private int mSurfaceH = 0;
// Initialize to the identity matrix.
private float mLastDsdx = 1;
@@ -517,11 +517,11 @@
return mSurfaceY;
}
- float getWidth() {
+ int getWidth() {
return mSurfaceW;
}
- float getHeight() {
+ int getHeight() {
return mSurfaceH;
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 169d0a3..d8e7457 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -462,6 +462,7 @@
appAnimator.setNullAnimation();
// TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
// animating?
+ wtoken.setAllAppWinAnimators();
wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
wtoken.updateReportedVisibilityLocked();
// setAllAppWinAnimators so the windows get onExitAnimationDone once the animation is
@@ -606,7 +607,7 @@
+ ", oldWallpaper=" + oldWallpaper
+ ", openingApps=" + openingApps
+ ", closingApps=" + closingApps);
- mService.mAnimateWallpaperWithTarget = false;
+
if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
@@ -645,8 +646,6 @@
transit = TRANSIT_WALLPAPER_OPEN;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
+ AppTransition.appTransitionToString(transit));
- } else {
- mService.mAnimateWallpaperWithTarget = true;
}
}
return transit;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 84cfabe..9163037 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -17,6 +17,7 @@
import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
+import android.os.PersistableBundle;
import com.android.internal.R;
import com.android.server.SystemService;
@@ -57,4 +58,6 @@
abstract void handleStopUser(int userId);
public void setSystemSetting(ComponentName who, String setting, String value){}
+
+ public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) {}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7ee047b..2080b72 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -751,7 +751,7 @@
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled";
- final DeviceAdminInfo info;
+ DeviceAdminInfo info;
static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
@@ -1402,6 +1402,13 @@
return userRestrictions;
}
+ public void transfer(DeviceAdminInfo deviceAdminInfo) {
+ if (hasParentActiveAdmin()) {
+ parentAdmin.info = deviceAdminInfo;
+ }
+ info = deviceAdminInfo;
+ }
+
void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("uid="); pw.println(getUid());
pw.print(prefix); pw.print("testOnlyAdmin=");
@@ -2541,7 +2548,7 @@
public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle,
- boolean throwForMissiongPermission) {
+ boolean throwForMissingPermission) {
if (!mHasFeature) {
return null;
}
@@ -2564,7 +2571,7 @@
final String message = "DeviceAdminReceiver " + adminName + " must be protected with "
+ permission.BIND_DEVICE_ADMIN;
Slog.w(LOG_TAG, message);
- if (throwForMissiongPermission &&
+ if (throwForMissingPermission &&
ai.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) {
throw new IllegalArgumentException(message);
}
@@ -2889,7 +2896,7 @@
try {
DeviceAdminInfo dai = findAdmin(
ComponentName.unflattenFromString(name), userHandle,
- /* throwForMissionPermission= */ false);
+ /* throwForMissingPermission= */ false);
if (VERBOSE_LOG
&& (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
!= userHandle)) {
@@ -3293,19 +3300,9 @@
DevicePolicyData policy = getUserData(userHandle);
DeviceAdminInfo info = findAdmin(adminReceiver, userHandle,
- /* throwForMissionPermission= */ true);
- if (info == null) {
- throw new IllegalArgumentException("Bad admin: " + adminReceiver);
- }
- if (!info.getActivityInfo().applicationInfo.isInternal()) {
- throw new IllegalArgumentException("Only apps in internal storage can be active admin: "
- + adminReceiver);
- }
- if (info.getActivityInfo().applicationInfo.isInstantApp()) {
- throw new IllegalArgumentException("Instant apps cannot be device admins: "
- + adminReceiver);
- }
+ /* throwForMissingPermission= */ true);
synchronized (this) {
+ checkActiveAdminPrecondition(adminReceiver, info, policy);
long ident = mInjector.binderClearCallingIdentity();
try {
final ActiveAdmin existingAdmin
@@ -3313,10 +3310,6 @@
if (!refreshing && existingAdmin != null) {
throw new IllegalArgumentException("Admin is already added");
}
- if (policy.mRemovingAdmins.contains(adminReceiver)) {
- throw new IllegalArgumentException(
- "Trying to set an admin which is being removed");
- }
ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);
newAdmin.testOnlyAdmin =
(existingAdmin != null) ? existingAdmin.testOnlyAdmin
@@ -3346,6 +3339,46 @@
}
}
+ private void transferActiveAdminUncheckedLocked(ComponentName incomingReceiver,
+ ComponentName outgoingReceiver, int userHandle) {
+ final DevicePolicyData policy = getUserData(userHandle);
+ final DeviceAdminInfo incomingDeviceInfo = findAdmin(incomingReceiver, userHandle,
+ /* throwForMissingPermission= */ true);
+ final ActiveAdmin adminToTransfer = policy.mAdminMap.get(outgoingReceiver);
+ final int oldAdminUid = adminToTransfer.getUid();
+
+ adminToTransfer.transfer(incomingDeviceInfo);
+ policy.mAdminMap.remove(outgoingReceiver);
+ policy.mAdminMap.put(incomingReceiver, adminToTransfer);
+ if (policy.mPasswordOwner == oldAdminUid) {
+ policy.mPasswordOwner = adminToTransfer.getUid();
+ }
+
+ saveSettingsLocked(userHandle);
+ //TODO: Make sure we revert back when we detect a failure.
+ sendAdminCommandLocked(adminToTransfer, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
+ null, null);
+ }
+
+ private void checkActiveAdminPrecondition(ComponentName adminReceiver, DeviceAdminInfo info,
+ DevicePolicyData policy) {
+ if (info == null) {
+ throw new IllegalArgumentException("Bad admin: " + adminReceiver);
+ }
+ if (!info.getActivityInfo().applicationInfo.isInternal()) {
+ throw new IllegalArgumentException("Only apps in internal storage can be active admin: "
+ + adminReceiver);
+ }
+ if (info.getActivityInfo().applicationInfo.isInstantApp()) {
+ throw new IllegalArgumentException("Instant apps cannot be device admins: "
+ + adminReceiver);
+ }
+ if (policy.mRemovingAdmins.contains(adminReceiver)) {
+ throw new IllegalArgumentException(
+ "Trying to set an admin which is being removed");
+ }
+ }
+
@Override
public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
if (!mHasFeature) {
@@ -11538,4 +11571,60 @@
return new ArrayList<>(
mOverlayPackagesProvider.getNonRequiredApps(admin, userId, provisioningAction));
}
+
+ //TODO: Add callback information to the javadoc once it is completed.
+ //TODO: Make transferOwner atomic.
+ @Override
+ public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) {
+ if (!mHasFeature) {
+ return;
+ }
+
+ Preconditions.checkNotNull(admin, "Admin cannot be null.");
+ Preconditions.checkNotNull(target, "Target cannot be null.");
+
+ enforceProfileOrDeviceOwner(admin);
+
+ if (admin.equals(target)) {
+ throw new IllegalArgumentException("Provided administrator and target are "
+ + "the same object.");
+ }
+
+ if (admin.getPackageName().equals(target.getPackageName())) {
+ throw new IllegalArgumentException("Provided administrator and target have "
+ + "the same package name.");
+ }
+
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final DevicePolicyData policy = getUserData(callingUserId);
+ final DeviceAdminInfo incomingDeviceInfo = findAdmin(target, callingUserId,
+ /* throwForMissingPermission= */ true);
+ checkActiveAdminPrecondition(target, incomingDeviceInfo, policy);
+
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ //STOPSHIP add support for COMP, DO, edge cases when device is rebooted/work mode off,
+ //transfer callbacks and broadcast
+ if (isProfileOwner(admin, callingUserId)) {
+ transferProfileOwner(admin, target, callingUserId);
+ }
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+
+ /**
+ * Transfers the profile owner for user with id profileOwnerUserId from admin to target.
+ */
+ private void transferProfileOwner(ComponentName admin, ComponentName target,
+ int profileOwnerUserId) {
+ synchronized (this) {
+ transferActiveAdminUncheckedLocked(target, admin, profileOwnerUserId);
+ mOwners.transferProfileOwner(target, profileOwnerUserId);
+ Slog.i(LOG_TAG, "Profile owner set: " + target + " on user " + profileOwnerUserId);
+ mOwners.writeProfileOwner(profileOwnerUserId);
+ mDeviceAdminServiceController.startServiceForOwner(
+ target.getPackageName(), profileOwnerUserId, "transfer-profile-owner");
+ }
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index a5500dd..9042a8d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -277,6 +277,17 @@
}
}
+ void transferProfileOwner(ComponentName target, int userId) {
+ synchronized (mLock) {
+ final OwnerInfo ownerInfo = mProfileOwners.get(userId);
+ final OwnerInfo newOwnerInfo = new OwnerInfo(target.getPackageName(), target,
+ ownerInfo.userRestrictionsMigrated, ownerInfo.remoteBugreportUri,
+ ownerInfo.remoteBugreportHash);
+ mProfileOwners.put(userId, newOwnerInfo);
+ pushToPackageManagerLocked();
+ }
+ }
+
ComponentName getProfileOwnerComponent(int userId) {
synchronized (mLock) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 114929c..b5e4af7 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -40,15 +40,15 @@
# Include the testing libraries (JUnit4 + Robolectric libs).
LOCAL_STATIC_JAVA_LIBRARIES := \
+ platform-robolectric-android-all-stubs \
android-support-test \
mockito-robolectric-prebuilt \
platform-test-annotations \
truth-prebuilt
-# TODO(b/69254249): Migrate to Robolectric 3.4.2
LOCAL_JAVA_LIBRARIES := \
junit \
- platform-robolectric-3.1.1-prebuilt
+ platform-robolectric-3.5.1-prebuilt
LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
LOCAL_MODULE := FrameworksServicesRoboTests
@@ -73,5 +73,4 @@
LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))backup/java
-# TODO(b/69254249): Migrate to Robolectric 3.4.2
-include prebuilts/misc/common/robolectric/3.1.1/run_robotests.mk
+include prebuilts/misc/common/robolectric/3.5.1/run_robotests.mk
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index 3d5851f..2cb4a69 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
+import static org.robolectric.shadow.api.Shadow.extract;
import android.app.backup.BackupManager;
import android.content.ComponentName;
@@ -31,24 +32,25 @@
import android.platform.test.annotations.Presubmit;
import com.android.server.backup.testing.BackupTransportStub;
-import com.android.server.backup.testing.DefaultPackageManagerWithQueryIntentServicesAsUser;
import com.android.server.backup.testing.ShadowBackupTransportStub;
import com.android.server.backup.testing.ShadowContextImplForBackup;
+import com.android.server.backup.testing.ShadowPackageManagerForBackup;
import com.android.server.backup.testing.TransportBoundListenerStub;
import com.android.server.backup.testing.TransportReadyCallbackStub;
import com.android.server.backup.transport.TransportClient;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderClasses;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import org.robolectric.res.builder.RobolectricPackageManager;
import org.robolectric.shadows.ShadowLog;
import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.shadows.ShadowPackageManager;
import java.util.ArrayList;
import java.util.Arrays;
@@ -56,15 +58,17 @@
import java.util.HashSet;
import java.util.List;
-@RunWith(RobolectricTestRunner.class)
+@RunWith(FrameworkRobolectricTestRunner.class)
@Config(
manifest = Config.NONE,
- sdk = 23,
+ sdk = 26,
shadows = {
ShadowContextImplForBackup.class,
- ShadowBackupTransportStub.class
+ ShadowBackupTransportStub.class,
+ ShadowPackageManagerForBackup.class
}
)
+@SystemLoaderClasses({TransportManager.class})
@Presubmit
public class TransportManagerTest {
private static final String PACKAGE_NAME = "some.package.name";
@@ -73,7 +77,7 @@
private TransportInfo mTransport1;
private TransportInfo mTransport2;
- private RobolectricPackageManager mPackageManager;
+ private ShadowPackageManager mPackageManagerShadow;
private final TransportBoundListenerStub mTransportBoundListenerStub =
new TransportBoundListenerStub(true);
@@ -86,9 +90,10 @@
MockitoAnnotations.initMocks(this);
ShadowLog.stream = System.out;
- mPackageManager = new DefaultPackageManagerWithQueryIntentServicesAsUser(
- RuntimeEnvironment.getAppResourceLoader());
- RuntimeEnvironment.setRobolectricPackageManager(mPackageManager);
+
+ mPackageManagerShadow =
+ (ShadowPackageManagerForBackup)
+ extract(RuntimeEnvironment.application.getPackageManager());
mTransport1 = new TransportInfo(PACKAGE_NAME, "transport1.name");
mTransport2 = new TransportInfo(PACKAGE_NAME, "transport2.name");
@@ -532,6 +537,18 @@
assertThat(transportName).isEqualTo("newName");
}
+ @Test
+ public void isTransportRegistered_returnsCorrectly() throws Exception {
+ TransportManager transportManager =
+ createTransportManagerAndSetUpTransports(
+ Collections.singletonList(mTransport1),
+ Collections.singletonList(mTransport2),
+ mTransport1.name);
+
+ assertThat(transportManager.isTransportRegistered(mTransport1.name)).isTrue();
+ assertThat(transportManager.isTransportRegistered(mTransport2.name)).isFalse();
+ }
+
private void setUpPackageWithTransports(String packageName, List<TransportInfo> transports,
int flags) throws Exception {
PackageInfo packageInfo = new PackageInfo();
@@ -539,7 +556,7 @@
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.privateFlags = flags;
- mPackageManager.addPackage(packageInfo);
+ mPackageManagerShadow.addPackage(packageInfo);
List<ResolveInfo> transportsInfo = new ArrayList<>();
for (TransportInfo transport : transports) {
@@ -553,7 +570,7 @@
Intent intent = new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST);
intent.setPackage(packageName);
- mPackageManager.addResolveInfoForIntent(intent, transportsInfo);
+ mPackageManagerShadow.addResolveInfoForIntent(intent, transportsInfo);
}
private TransportManager createTransportManagerAndSetUpTransports(
diff --git a/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java b/services/robotests/src/com/android/server/backup/testing/ShadowPackageManagerForBackup.java
similarity index 69%
rename from services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java
rename to services/robotests/src/com/android/server/backup/testing/ShadowPackageManagerForBackup.java
index 5a0967b..b64b59d 100644
--- a/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java
+++ b/services/robotests/src/com/android/server/backup/testing/ShadowPackageManagerForBackup.java
@@ -16,28 +16,22 @@
package com.android.server.backup.testing;
+import android.app.ApplicationPackageManager;
import android.content.Intent;
import android.content.pm.ResolveInfo;
-import org.robolectric.res.ResourceLoader;
-import org.robolectric.res.builder.DefaultPackageManager;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowApplicationPackageManager;
import java.util.List;
/**
* Implementation of PackageManager for Robolectric which handles queryIntentServicesAsUser().
*/
-public class DefaultPackageManagerWithQueryIntentServicesAsUser extends
- DefaultPackageManager {
-
- /* package */
- public DefaultPackageManagerWithQueryIntentServicesAsUser(
- ResourceLoader appResourceLoader) {
- super(appResourceLoader);
- }
-
+@Implements(value = ApplicationPackageManager.class, inheritImplementationMethods = true)
+public class ShadowPackageManagerForBackup extends ShadowApplicationPackageManager {
@Override
public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
- return super.queryIntentServices(intent, flags);
+ return queryIntentServices(intent, flags);
}
}
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
index 4a3277f..4462d2a 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
@@ -17,6 +17,7 @@
package com.android.server.backup.transport;
import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -37,31 +38,34 @@
import android.platform.test.annotations.Presubmit;
import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.TransportManager;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderClasses;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE, sdk = 23)
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderClasses({TransportManager.class, TransportClient.class})
@Presubmit
public class TransportClientTest {
private static final String PACKAGE_NAME = "some.package.name";
- private static final ComponentName TRANSPORT_COMPONENT =
- new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport");
- private static final String TRANSPORT_DIR_NAME = TRANSPORT_COMPONENT.toString();
@Mock private Context mContext;
@Mock private TransportConnectionListener mTransportConnectionListener;
@Mock private TransportConnectionListener mTransportConnectionListener2;
@Mock private IBackupTransport.Stub mIBackupTransport;
private TransportClient mTransportClient;
+ private ComponentName mTransportComponent;
+ private String mTransportDirName;
private Intent mBindIntent;
private ShadowLooper mShadowLooper;
@@ -71,13 +75,16 @@
Looper mainLooper = Looper.getMainLooper();
mShadowLooper = shadowOf(mainLooper);
- mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(TRANSPORT_COMPONENT);
+ mTransportComponent =
+ new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport");
+ mTransportDirName = mTransportComponent.toString();
+ mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
mTransportClient =
new TransportClient(
mContext,
mBindIntent,
- TRANSPORT_COMPONENT,
- TRANSPORT_DIR_NAME,
+ mTransportComponent,
+ mTransportDirName,
"1",
new Handler(mainLooper));
@@ -91,12 +98,12 @@
@Test
public void testGetTransportDirName_returnsTransportDirName() {
- assertThat(mTransportClient.getTransportDirName()).isEqualTo(TRANSPORT_DIR_NAME);
+ assertThat(mTransportClient.getTransportDirName()).isEqualTo(mTransportDirName);
}
@Test
public void testGetTransportComponent_returnsTransportComponent() {
- assertThat(mTransportClient.getTransportComponent()).isEqualTo(TRANSPORT_COMPONENT);
+ assertThat(mTransportClient.getTransportComponent()).isEqualTo(mTransportComponent);
}
@Test
@@ -117,7 +124,7 @@
// Simulate framework connecting
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
mShadowLooper.runToEndOfTasks();
verify(mTransportConnectionListener)
@@ -132,7 +139,7 @@
mTransportClient.connectAsync(mTransportConnectionListener2, "caller2");
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
mShadowLooper.runToEndOfTasks();
verify(mTransportConnectionListener)
@@ -145,7 +152,7 @@
public void testConnectAsync_whenAlreadyConnected_callsListener() throws Exception {
mTransportClient.connectAsync(mTransportConnectionListener, "caller1");
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
mTransportClient.connectAsync(mTransportConnectionListener2, "caller2");
@@ -190,8 +197,8 @@
throws Exception {
mTransportClient.connectAsync(mTransportConnectionListener, "caller1");
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
- connection.onServiceDisconnected(TRANSPORT_COMPONENT);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
+ connection.onServiceDisconnected(mTransportComponent);
mTransportClient.connectAsync(mTransportConnectionListener2, "caller1");
@@ -204,9 +211,9 @@
throws Exception {
mTransportClient.connectAsync(mTransportConnectionListener, "caller1");
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
- connection.onServiceDisconnected(TRANSPORT_COMPONENT);
- connection.onServiceConnected(TRANSPORT_COMPONENT, mIBackupTransport);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
+ connection.onServiceDisconnected(mTransportComponent);
+ connection.onServiceConnected(mTransportComponent, mIBackupTransport);
mTransportClient.connectAsync(mTransportConnectionListener2, "caller1");
@@ -221,7 +228,7 @@
mTransportClient.connectAsync(mTransportListener, "caller");
ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext);
- connection.onBindingDied(TRANSPORT_COMPONENT);
+ connection.onBindingDied(mTransportComponent);
mShadowLooper.runToEndOfTasks();
verify(mTransportListener).onTransportBound(isNull(), eq(mTransportClient));
@@ -235,7 +242,7 @@
mTransportClient.connectAsync(mTransportListener2, "caller2");
- connection.onBindingDied(TRANSPORT_COMPONENT);
+ connection.onBindingDied(mTransportComponent);
mShadowLooper.runToEndOfTasks();
verify(mTransportListener).onTransportBound(isNull(), eq(mTransportClient));
diff --git a/services/robotests/src/com/android/server/testing/FrameworkRobolectricTestRunner.java b/services/robotests/src/com/android/server/testing/FrameworkRobolectricTestRunner.java
new file mode 100644
index 0000000..78ac4ed
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/FrameworkRobolectricTestRunner.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 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.testing;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.internal.SandboxFactory;
+import org.robolectric.internal.SdkEnvironment;
+import org.robolectric.internal.bytecode.InstrumentationConfiguration;
+import org.robolectric.internal.bytecode.SandboxClassLoader;
+import org.robolectric.util.Util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+/**
+ * HACK
+ * Robolectric loads up Android environment from prebuilt android jars before running a method.
+ * These jars are versioned according to the SDK level configured for the method (or class). The
+ * jars represent a snapshot of the Android APIs in that SDK level. For Robolectric tests that are
+ * testing Android components themselves we don't want certain classes (usually the
+ * class-under-test) to be loaded from the prebuilt jar, we want it instead to be loaded from the
+ * dependencies of our test target, i.e. the system class loader. That way we can write tests
+ * against the actual classes that are in the tree, not a past version of them. Ideally we would
+ * have a locally built jar referenced by Robolectric, but until that happens one can use this
+ * class.
+ * This class reads the {@link SystemLoaderClasses} annotation on test classes and for each class
+ * in that annotation value it will bypass the android jar and load it from the system class loader.
+ * Allowing the test to test the actual class in the tree.
+ *
+ * Implementation note: One could think about overriding
+ * {@link RobolectricTestRunner#createClassLoaderConfig(FrameworkMethod)} method and putting the
+ * classes in the annotation in the {@link InstrumentationConfiguration} list of classes not to
+ * acquire. Unfortunately, this will not work because we will not be instrumenting the class.
+ * Instead, we have to load the class bytes from the system class loader but still instrument it, we
+ * do this by overriding {@link SandboxClassLoader#getByteCode(String)} and loading the class bytes
+ * from the system class loader if it in the {@link SystemLoaderClasses} annotation. This way the
+ * {@link SandboxClassLoader} still instruments the class, but it's not loaded from the android jar.
+ * Finally, we inject the custom class loader in place of the default one.
+ *
+ * TODO: Remove this when we are using locally built android jars in the method's environment.
+ */
+public class FrameworkRobolectricTestRunner extends RobolectricTestRunner {
+ private final SandboxFactory mSandboxFactory;
+
+ public FrameworkRobolectricTestRunner(Class<?> testClass) throws InitializationError {
+ super(testClass);
+ SystemLoaderClasses annotation = testClass.getAnnotation(SystemLoaderClasses.class);
+ Class<?>[] systemLoaderClasses =
+ (annotation != null) ? annotation.value() : new Class<?>[0];
+ Set<String> systemLoaderClassNames = classesToClassNames(systemLoaderClasses);
+ mSandboxFactory = new FrameworkSandboxFactory(systemLoaderClassNames);
+ }
+
+ @Nonnull
+ @Override
+ protected SdkEnvironment getSandbox(FrameworkMethod method) {
+ // HACK: Calling super just to get SdkConfig via sandbox.getSdkConfig(), because
+ // RobolectricFrameworkMethod, the runtime class of method, is package-protected
+ SdkEnvironment sandbox = super.getSandbox(method);
+ return mSandboxFactory.getSdkEnvironment(
+ createClassLoaderConfig(method),
+ getJarResolver(),
+ sandbox.getSdkConfig());
+ }
+
+ private static class FrameworkClassLoader extends SandboxClassLoader {
+ private final Set<String> mSystemLoaderClasses;
+
+ private FrameworkClassLoader(
+ Set<String> systemLoaderClasses,
+ ClassLoader systemClassLoader,
+ InstrumentationConfiguration instrumentationConfig,
+ URL... urls) {
+ super(systemClassLoader, instrumentationConfig, urls);
+ mSystemLoaderClasses = systemLoaderClasses;
+ }
+
+ @Override
+ protected byte[] getByteCode(String className) throws ClassNotFoundException {
+ String classFileName = className.replace('.', '/') + ".class";
+ if (shouldLoadFromSystemLoader(className)) {
+ try (InputStream classByteStream = getResourceAsStream(classFileName)) {
+ if (classByteStream == null) {
+ throw new ClassNotFoundException(className);
+ }
+ return Util.readBytes(classByteStream);
+ } catch (IOException e) {
+ throw new ClassNotFoundException(
+ "Couldn't load " + className + " from system class loader", e);
+ }
+ }
+ return super.getByteCode(className);
+ }
+
+ /**
+ * Classes like com.package.ClassName$InnerClass should also be loaded from the system class
+ * loader, so we test if the classes in the annotation are prefixes of the class to load.
+ */
+ private boolean shouldLoadFromSystemLoader(String className) {
+ for (String classNamePrefix : mSystemLoaderClasses) {
+ if (className.startsWith(classNamePrefix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private static class FrameworkSandboxFactory extends SandboxFactory {
+ private final Set<String> mSystemLoaderClasses;
+
+ private FrameworkSandboxFactory(Set<String> systemLoaderClasses) {
+ mSystemLoaderClasses = systemLoaderClasses;
+ }
+
+ @Nonnull
+ @Override
+ public ClassLoader createClassLoader(
+ InstrumentationConfiguration instrumentationConfig, URL... urls) {
+ return new FrameworkClassLoader(
+ mSystemLoaderClasses,
+ ClassLoader.getSystemClassLoader(),
+ instrumentationConfig,
+ urls);
+ }
+ }
+
+ private static Set<String> classesToClassNames(Class<?>[] classes) {
+ ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+ for (Class<?> classObject : classes) {
+ builder.add(classObject.getName());
+ }
+ return builder.build();
+ }
+}
diff --git a/services/robotests/src/com/android/server/testing/SystemLoaderClasses.java b/services/robotests/src/com/android/server/testing/SystemLoaderClasses.java
new file mode 100644
index 0000000..646a413
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/SystemLoaderClasses.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 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.testing;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to be used in test classes that run with {@link FrameworkRobolectricTestRunner}.
+ * This will make the classes specified be loaded from the system class loader, NOT from the
+ * Robolectric android jar.
+ *
+ * @see FrameworkRobolectricTestRunner
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SystemLoaderClasses {
+ Class<?>[] value() default {};
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
index 4dd51eb..70906df 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
@@ -53,12 +53,12 @@
}
@Override
- SurfaceControl getSurfaceControl() {
+ public SurfaceControl getSurfaceControl() {
return mControl;
}
@Override
- SurfaceControl.Transaction getPendingTransaction() {
+ public SurfaceControl.Transaction getPendingTransaction() {
return mTransaction;
}
}
@@ -93,12 +93,12 @@
}
@Override
- SurfaceControl getSurfaceControl() {
+ public SurfaceControl getSurfaceControl() {
return mHostControl;
}
@Override
- SurfaceControl.Transaction getPendingTransaction() {
+ public SurfaceControl.Transaction getPendingTransaction() {
return mHostTransaction;
}
}
@@ -110,8 +110,8 @@
@Before
public void setUp() throws Exception {
super.setUp();
-
mHost = new MockSurfaceBuildingContainer();
+
mTransaction = mock(SurfaceControl.Transaction.class);
mDimmer = new Dimmer(mHost);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index 9ecf51e..c309611 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -24,9 +24,13 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.animation.AnimationHandler;
import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
+import android.animation.ValueAnimator;
import android.graphics.Matrix;
import android.graphics.Point;
import android.platform.test.annotations.Presubmit;
@@ -40,6 +44,7 @@
import android.view.animation.TranslateAnimation;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+import com.android.server.wm.SurfaceAnimationRunner.AnimatorFactory;
import org.junit.Before;
import org.junit.Rule;
@@ -54,7 +59,7 @@
/**
* Test class for {@link SurfaceAnimationRunner}.
*
- * runtest frameworks-services -c com.android.server.wm.SurfaceAnimationRunnerTest
+ * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimationRunnerTest
*/
@SmallTest
@Presubmit
@@ -63,6 +68,7 @@
@Mock SurfaceControl mMockSurface;
@Mock Transaction mMockTransaction;
+ @Mock AnimationSpec mMockAnimationSpec;
@Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
private SurfaceAnimationRunner mSurfaceAnimationRunner;
@@ -72,7 +78,7 @@
public void setUp() throws Exception {
super.setUp();
mFinishCallbackLatch = new CountDownLatch(1);
- mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */,
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */, null,
mMockTransaction);
}
@@ -104,7 +110,8 @@
@Test
public void testCancel_notStarted() throws Exception {
- mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), mMockTransaction);
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
+ mMockTransaction);
mSurfaceAnimationRunner
.startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
this::finishedCallback);
@@ -112,22 +119,47 @@
waitUntilHandlersIdle();
assertTrue(mSurfaceAnimationRunner.mPendingAnimations.isEmpty());
assertFinishCallbackNotCalled();
- //verify(mMockSurface).release();
}
@Test
public void testCancel_running() throws Exception {
- mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), mMockTransaction);
- mSurfaceAnimationRunner
- .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
- this::finishedCallback);
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
+ mMockTransaction);
+ mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface,
+ mMockTransaction, this::finishedCallback);
waitUntilNextFrame();
assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
waitUntilHandlersIdle();
assertFinishCallbackNotCalled();
- //verify(mMockSurface).release();
+ }
+
+ @Test
+ public void testCancel_sneakyCancelBeforeUpdate() throws Exception {
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(null, () -> new ValueAnimator() {
+ {
+ setFloatValues(0f, 1f);
+ }
+
+ @Override
+ public void addUpdateListener(AnimatorUpdateListener listener) {
+ super.addUpdateListener(animation -> {
+ // Sneaky test cancels animation just before applying frame to simulate
+ // interleaving of multiple threads. Muahahaha
+ if (animation.getCurrentPlayTime() > 0) {
+ mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
+ }
+ listener.onAnimationUpdate(animation);
+ });
+ }
+ }, mMockTransaction);
+ when(mMockAnimationSpec.getDuration()).thenReturn(200L);
+ mSurfaceAnimationRunner.startAnimation(mMockAnimationSpec, mMockSurface, mMockTransaction,
+ this::finishedCallback);
+ waitUntilNextFrame();
+ assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
+ verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L));
}
private void waitUntilNextFrame() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 9a52042..6f739ca 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -33,8 +33,6 @@
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
-import com.google.android.collect.Lists;
-
import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
@@ -50,27 +48,127 @@
/**
* Test class for {@link SurfaceAnimatorTest}.
*
- * runtest frameworks-services -c com.android.server.wm.SurfaceAnimatorTest
+ * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimatorTest
*/
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class SurfaceAnimatorTest extends WindowTestsBase {
- @Mock
- AnimationAdapter mSpec;
- @Mock
- AnimationAdapter mSpec2;
+ @Mock AnimationAdapter mSpec;
+ @Mock AnimationAdapter mSpec2;
@Mock Transaction mTransaction;
- private SurfaceAnimator mSurfaceAnimator;
- private SurfaceControl mParent;
- private SurfaceControl mSurface;
- private boolean mFinishedCallbackCalled;
- private SurfaceControl mLeash;
private SurfaceSession mSession = new SurfaceSession();
+ private MyAnimatable mAnimatable;
- private final Animatable mAnimatable = new Animatable() {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ mAnimatable = new MyAnimatable();
+ }
+
+ @Test
+ public void testRunAnimation() throws Exception {
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
+ OnAnimationFinishedCallback.class);
+
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertNotNull(mAnimatable.mSurfaceAnimator.getAnimation());
+ verify(mTransaction).reparent(eq(mAnimatable.mSurface), eq(mAnimatable.mLeash.getHandle()));
+ verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+
+ callbackCaptor.getValue().onAnimationFinished(mSpec);
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertNull(mAnimatable.mSurfaceAnimator.getAnimation());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ // TODO: Verify reparenting once we use mPendingTransaction to reparent it back
+ }
+
+ @Test
+ public void testOverrideAnimation() throws Exception {
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ final SurfaceControl firstLeash = mAnimatable.mLeash;
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
+
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
+ assertFalse(mAnimatable.mFinishedCallbackCalled);
+
+ final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
+ OnAnimationFinishedCallback.class);
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertNotNull(mAnimatable.mSurfaceAnimator.getAnimation());
+ verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+
+ // First animation was finished, but this shouldn't cancel the second animation
+ callbackCaptor.getValue().onAnimationFinished(mSpec);
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+
+ // Second animation was finished
+ verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
+ callbackCaptor.getValue().onAnimationFinished(mSpec2);
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ }
+
+ @Test
+ public void testCancelAnimation() throws Exception {
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ mAnimatable.mSurfaceAnimator.cancelAnimation();
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ verify(mSpec).onAnimationCancelled(any());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ }
+
+ @Test
+ public void testDelayingAnimationStart() throws Exception {
+ mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ verifyZeroInteractions(mSpec);
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ mAnimatable.mSurfaceAnimator.endDelayingAnimationStart();
+ verify(mSpec).startAnimation(any(), any(), any());
+ }
+
+ @Test
+ public void testDelayingAnimationStartAndCancelled() throws Exception {
+ mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.cancelAnimation();
+ verifyZeroInteractions(mSpec);
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ }
+
+ private class MyAnimatable implements Animatable {
+
+ final SurfaceControl mParent;
+ final SurfaceControl mSurface;
+ final ArrayList<SurfaceControl> mPendingDestroySurfaces = new ArrayList<>();
+ final SurfaceAnimator mSurfaceAnimator;
+ SurfaceControl mLeash;
+ boolean mFinishedCallbackCalled;
+
+ MyAnimatable() {
+ mParent = sWm.makeSurfaceBuilder(mSession)
+ .setName("test surface parent")
+ .setSize(3000, 3000)
+ .build();
+ mSurface = sWm.makeSurfaceBuilder(mSession)
+ .setName("test surface")
+ .setSize(1, 1)
+ .build();
+ mFinishedCallbackCalled = false;
+ mLeash = null;
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
+ }
+
@Override
public Transaction getPendingTransaction() {
return mTransaction;
@@ -81,15 +179,20 @@
}
@Override
- public void onLeashCreated(Transaction t, SurfaceControl leash) {
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
}
@Override
- public void onLeashDestroyed(Transaction t) {
+ public void onAnimationLeashDestroyed(Transaction t) {
}
@Override
- public Builder makeLeash() {
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
+ mPendingDestroySurfaces.add(surface);
+ }
+
+ @Override
+ public Builder makeAnimationLeash() {
return new SurfaceControl.Builder(mSession) {
@Override
@@ -101,12 +204,12 @@
}
@Override
- public SurfaceControl getSurface() {
+ public SurfaceControl getSurfaceControl() {
return mSurface;
}
@Override
- public SurfaceControl getParentSurface() {
+ public SurfaceControl getParentSurfaceControl() {
return mParent;
}
@@ -119,99 +222,9 @@
public int getSurfaceHeight() {
return 1;
}
- };
- private final Runnable mFinishedCallback = () -> {
- mFinishedCallbackCalled = true;
- };
-
- @Before
- public void setUp() throws Exception {
- super.setUp();
- MockitoAnnotations.initMocks(this);
- mParent = sWm.makeSurfaceBuilder(mSession)
- .setName("test surface parent")
- .setSize(3000, 3000)
- .build();
- mSurface = sWm.makeSurfaceBuilder(mSession)
- .setName("test surface")
- .setSize(1, 1)
- .build();
- mFinishedCallbackCalled = false;
- mLeash = null;
- mSurfaceAnimator = new SurfaceAnimator(mAnimatable, mFinishedCallback, sWm);
- }
-
- @Test
- public void testRunAnimation() throws Exception {
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
- final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
- OnAnimationFinishedCallback.class);
-
- assertTrue(mSurfaceAnimator.isAnimating());
- assertNotNull(mSurfaceAnimator.getAnimation());
- verify(mTransaction).reparent(eq(mSurface), eq(mLeash.getHandle()));
- verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
-
- callbackCaptor.getValue().onAnimationFinished(mSpec);
- assertFalse(mSurfaceAnimator.isAnimating());
- assertNull(mSurfaceAnimator.getAnimation());
- assertTrue(mFinishedCallbackCalled);
-
- // TODO: Verify reparenting once we use mPendingTransaction to reparent it back
- }
-
- @Test
- public void testOverrideAnimation() throws Exception {
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
- mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
-
- assertFalse(mFinishedCallbackCalled);
-
- final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
- OnAnimationFinishedCallback.class);
- assertTrue(mSurfaceAnimator.isAnimating());
- assertNotNull(mSurfaceAnimator.getAnimation());
- verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
-
- // First animation was finished, but this shouldn't cancel the second animation
- callbackCaptor.getValue().onAnimationFinished(mSpec);
- assertTrue(mSurfaceAnimator.isAnimating());
-
- // Second animation was finished
- verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
- callbackCaptor.getValue().onAnimationFinished(mSpec2);
- assertFalse(mSurfaceAnimator.isAnimating());
- assertTrue(mFinishedCallbackCalled);
- }
-
- @Test
- public void testCancelAnimation() throws Exception {
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
- assertTrue(mSurfaceAnimator.isAnimating());
- mSurfaceAnimator.cancelAnimation();
- assertFalse(mSurfaceAnimator.isAnimating());
- verify(mSpec).onAnimationCancelled(any());
- assertTrue(mFinishedCallbackCalled);
- }
-
- @Test
- public void testDelayingAnimationStart() throws Exception {
- mSurfaceAnimator.startDelayingAnimationStart();
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
- verifyZeroInteractions(mSpec);
- assertTrue(mSurfaceAnimator.isAnimating());
- mSurfaceAnimator.endDelayingAnimationStart();
- verify(mSpec).startAnimation(any(), any(), any());
- }
-
- @Test
- public void testDelayingAnimationStartAndCancelled() throws Exception {
- mSurfaceAnimator.startDelayingAnimationStart();
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
- mSurfaceAnimator.cancelAnimation();
- verifyZeroInteractions(mSpec);
- assertFalse(mSurfaceAnimator.isAnimating());
- assertTrue(mFinishedCallbackCalled);
+ private final Runnable mFinishedCallback = () -> {
+ mFinishedCallbackCalled = true;
+ };
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 5cb9467..307deb4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -29,8 +29,6 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -333,12 +331,19 @@
final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true));
final TestWindowContainer child21 = child2.addChildWindow();
- assertTrue(root.isAnimating());
+ assertFalse(root.isAnimating());
assertTrue(child1.isAnimating());
- assertFalse(child11.isAnimating());
+ assertTrue(child11.isAnimating());
assertTrue(child12.isAnimating());
assertFalse(child2.isAnimating());
assertFalse(child21.isAnimating());
+
+ assertTrue(root.isSelfOrChildAnimating());
+ assertTrue(child1.isSelfOrChildAnimating());
+ assertFalse(child11.isSelfOrChildAnimating());
+ assertTrue(child12.isSelfOrChildAnimating());
+ assertFalse(child2.isSelfOrChildAnimating());
+ assertFalse(child21.isSelfOrChildAnimating());
}
@Test
@@ -630,8 +635,8 @@
}
@Override
- boolean isAnimating() {
- return mIsAnimating || super.isAnimating();
+ boolean isSelfAnimating() {
+ return mIsAnimating;
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index b2334e8..5f58744 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -189,7 +189,6 @@
public static class TestTask extends Task {
boolean mShouldDeferRemoval = false;
boolean mOnDisplayChangedCalled = false;
- private boolean mUseLocalIsAnimating = false;
private boolean mIsAnimating = false;
TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service,
@@ -214,12 +213,11 @@
}
@Override
- boolean isAnimating() {
- return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
+ boolean isSelfAnimating() {
+ return mIsAnimating;
}
void setLocalIsAnimating(boolean isAnimating) {
- mUseLocalIsAnimating = true;
mIsAnimating = isAnimating;
}
}
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index e60f52f..7a5049d 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -182,7 +182,7 @@
*
* @hide
*/
- public void assertValid(Characteristics characteristics)
+ public void assertValid(Characteristics characteristics, boolean rttSupported)
throws IllegalArgumentException {
WifiAwareUtils.validateServiceName(mServiceName);
@@ -216,6 +216,10 @@
"Match filter longer than supported by device characteristics");
}
}
+
+ if (!rttSupported && mEnableRanging) {
+ throw new IllegalArgumentException("Ranging is not supported");
+ }
}
/**
@@ -364,6 +368,9 @@
* Optional. Disabled by default - i.e. any peer which attempts to measure distance to this
* device will be refused. If the peer has ranging enabled (using the
* {@link SubscribeConfig} APIs listed above, it will never discover this device.
+ * <p>
+ * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked
+ * as described in {@link android.net.wifi.rtt}.
*
* @param enable If true, ranging is supported on request of the peer.
*
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index f6552a7..91f8e520 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -224,7 +224,7 @@
*
* @hide
*/
- public void assertValid(Characteristics characteristics)
+ public void assertValid(Characteristics characteristics, boolean rttSupported)
throws IllegalArgumentException {
WifiAwareUtils.validateServiceName(mServiceName);
@@ -269,6 +269,10 @@
throw new IllegalArgumentException(
"Maximum distance must be greater than minimum distance");
}
+
+ if (!rttSupported && (mMinDistanceMmSet || mMaxDistanceMmSet)) {
+ throw new IllegalArgumentException("Ranging is not supported");
+ }
}
/**
@@ -422,6 +426,9 @@
* peer must enable ranging using
* {@link PublishConfig.Builder#setRangingEnabled(boolean)}. Otherwise discovery will
* never be triggered.
+ * <p>
+ * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked
+ * as described in {@link android.net.wifi.rtt}.
*
* @param minDistanceMm Minimum distance, in mm, to the publisher above which to trigger
* discovery.
@@ -450,6 +457,9 @@
* peer must enable ranging using
* {@link PublishConfig.Builder#setRangingEnabled(boolean)}. Otherwise discovery will
* never be triggered.
+ * <p>
+ * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked
+ * as described in {@link android.net.wifi.rtt}.
*
* @param maxDistanceMm Maximum distance, in mm, to the publisher below which to trigger
* discovery.