Merge "Update the ttc index attribute documentation"
diff --git a/api/current.txt b/api/current.txt
index 9741fbc..2be925e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6338,7 +6338,7 @@
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
- method public android.security.AttestedKeyPair generateKeyPair(android.content.ComponentName, java.lang.String, android.security.keystore.KeyGenParameterSpec);
+ method public android.security.AttestedKeyPair generateKeyPair(android.content.ComponentName, java.lang.String, android.security.keystore.KeyGenParameterSpec, int);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public java.util.Set<java.lang.String> getAffiliationIds(android.content.ComponentName);
@@ -6572,6 +6572,10 @@
field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
+ field public static final int ID_TYPE_BASE_INFO = 1; // 0x1
+ field public static final int ID_TYPE_IMEI = 4; // 0x4
+ field public static final int ID_TYPE_MEID = 8; // 0x8
+ field public static final int ID_TYPE_SERIAL = 2; // 0x2
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
field public static final int KEYGUARD_DISABLE_FINGERPRINT = 32; // 0x20
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7e80ac7..0b74741 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1668,6 +1668,46 @@
public static final String ACTION_DEVICE_ADMIN_SERVICE
= "android.app.action.DEVICE_ADMIN_SERVICE";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"ID_TYPE_"}, value = {
+ ID_TYPE_BASE_INFO,
+ ID_TYPE_SERIAL,
+ ID_TYPE_IMEI,
+ ID_TYPE_MEID
+ })
+ public @interface AttestationIdType {}
+
+ /**
+ * Specifies that the device should attest its manufacturer details. For use with
+ * {@link #generateKeyPair}.
+ *
+ * @see #generateKeyPair
+ */
+ public static final int ID_TYPE_BASE_INFO = 1;
+
+ /**
+ * Specifies that the device should attest its serial number. For use with
+ * {@link #generateKeyPair}.
+ *
+ * @see #generateKeyPair
+ */
+ public static final int ID_TYPE_SERIAL = 2;
+
+ /**
+ * Specifies that the device should attest its IMEI. For use with {@link #generateKeyPair}.
+ *
+ * @see #generateKeyPair
+ */
+ public static final int ID_TYPE_IMEI = 4;
+
+ /**
+ * Specifies that the device should attest its MEID. For use with {@link #generateKeyPair}.
+ *
+ * @see #generateKeyPair
+ */
+ public static final int ID_TYPE_MEID = 8;
+
/**
* Return true if the given administrator component is currently active (enabled) in the system.
*
@@ -4106,22 +4146,46 @@
* @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}.
* @param keySpec Specification of the key to generate, see
* {@link java.security.KeyPairGenerator}.
+ * @param idAttestationFlags A bitmask of all the identifiers that should be included in the
+ * attestation record ({@code ID_TYPE_BASE_INFO}, {@code ID_TYPE_SERIAL},
+ * {@code ID_TYPE_IMEI} and {@code ID_TYPE_MEID}), or {@code 0} if no device
+ * identification is required in the attestation record.
+ * Device owner, profile owner and their delegated certificate installer can use
+ * {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device information
+ * including manufacturer, model, brand, device and product in the attestation record.
+ * Only device owner and their delegated certificate installer can use
+ * {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID} to request
+ * unique device identifiers to be attested.
+ * <p>
+ * If any of {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID}
+ * is set, it is implicitly assumed that {@link #ID_TYPE_BASE_INFO} is also set.
+ * <p>
+ * If any flag is specified, then an attestation challenge must be included in the
+ * {@code keySpec}.
* @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner.
- * @throws IllegalArgumentException if the alias in {@code keySpec} is empty, or if the
+ * owner. If Device ID attestation is requested (using {@link #ID_TYPE_SERIAL},
+ * {@link #ID_TYPE_IMEI} or {@link #ID_TYPE_MEID}), the caller must be the Device Owner
+ * or the Certificate Installer delegate.
+ * @throws IllegalArgumentException if the alias in {@code keySpec} is empty, if the
* algorithm specification in {@code keySpec} is not {@code RSAKeyGenParameterSpec}
- * or {@code ECGenParameterSpec}.
+ * or {@code ECGenParameterSpec}, or if Device ID attestation was requested but the
+ * {@code keySpec} does not contain an attestation challenge.
+ * @see KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])
*/
public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin,
- @NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec) {
+ @NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec,
+ @AttestationIdType int idAttestationFlags) {
throwIfParentInstance("generateKeyPair");
try {
final ParcelableKeyGenParameterSpec parcelableSpec =
new ParcelableKeyGenParameterSpec(keySpec);
KeymasterCertificateChain attestationChain = new KeymasterCertificateChain();
+
+ // Translate ID attestation flags to values used by AttestationUtils
final boolean success = mService.generateKeyPair(
- admin, mContext.getPackageName(), algorithm, parcelableSpec, attestationChain);
+ admin, mContext.getPackageName(), algorithm, parcelableSpec,
+ idAttestationFlags, attestationChain);
if (!success) {
Log.e(TAG, "Error generating key via DevicePolicyManagerService.");
return null;
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 7cf19ee..5916a62 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -173,7 +173,7 @@
boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias);
boolean generateKeyPair(in ComponentName who, in String callerPackage, in String algorithm,
in ParcelableKeyGenParameterSpec keySpec,
- out KeymasterCertificateChain attestationChain);
+ in int idAttestationFlags, out KeymasterCertificateChain attestationChain);
boolean setKeyPairCertificate(in ComponentName who, in String callerPackage, in String alias,
in byte[] certBuffer, in byte[] certChainBuffer, boolean isUserSelectable);
void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index dd9fd93..38993b7 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2197,7 +2197,8 @@
/**
* Similar to {@link #trySetQuietModeEnabled(boolean, UserHandle)}, except you can specify
- * a target to start when user is unlocked.
+ * a target to start when user is unlocked. If {@code target} is specified, caller must have
+ * the {@link android.Manifest.permission#MANAGE_USERS} permission.
*
* @see {@link #trySetQuietModeEnabled(boolean, UserHandle)}
* @hide
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 7c7417d..5a8fa07 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -34,7 +34,8 @@
void setUserSelectable(String alias, boolean isUserSelectable);
boolean generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec);
- boolean attestKey(in String alias, in byte[] challenge, out KeymasterCertificateChain chain);
+ boolean attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags,
+ out KeymasterCertificateChain chain);
boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain);
// APIs used by CertInstaller and DevicePolicyManager
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index 0811100..efee8b4 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -99,48 +99,35 @@
}
}
- /**
- * Performs attestation of the device's identifiers. This method returns a certificate chain
- * whose first element contains the requested device identifiers in an extension. The device's
- * manufacturer, model, brand, device and product are always also included in the attestation.
- * If the device supports attestation in secure hardware, the chain will be rooted at a
- * trustworthy CA key. Otherwise, the chain will be rooted at an untrusted certificate. See
- * <a href="https://developer.android.com/training/articles/security-key-attestation.html">
- * Key Attestation</a> for the format of the certificate extension.
- * <p>
- * Attestation will only be successful when all of the following are true:
- * 1) The device has been set up to support device identifier attestation at the factory.
- * 2) The user has not permanently disabled device identifier attestation.
- * 3) You have permission to access the device identifiers you are requesting attestation for.
- * <p>
- * For privacy reasons, you cannot distinguish between (1) and (2). If attestation is
- * unsuccessful, the device may not support it in general or the user may have permanently
- * disabled it.
- *
- * @param context the context to use for retrieving device identifiers.
- * @param idTypes the types of device identifiers to attest.
- * @param attestationChallenge a blob to include in the certificate alongside the device
- * identifiers.
- *
- * @return a certificate chain containing the requested device identifiers in the first element
- *
- * @exception SecurityException if you are not permitted to obtain an attestation of the
- * device's identifiers.
- * @exception DeviceIdAttestationException if the attestation operation fails.
- */
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- @NonNull public static X509Certificate[] attestDeviceIds(Context context,
- @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
+ @NonNull private static KeymasterArguments prepareAttestationArgumentsForDeviceId(
+ Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
DeviceIdAttestationException {
- // Check method arguments, retrieve requested device IDs and prepare attestation arguments.
+ // Verify that device ID attestation types are provided.
if (idTypes == null) {
throw new NullPointerException("Missing id types");
}
+
+ return prepareAttestationArguments(context, idTypes, attestationChallenge);
+ }
+
+ /**
+ * Prepares Keymaster Arguments with attestation data.
+ * @hide should only be used by KeyChain.
+ */
+ @NonNull public static KeymasterArguments prepareAttestationArguments(Context context,
+ @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
+ DeviceIdAttestationException {
+ // Check method arguments, retrieve requested device IDs and prepare attestation arguments.
if (attestationChallenge == null) {
throw new NullPointerException("Missing attestation challenge");
}
final KeymasterArguments attestArgs = new KeymasterArguments();
attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, attestationChallenge);
+ // Return early if the caller did not request any device identifiers to be included in the
+ // attestation record.
+ if (idTypes == null) {
+ return attestArgs;
+ }
final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
for (int idType : idTypes) {
idTypesSet.add(idType);
@@ -191,6 +178,44 @@
Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8));
attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
Build.MODEL.getBytes(StandardCharsets.UTF_8));
+ return attestArgs;
+ }
+
+ /**
+ * Performs attestation of the device's identifiers. This method returns a certificate chain
+ * whose first element contains the requested device identifiers in an extension. The device's
+ * manufacturer, model, brand, device and product are always also included in the attestation.
+ * If the device supports attestation in secure hardware, the chain will be rooted at a
+ * trustworthy CA key. Otherwise, the chain will be rooted at an untrusted certificate. See
+ * <a href="https://developer.android.com/training/articles/security-key-attestation.html">
+ * Key Attestation</a> for the format of the certificate extension.
+ * <p>
+ * Attestation will only be successful when all of the following are true:
+ * 1) The device has been set up to support device identifier attestation at the factory.
+ * 2) The user has not permanently disabled device identifier attestation.
+ * 3) You have permission to access the device identifiers you are requesting attestation for.
+ * <p>
+ * For privacy reasons, you cannot distinguish between (1) and (2). If attestation is
+ * unsuccessful, the device may not support it in general or the user may have permanently
+ * disabled it.
+ *
+ * @param context the context to use for retrieving device identifiers.
+ * @param idTypes the types of device identifiers to attest.
+ * @param attestationChallenge a blob to include in the certificate alongside the device
+ * identifiers.
+ *
+ * @return a certificate chain containing the requested device identifiers in the first element
+ *
+ * @exception SecurityException if you are not permitted to obtain an attestation of the
+ * device's identifiers.
+ * @exception DeviceIdAttestationException if the attestation operation fails.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @NonNull public static X509Certificate[] attestDeviceIds(Context context,
+ @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
+ DeviceIdAttestationException {
+ final KeymasterArguments attestArgs = prepareAttestationArgumentsForDeviceId(
+ context, idTypes, attestationChallenge);
// Perform attestation.
final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
index 537592e..b17f794 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerConstants.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
@@ -121,7 +121,7 @@
DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
mFullBackupRequiredNetworkType = mParser.getInt(FULL_BACKUP_REQUIRED_NETWORK_TYPE,
DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
- final String backupFinishedNotificationReceivers = mParser.getString(
+ String backupFinishedNotificationReceivers = mParser.getString(
BACKUP_FINISHED_NOTIFICATION_RECEIVERS,
DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS);
if (backupFinishedNotificationReceivers.isEmpty()) {
@@ -190,6 +190,9 @@
return mFullBackupRequiredNetworkType;
}
+ /**
+ * Returns an array of package names that should be notified whenever a backup finishes.
+ */
public synchronized String[] getBackupFinishedNotificationReceivers() {
if (RefactoredBackupManagerService.DEBUG_SCHEDULING) {
Slog.v(TAG, "getBackupFinishedNotificationReceivers(...) returns "
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 768eb8f..c3dce31 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -27,7 +27,6 @@
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
-import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.KeyguardManager;
@@ -795,12 +794,7 @@
"target should only be specified when we are disabling quiet mode.");
}
- if (!isAllowedToSetWorkMode(callingPackage, Binder.getCallingUid())) {
- throw new SecurityException("Not allowed to call trySetQuietModeEnabled, "
- + "caller is foreground default launcher "
- + "nor with MANAGE_USERS/MODIFY_QUIET_MODE permission");
- }
-
+ ensureCanModifyQuietMode(callingPackage, Binder.getCallingUid(), target != null);
final long identity = Binder.clearCallingIdentity();
try {
if (enableQuietMode) {
@@ -824,35 +818,44 @@
}
/**
- * An app can modify quiet mode if the caller meets one of the condition:
+ * The caller can modify quiet mode if it meets one of these conditions:
* <ul>
* <li>Has system UID or root UID</li>
* <li>Has {@link Manifest.permission#MODIFY_QUIET_MODE}</li>
* <li>Has {@link Manifest.permission#MANAGE_USERS}</li>
* </ul>
+ * <p>
+ * If caller wants to start an intent after disabling the quiet mode, it must has
+ * {@link Manifest.permission#MANAGE_USERS}.
*/
- private boolean isAllowedToSetWorkMode(String callingPackage, int callingUid) {
+ private void ensureCanModifyQuietMode(String callingPackage, int callingUid,
+ boolean startIntent) {
if (hasManageUsersPermission()) {
- return true;
+ return;
}
-
+ if (startIntent) {
+ throw new SecurityException("MANAGE_USERS permission is required to start intent "
+ + "after disabling quiet mode.");
+ }
final boolean hasModifyQuietModePermission = ActivityManager.checkComponentPermission(
Manifest.permission.MODIFY_QUIET_MODE,
callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
if (hasModifyQuietModePermission) {
- return true;
+ return;
}
+ verifyCallingPackage(callingPackage, callingUid);
final ShortcutServiceInternal shortcutInternal =
LocalServices.getService(ShortcutServiceInternal.class);
if (shortcutInternal != null) {
boolean isForegroundLauncher =
shortcutInternal.isForegroundDefaultLauncher(callingPackage, callingUid);
if (isForegroundLauncher) {
- return true;
+ return;
}
}
- return false;
+ throw new SecurityException("Can't modify quiet mode, caller is neither foreground "
+ + "default launcher nor has MANAGE_USERS/MODIFY_QUIET_MODE permission");
}
private void setQuietModeEnabled(
@@ -3932,4 +3935,16 @@
return false;
}
}
+
+ /**
+ * Check if the calling package name matches with the calling UID, throw
+ * {@link SecurityException} if not.
+ */
+ private void verifyCallingPackage(String callingPackage, int callingUid) {
+ int packageUid = mPm.getPackageUid(callingPackage, 0, UserHandle.getUserId(callingUid));
+ if (packageUid != callingUid) {
+ throw new SecurityException("Specified package " + callingPackage
+ + " does not match the calling uid " + callingUid);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index b86cd50..c16a531 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -139,7 +139,7 @@
@Override
public Builder makeAnimationLeash() {
- return mAppToken.makeSurface().setParent(mAppToken.getAppAnimationLayer());
+ return mAppToken.makeSurface();
}
@Override
@@ -148,6 +148,11 @@
}
@Override
+ public SurfaceControl getAnimationLeashParent() {
+ return mAppToken.getAppAnimationLayer();
+ }
+
+ @Override
public SurfaceControl getParentSurfaceControl() {
return mAppToken.getParentSurfaceControl();
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 44d7948..3f99591 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1512,9 +1512,8 @@
}
@Override
- public SurfaceControl.Builder makeAnimationLeash() {
- return super.makeAnimationLeash()
- .setParent(getAppAnimationLayer());
+ public SurfaceControl getAnimationLeashParent() {
+ return getAppAnimationLayer();
}
boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d053015..63dfbc2 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1923,6 +1923,8 @@
mService.unregisterPointerEventListener(mService.mMousePositionTracker);
}
}
+ mService.mAnimator.removeDisplayLocked(mDisplayId);
+
// The pending transaction won't be applied so we should
// just clean up any surfaces pending destruction.
onPendingTransactionApplied();
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index bda5bc9..a32e711 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -72,23 +72,29 @@
target.mInnerAnimationFinishedCallback.onAnimationFinished(anim);
return;
}
- if (anim != mAnimation) {
- // Callback was from another animation - ignore.
- return;
- }
- final Transaction t = new Transaction();
- SurfaceControl.openTransaction();
- try {
- reset(t, true /* destroyLeash */);
- animationFinishedCallback.run();
- } finally {
- // TODO: This should use pendingTransaction eventually, but right now things
- // happening on the animation finished callback are happening on the global
- // transaction.
- SurfaceControl.mergeToGlobalTransaction(t);
- SurfaceControl.closeTransaction();
- }
+ // TODO: This should use pendingTransaction eventually, but right now things
+ // happening on the animation finished callback are happening on the global
+ // transaction.
+ // For now we need to run this after it's guaranteed that the transaction that
+ // reparents the surface onto the leash is executed already. Otherwise this may be
+ // executed first, leading to surface loss, as the reparent operations wouldn't
+ // be in order.
+ mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
+ if (anim != mAnimation) {
+ // Callback was from another animation - ignore.
+ return;
+ }
+ final Transaction t = new Transaction();
+ SurfaceControl.openTransaction();
+ try {
+ reset(t, true /* destroyLeash */);
+ animationFinishedCallback.run();
+ } finally {
+ SurfaceControl.mergeToGlobalTransaction(t);
+ SurfaceControl.closeTransaction();
+ }
+ });
}
};
}
@@ -213,7 +219,7 @@
return;
}
final SurfaceControl surface = mAnimatable.getSurfaceControl();
- final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
+ final SurfaceControl parent = mAnimatable.getAnimationLeashParent();
if (surface == null || parent == null) {
Slog.w(TAG, "Unable to transfer animation, surface or parent is null");
cancelAnimation();
@@ -287,6 +293,7 @@
int height, boolean hidden) {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash()
+ .setParent(mAnimatable.getAnimationLeashParent())
.setName(surface + " - animation-leash")
.setSize(width, height);
final SurfaceControl leash = builder.build();
@@ -355,6 +362,11 @@
SurfaceControl.Builder makeAnimationLeash();
/**
+ * @return The parent that should be used for the animation leash.
+ */
+ @Nullable SurfaceControl getAnimationLeashParent();
+
+ /**
* @return The surface of the object to be animated.
*/
@Nullable SurfaceControl getSurfaceControl();
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 3ffc7fa..eb8eae1 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -44,6 +44,7 @@
import android.annotation.CallSuper;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.RemoteException;
@@ -145,6 +146,7 @@
* For {@link #prepareSurfaces}.
*/
final Rect mTmpDimBoundsRect = new Rect();
+ private final Point mLastSurfaceSize = new Point();
TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
super(service);
@@ -743,7 +745,13 @@
}
final Rect stackBounds = getBounds();
- transaction.setSize(mSurfaceControl, stackBounds.width(), stackBounds.height());
+ final int width = stackBounds.width();
+ final int height = stackBounds.height();
+ if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
+ return;
+ }
+ transaction.setSize(mSurfaceControl, width, height);
+ mLastSurfaceSize.set(width, height);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 8bceb64..7295873 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -35,6 +35,7 @@
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
+import java.util.ArrayList;
/**
* Singleton class that carries out the animations and Surface operations in a separate task
@@ -87,6 +88,12 @@
*/
private boolean mAnimationFrameCallbackScheduled;
+ /**
+ * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is
+ * executed and the corresponding transaction is closed and applied.
+ */
+ private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
+
WindowAnimator(final WindowManagerService service) {
mService = service;
mContext = service.mContext;
@@ -262,6 +269,7 @@
mService.destroyPreservedSurfaceLocked();
mService.mWindowPlacerLocked.destroyPendingSurfaces();
+ executeAfterPrepareSurfacesRunnables();
if (DEBUG_WINDOW_TRACE) {
Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
@@ -425,4 +433,23 @@
void orAnimating(boolean animating) {
mAnimating |= animating;
}
+
+ /**
+ * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
+ * the corresponding transaction is closed and applied.
+ */
+ void addAfterPrepareSurfacesRunnable(Runnable r) {
+ mAfterPrepareSurfacesRunnables.add(r);
+ scheduleAnimation();
+ }
+
+ private void executeAfterPrepareSurfacesRunnables() {
+
+ // Traverse in order they were added.
+ final int size = mAfterPrepareSurfacesRunnables.size();
+ for (int i = 0; i < size; i++) {
+ mAfterPrepareSurfacesRunnables.get(i).run();
+ }
+ mAfterPrepareSurfacesRunnables.clear();
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b251b53..af31410 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -95,6 +95,7 @@
protected final WindowManagerService mService;
private final Point mTmpPos = new Point();
+ protected final Point mLastSurfacePosition = new Point();
/** Total number of elements in this subtree, including our own hierarchy element. */
private int mTreeWeight = 1;
@@ -1088,6 +1089,11 @@
return makeSurface();
}
+ @Override
+ public SurfaceControl getAnimationLeashParent() {
+ return getParentSurfaceControl();
+ }
+
/**
* @return The layer on which all app animations are happening.
*/
@@ -1172,7 +1178,12 @@
}
getRelativePosition(mTmpPos);
+ if (mTmpPos.equals(mLastSurfacePosition)) {
+ return;
+ }
+
transaction.setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y);
+ mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y);
for (int i = mChildren.size() - 1; i >= 0; i--) {
mChildren.get(i).updateSurfacePosition(transaction);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 863922f..0e025dc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4432,6 +4432,7 @@
// Leash is now responsible for position, so set our position to 0.
t.setPosition(mSurfaceControl, 0, 0);
+ mLastSurfacePosition.set(0, 0);
}
@Override
@@ -4447,8 +4448,9 @@
}
transformFrameToSurfacePosition(mFrame.left, mFrame.top, mSurfacePosition);
- if (!mSurfaceAnimator.hasLeash()) {
+ if (!mSurfaceAnimator.hasLeash() && !mLastSurfacePosition.equals(mSurfacePosition)) {
t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index e55d4ea..c1e95eb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -67,7 +67,8 @@
public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) {}
public boolean generateKeyPair(ComponentName who, String callerPackage, String algorithm,
- ParcelableKeyGenParameterSpec keySpec, KeymasterCertificateChain attestationChain) {
+ ParcelableKeyGenParameterSpec keySpec, int idAttestationFlags,
+ KeymasterCertificateChain attestationChain) {
return false;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e5351b4..11fce4d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -45,6 +45,10 @@
import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
import static android.app.admin.DevicePolicyManager.LEAVE_ALL_SYSTEM_APPS_ENABLED;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -217,8 +221,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -5052,17 +5058,82 @@
return false;
}
+ private void enforceIsDeviceOwnerOrCertInstallerOfDeviceOwner(
+ ComponentName who, String callerPackage, int callerUid) throws SecurityException {
+ if (who == null) {
+ if (!mOwners.hasDeviceOwner()) {
+ throw new SecurityException("Not in Device Owner mode.");
+ }
+ if (UserHandle.getUserId(callerUid) != mOwners.getDeviceOwnerUserId()) {
+ throw new SecurityException("Caller not from device owner user");
+ }
+ if (!isCallerDelegate(callerPackage, DELEGATION_CERT_INSTALL)) {
+ throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid() +
+ "has no permission to generate keys.");
+ }
+ } else {
+ // Caller provided - check it is the device owner.
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ public static int[] translateIdAttestationFlags(
+ int idAttestationFlags) {
+ Map<Integer, Integer> idTypeToAttestationFlag = new HashMap();
+ idTypeToAttestationFlag.put(ID_TYPE_SERIAL, AttestationUtils.ID_TYPE_SERIAL);
+ idTypeToAttestationFlag.put(ID_TYPE_IMEI, AttestationUtils.ID_TYPE_IMEI);
+ idTypeToAttestationFlag.put(ID_TYPE_MEID, AttestationUtils.ID_TYPE_MEID);
+
+ int numFlagsSet = Integer.bitCount(idAttestationFlags);
+ // No flags are set - return null to indicate no device ID attestation information should
+ // be included in the attestation record.
+ if (numFlagsSet == 0) {
+ return null;
+ }
+
+ // If the ID_TYPE_BASE_INFO is set, make sure that a non-null array is returned, even if
+ // no other flag is set. That will lead to inclusion of general device make data in the
+ // attestation record, but no specific device identifiers.
+ if ((idAttestationFlags & ID_TYPE_BASE_INFO) != 0) {
+ numFlagsSet -= 1;
+ idAttestationFlags = idAttestationFlags & (~ID_TYPE_BASE_INFO);
+ }
+
+ int[] attestationUtilsFlags = new int[numFlagsSet];
+ int i = 0;
+ for (Integer idType: idTypeToAttestationFlag.keySet()) {
+ if ((idType & idAttestationFlags) != 0) {
+ attestationUtilsFlags[i++] = idTypeToAttestationFlag.get(idType);
+ }
+ }
+
+ return attestationUtilsFlags;
+ }
+
@Override
public boolean generateKeyPair(ComponentName who, String callerPackage, String algorithm,
ParcelableKeyGenParameterSpec parcelableKeySpec,
+ int idAttestationFlags,
KeymasterCertificateChain attestationChain) {
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_CERT_INSTALL);
+ // Get attestation flags, if any.
+ final int[] attestationUtilsFlags = translateIdAttestationFlags(idAttestationFlags);
+ final boolean deviceIdAttestationRequired = attestationUtilsFlags != null;
+ final int callingUid = mInjector.binderGetCallingUid();
+
+ if (deviceIdAttestationRequired && attestationUtilsFlags.length > 0) {
+ enforceIsDeviceOwnerOrCertInstallerOfDeviceOwner(who, callerPackage, callingUid);
+ } else {
+ enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
+ DELEGATION_CERT_INSTALL);
+ }
final KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec();
- if (TextUtils.isEmpty(keySpec.getKeystoreAlias())) {
+ final String alias = keySpec.getKeystoreAlias();
+ if (TextUtils.isEmpty(alias)) {
throw new IllegalArgumentException("Empty alias provided.");
}
- final String alias = keySpec.getKeystoreAlias();
// As the caller will be granted access to the key, ensure no UID was specified, as
// it will not have the desired effect.
if (keySpec.getUid() != KeyStore.UID_SELF) {
@@ -5070,7 +5141,10 @@
return false;
}
- final int callingUid = mInjector.binderGetCallingUid();
+ if (deviceIdAttestationRequired && (keySpec.getAttestationChallenge() == null)) {
+ throw new IllegalArgumentException(
+ "Requested Device ID attestation but challenge is empty.");
+ }
final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
final long id = mInjector.binderClearCallingIdentity();
@@ -5103,7 +5177,7 @@
final byte[] attestationChallenge = keySpec.getAttestationChallenge();
if (attestationChallenge != null) {
final boolean attestationResult = keyChain.attestKey(
- alias, attestationChallenge, attestationChain);
+ alias, attestationChallenge, attestationUtilsFlags, attestationChain);
if (!attestationResult) {
Log.e(LOG_TAG, String.format(
"Attestation for %s failed, deleting key.", alias));
@@ -11802,10 +11876,14 @@
final long id = mInjector.binderClearCallingIdentity();
try {
- //STOPSHIP add support for COMP, DO, edge cases when device is rebooted/work mode off,
+ //STOPSHIP add support for COMP, edge cases when device is rebooted/work mode off,
//transfer callbacks and broadcast
- if (isProfileOwner(admin, callingUserId)) {
- transferProfileOwner(admin, target, callingUserId);
+ synchronized (this) {
+ if (isProfileOwner(admin, callingUserId)) {
+ transferProfileOwnerLocked(admin, target, callingUserId);
+ } else if (isDeviceOwner(admin, callingUserId)) {
+ transferDeviceOwnerLocked(admin, target, callingUserId);
+ }
}
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -11815,15 +11893,25 @@
/**
* Transfers the profile owner for user with id profileOwnerUserId from admin to target.
*/
- private void transferProfileOwner(ComponentName admin, ComponentName target,
+ private void transferProfileOwnerLocked(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");
- }
+ 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");
+ }
+
+ /**
+ * Transfers the device owner for user with id userId from admin to target.
+ */
+ private void transferDeviceOwnerLocked(ComponentName admin, ComponentName target, int userId) {
+ transferActiveAdminUncheckedLocked(target, admin, userId);
+ mOwners.transferDeviceOwner(target);
+ Slog.i(LOG_TAG, "Device owner set: " + target + " on user " + userId);
+ mOwners.writeDeviceOwner();
+ mDeviceAdminServiceController.startServiceForOwner(
+ target.getPackageName(), userId, "transfer-device-owner");
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 9042a8d..2a23888 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -288,6 +288,17 @@
}
}
+ void transferDeviceOwner(ComponentName target) {
+ synchronized (mLock) {
+ // We don't set a name because it's not used anyway.
+ // See DevicePolicyManagerService#getDeviceOwnerName
+ mDeviceOwner = new OwnerInfo(null, target,
+ mDeviceOwner.userRestrictionsMigrated, mDeviceOwner.remoteBugreportUri,
+ mDeviceOwner.remoteBugreportHash);
+ pushToPackageManagerLocked();
+ }
+ }
+
ComponentName getProfileOwnerComponent(int userId) {
synchronized (mLock) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java b/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java
index c20c376..a473bc6 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java
@@ -16,19 +16,17 @@
package com.android.server.backup;
+import static com.google.common.truth.Truth.assertThat;
+
import android.app.AlarmManager;
import android.content.Context;
import android.os.Handler;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
-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.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;
@@ -36,19 +34,9 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import static com.google.common.truth.Truth.assertThat;
-
@RunWith(FrameworkRobolectricTestRunner.class)
-@Config(
- manifest = Config.NONE,
- sdk = 26,
- shadows = {
- ShadowContextImplForBackup.class,
- ShadowBackupTransportStub.class,
- ShadowPackageManagerForBackup.class
- }
-)
-@SystemLoaderClasses({TransportManager.class})
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderClasses({BackupManagerConstants.class})
@Presubmit
public class BackupManagerConstantsTest {
private static final String PACKAGE_NAME = "some.package.name";
@@ -59,17 +47,13 @@
MockitoAnnotations.initMocks(this);
}
- @After
- public void tearDown() throws Exception {
- }
-
@Test
public void testDefaultValues() throws Exception {
final Context context = RuntimeEnvironment.application.getApplicationContext();
final Handler handler = new Handler();
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.BACKUP_MANAGER_CONSTANTS, null);
+ Settings.Secure.putString(
+ context.getContentResolver(), Settings.Secure.BACKUP_MANAGER_CONSTANTS, null);
final BackupManagerConstants constants =
new BackupManagerConstants(handler, context.getContentResolver());
@@ -93,17 +77,21 @@
final Context context = RuntimeEnvironment.application.getApplicationContext();
final Handler handler = new Handler();
- final String recievers_setting = "backup_finished_notification_receivers=" +
- PACKAGE_NAME + ':' + ANOTHER_PACKAGE_NAME;
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.BACKUP_MANAGER_CONSTANTS, recievers_setting);
+ final String recieversSetting =
+ "backup_finished_notification_receivers="
+ + PACKAGE_NAME
+ + ':'
+ + ANOTHER_PACKAGE_NAME;
+ Settings.Secure.putString(
+ context.getContentResolver(),
+ Settings.Secure.BACKUP_MANAGER_CONSTANTS,
+ recieversSetting);
final BackupManagerConstants constants =
new BackupManagerConstants(handler, context.getContentResolver());
constants.start();
- assertThat(constants.getBackupFinishedNotificationReceivers()).isEqualTo(new String[] {
- PACKAGE_NAME,
- ANOTHER_PACKAGE_NAME});
+ assertThat(constants.getBackupFinishedNotificationReceivers())
+ .isEqualTo(new String[] {PACKAGE_NAME, ANOTHER_PACKAGE_NAME});
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 60783db..58ac7d2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -17,6 +17,10 @@
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
+import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
@@ -71,6 +75,7 @@
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.security.KeyChain;
+import android.security.keystore.AttestationUtils;
import android.telephony.TelephonyManager;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
@@ -4459,6 +4464,47 @@
});
}
+ private void assertAttestationFlags(int attestationFlags, int[] expectedFlags) {
+ int[] gotFlags = DevicePolicyManagerService.translateIdAttestationFlags(attestationFlags);
+ Arrays.sort(gotFlags);
+ Arrays.sort(expectedFlags);
+ assertTrue(Arrays.equals(expectedFlags, gotFlags));
+ }
+
+ public void testTranslationOfIdAttestationFlag() {
+ int[] allIdTypes = new int[]{ID_TYPE_SERIAL, ID_TYPE_IMEI, ID_TYPE_MEID};
+ int[] correspondingAttUtilsTypes = new int[]{
+ AttestationUtils.ID_TYPE_SERIAL, AttestationUtils.ID_TYPE_IMEI,
+ AttestationUtils.ID_TYPE_MEID};
+
+ // Test translation of zero flags
+ assertNull(DevicePolicyManagerService.translateIdAttestationFlags(0));
+
+ // Test translation of the ID_TYPE_BASE_INFO flag, which should yield an empty, but
+ // non-null array
+ assertAttestationFlags(ID_TYPE_BASE_INFO, new int[] {});
+
+ // Test translation of a single flag
+ assertAttestationFlags(ID_TYPE_BASE_INFO | ID_TYPE_SERIAL,
+ new int[] {AttestationUtils.ID_TYPE_SERIAL});
+ assertAttestationFlags(ID_TYPE_SERIAL, new int[] {AttestationUtils.ID_TYPE_SERIAL});
+
+ // Test translation of two flags
+ assertAttestationFlags(ID_TYPE_SERIAL | ID_TYPE_IMEI,
+ new int[] {AttestationUtils.ID_TYPE_IMEI, AttestationUtils.ID_TYPE_SERIAL});
+ assertAttestationFlags(ID_TYPE_BASE_INFO | ID_TYPE_MEID | ID_TYPE_SERIAL,
+ new int[] {AttestationUtils.ID_TYPE_MEID, AttestationUtils.ID_TYPE_SERIAL});
+
+ // Test translation of all three flags
+ assertAttestationFlags(ID_TYPE_SERIAL | ID_TYPE_IMEI | ID_TYPE_MEID,
+ new int[] {AttestationUtils.ID_TYPE_IMEI, AttestationUtils.ID_TYPE_SERIAL,
+ AttestationUtils.ID_TYPE_MEID});
+ // Test translation of all three flags
+ assertAttestationFlags(ID_TYPE_SERIAL | ID_TYPE_IMEI | ID_TYPE_MEID | ID_TYPE_BASE_INFO,
+ new int[] {AttestationUtils.ID_TYPE_IMEI, AttestationUtils.ID_TYPE_SERIAL,
+ AttestationUtils.ID_TYPE_MEID});
+ }
+
private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
when(getServices().settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
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 96ff461..6e57f47 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -45,6 +45,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
/**
* Test class for {@link SurfaceAnimatorTest}.
@@ -82,6 +83,7 @@
verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
callbackCaptor.getValue().onAnimationFinished(mSpec);
+ waitUntilPrepareSurfaces();
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
@@ -104,11 +106,13 @@
// First animation was finished, but this shouldn't cancel the second animation
callbackCaptor.getValue().onAnimationFinished(mSpec);
+ waitUntilPrepareSurfaces();
assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
// Second animation was finished
verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
callbackCaptor.getValue().onAnimationFinished(mSpec2);
+ waitUntilPrepareSurfaces();
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
}
@@ -160,6 +164,7 @@
assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
assertFalse(mAnimatable.mPendingDestroySurfaces.contains(leash));
callbackCaptor.getValue().onAnimationFinished(mSpec);
+ waitUntilPrepareSurfaces();
assertNotAnimating(mAnimatable2);
assertTrue(mAnimatable2.mFinishedCallbackCalled);
assertTrue(mAnimatable2.mPendingDestroySurfaces.contains(leash));
@@ -175,6 +180,14 @@
assertNull(animatable.mSurfaceAnimator.getAnimation());
}
+ private void waitUntilPrepareSurfaces() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ synchronized (sWm.mWindowMap) {
+ sWm.mAnimator.addAfterPrepareSurfacesRunnable(latch::countDown);
+ }
+ latch.await();
+ }
+
private class MyAnimatable implements Animatable {
final SurfaceControl mParent;
@@ -233,6 +246,11 @@
}
@Override
+ public SurfaceControl getAnimationLeashParent() {
+ return mParent;
+ }
+
+ @Override
public SurfaceControl getSurfaceControl() {
return mSurface;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index c699a94..ff840f3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -103,6 +103,7 @@
context.getDisplay().getDisplayInfo(mDisplayInfo);
mDisplayContent = createNewDisplay();
+ sWm.mAnimator.mInitialized = true;
sWm.mDisplayEnabled = true;
sWm.mDisplayReady = true;
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/provider/Telephony.java
similarity index 100%
rename from telephony/java/android/telephony/Telephony.java
rename to telephony/java/android/provider/Telephony.java