Merge "Fix TaskView cropping for transient taskbar" into udc-dev
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index cd96a1e..765a17f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -925,7 +925,7 @@
public class KeyguardManager {
method @RequiresPermission(android.Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) public long addWeakEscrowToken(@NonNull byte[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.WeakEscrowTokenActivatedListener);
- method @NonNull @RequiresPermission(android.Manifest.permission.CHECK_REMOTE_LOCKSCREEN) public android.content.Intent createConfirmDeviceCredentialForRemoteValidationIntent(@NonNull android.app.StartLockscreenValidationRequest, @NonNull android.content.ComponentName, @Nullable CharSequence, @Nullable CharSequence, @Nullable CharSequence, @Nullable CharSequence);
+ method @NonNull @RequiresPermission(android.Manifest.permission.CHECK_REMOTE_LOCKSCREEN) public android.content.Intent createConfirmDeviceCredentialForRemoteValidationIntent(@NonNull android.app.RemoteLockscreenValidationSession, @NonNull android.content.ComponentName, @Nullable CharSequence, @Nullable CharSequence, @Nullable CharSequence, @Nullable CharSequence);
method public android.content.Intent createConfirmFactoryResetCredentialIntent(CharSequence, CharSequence, CharSequence);
method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public int getMinLockLength(boolean, int);
method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public boolean getPrivateNotificationsAllowed();
@@ -937,7 +937,7 @@
method @RequiresPermission(android.Manifest.permission.SHOW_KEYGUARD_MESSAGE) public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable CharSequence, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean setLock(int, @NonNull byte[], int);
method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public void setPrivateNotificationsAllowed(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.CHECK_REMOTE_LOCKSCREEN) public android.app.StartLockscreenValidationRequest startRemoteLockscreenValidation();
+ method @NonNull @RequiresPermission(android.Manifest.permission.CHECK_REMOTE_LOCKSCREEN) public android.app.RemoteLockscreenValidationSession startRemoteLockscreenValidation();
method @RequiresPermission(android.Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN) public boolean unregisterWeakEscrowTokenRemovedListener(@NonNull android.app.KeyguardManager.WeakEscrowTokenRemovedListener);
method @NonNull @RequiresPermission(android.Manifest.permission.CHECK_REMOTE_LOCKSCREEN) public android.app.RemoteLockscreenValidationResult validateRemoteLockscreen(@NonNull byte[]);
field public static final int PASSWORD = 0; // 0x0
@@ -1026,6 +1026,7 @@
field public static final int RESULT_GUESS_VALID = 1; // 0x1
field public static final int RESULT_LOCKOUT = 3; // 0x3
field public static final int RESULT_NO_REMAINING_ATTEMPTS = 4; // 0x4
+ field public static final int RESULT_SESSION_EXPIRED = 5; // 0x5
}
public static final class RemoteLockscreenValidationResult.Builder {
@@ -1035,6 +1036,23 @@
method @NonNull public android.app.RemoteLockscreenValidationResult.Builder setTimeoutMillis(long);
}
+ public final class RemoteLockscreenValidationSession implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getLockType();
+ method public int getRemainingAttempts();
+ method @NonNull public byte[] getSourcePublicKey();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.RemoteLockscreenValidationSession> CREATOR;
+ }
+
+ public static final class RemoteLockscreenValidationSession.Builder {
+ ctor public RemoteLockscreenValidationSession.Builder();
+ method @NonNull public android.app.RemoteLockscreenValidationSession build();
+ method @NonNull public android.app.RemoteLockscreenValidationSession.Builder setLockType(int);
+ method @NonNull public android.app.RemoteLockscreenValidationSession.Builder setRemainingAttempts(int);
+ method @NonNull public android.app.RemoteLockscreenValidationSession.Builder setSourcePublicKey(@NonNull byte[]);
+ }
+
public final class RuntimeAppOpAccessMessage implements android.os.Parcelable {
ctor public RuntimeAppOpAccessMessage(@IntRange(from=0L) int, @IntRange(from=0L) int, @NonNull String, @Nullable String, @NonNull String, int);
method public int describeContents();
@@ -1052,23 +1070,6 @@
method public void launchAssist(@Nullable android.os.Bundle);
}
- public final class StartLockscreenValidationRequest implements android.os.Parcelable {
- method public int describeContents();
- method public int getLockscreenUiType();
- method public int getRemainingAttempts();
- method @NonNull public byte[] getSourcePublicKey();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.StartLockscreenValidationRequest> CREATOR;
- }
-
- public static final class StartLockscreenValidationRequest.Builder {
- ctor public StartLockscreenValidationRequest.Builder();
- method @NonNull public android.app.StartLockscreenValidationRequest build();
- method @NonNull public android.app.StartLockscreenValidationRequest.Builder setLockscreenUiType(int);
- method @NonNull public android.app.StartLockscreenValidationRequest.Builder setRemainingAttempts(int);
- method @NonNull public android.app.StartLockscreenValidationRequest.Builder setSourcePublicKey(@NonNull byte[]);
- }
-
public class StatusBarManager {
method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public int getNavBarMode();
@@ -14615,7 +14616,6 @@
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getCompleteActiveSubscriptionIdList();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int);
method @NonNull public static android.content.res.Resources getResourcesForSubId(@NonNull android.content.Context, int);
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION) public android.os.UserHandle getSubscriptionUserHandle(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int);
method public void requestEmbeddedSubscriptionInfoListRefresh();
method public void requestEmbeddedSubscriptionInfoListRefresh(int);
@@ -14625,7 +14625,6 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultVoiceSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION) public void setSubscriptionUserHandle(int, @Nullable android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUiccApplicationsEnabled(int, boolean);
field @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS) public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED";
field @NonNull public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index be0d1c9..0ef8e92 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -146,13 +146,13 @@
public static final String EXTRA_CHECKBOX_LABEL = "android.app.extra.CHECKBOX_LABEL";
/**
- * A {@link StartLockscreenValidationRequest} extra to be sent along with
+ * A {@link RemoteLockscreenValidationSession} extra to be sent along with
* {@link #ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL} containing the data needed to prompt for
* a remote device's lock screen.
* @hide
*/
- public static final String EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST =
- "android.app.extra.START_LOCKSCREEN_VALIDATION_REQUEST";
+ public static final String EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION =
+ "android.app.extra.REMOTE_LOCKSCREEN_VALIDATION_SESSION";
/**
* Result code returned by the activity started by
@@ -359,8 +359,7 @@
/**
* Get an Intent to launch an activity to prompt the user to confirm the
* credentials (pin, pattern or password) of a remote device.
- * @param startLockscreenValidationRequest contains information necessary to start remote device
- * credential validation.
+ * @param session contains information necessary to start remote device credential validation.
* @param remoteLockscreenValidationServiceComponent
* the {@link ComponentName} of the implementation of
* {@link android.service.remotelockscreenvalidation.RemoteLockscreenValidationService}
@@ -376,15 +375,14 @@
@RequiresPermission(Manifest.permission.CHECK_REMOTE_LOCKSCREEN)
@NonNull
public Intent createConfirmDeviceCredentialForRemoteValidationIntent(
- @NonNull StartLockscreenValidationRequest startLockscreenValidationRequest,
+ @NonNull RemoteLockscreenValidationSession session,
@NonNull ComponentName remoteLockscreenValidationServiceComponent,
@Nullable CharSequence title,
@Nullable CharSequence description,
@Nullable CharSequence checkboxLabel,
@Nullable CharSequence alternateButtonLabel) {
Intent intent = new Intent(ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL)
- .putExtra(
- EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST, startLockscreenValidationRequest)
+ .putExtra(EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION, session)
.putExtra(Intent.EXTRA_COMPONENT_NAME, remoteLockscreenValidationServiceComponent)
.putExtra(EXTRA_TITLE, title)
.putExtra(EXTRA_DESCRIPTION, description)
@@ -1157,7 +1155,7 @@
@SystemApi
@RequiresPermission(Manifest.permission.CHECK_REMOTE_LOCKSCREEN)
@NonNull
- public StartLockscreenValidationRequest startRemoteLockscreenValidation() {
+ public RemoteLockscreenValidationSession startRemoteLockscreenValidation() {
return mLockPatternUtils.startRemoteLockscreenValidation();
}
@@ -1165,11 +1163,10 @@
* Verifies credentials guess from a remote device.
*
* <p>Secret must be encrypted using {@code SecureBox} library
- * with public key from {@code StartLockscreenValidationRequest}
+ * with public key from {@code RemoteLockscreenValidationSession}
* and header set to {@code "encrypted_remote_credentials"} in UTF-8 encoding.
*
- * @throws IllegalStateException if there is no active lock screen validation session or
- * there was a decryption error.
+ * @throws IllegalStateException if there was a decryption error.
*
* @hide
*/
diff --git a/core/java/android/app/RemoteLockscreenValidationResult.java b/core/java/android/app/RemoteLockscreenValidationResult.java
index 0245f8c..bbb3567 100644
--- a/core/java/android/app/RemoteLockscreenValidationResult.java
+++ b/core/java/android/app/RemoteLockscreenValidationResult.java
@@ -55,10 +55,16 @@
*/
public static final int RESULT_NO_REMAINING_ATTEMPTS = 4;
+ /**
+ * New lockscreen validation session is required to verify guess.
+ */
+ public static final int RESULT_SESSION_EXPIRED = 5;
+
@IntDef({RESULT_GUESS_VALID,
RESULT_GUESS_INVALID,
RESULT_LOCKOUT,
- RESULT_NO_REMAINING_ATTEMPTS})
+ RESULT_NO_REMAINING_ATTEMPTS,
+ RESULT_SESSION_EXPIRED})
@Retention(RetentionPolicy.SOURCE)
@interface ResultCode {}
diff --git a/core/java/android/app/StartLockscreenValidationRequest.aidl b/core/java/android/app/RemoteLockscreenValidationSession.aidl
similarity index 93%
rename from core/java/android/app/StartLockscreenValidationRequest.aidl
rename to core/java/android/app/RemoteLockscreenValidationSession.aidl
index 367dfee..edc8d56 100644
--- a/core/java/android/app/StartLockscreenValidationRequest.aidl
+++ b/core/java/android/app/RemoteLockscreenValidationSession.aidl
@@ -17,4 +17,4 @@
package android.app;
/** {@hide} */
-parcelable StartLockscreenValidationRequest;
+parcelable RemoteLockscreenValidationSession;
diff --git a/core/java/android/app/StartLockscreenValidationRequest.java b/core/java/android/app/RemoteLockscreenValidationSession.java
similarity index 69%
rename from core/java/android/app/StartLockscreenValidationRequest.java
rename to core/java/android/app/RemoteLockscreenValidationSession.java
index e818195..c6592e3 100644
--- a/core/java/android/app/StartLockscreenValidationRequest.java
+++ b/core/java/android/app/RemoteLockscreenValidationSession.java
@@ -30,44 +30,45 @@
* @hide
*/
@SystemApi
-public final class StartLockscreenValidationRequest implements Parcelable {
+public final class RemoteLockscreenValidationSession implements Parcelable {
@LockTypes
- private int mLockscreenUiType;
+ private int mLockType;
private byte[] mSourcePublicKey;
private int mRemainingAttempts;
- public static final @NonNull Parcelable.Creator<StartLockscreenValidationRequest> CREATOR = new
- Parcelable.Creator<StartLockscreenValidationRequest>() {
+ public static final @NonNull Parcelable.Creator<RemoteLockscreenValidationSession> CREATOR = new
+ Parcelable.Creator<RemoteLockscreenValidationSession>() {
@Override
- public StartLockscreenValidationRequest createFromParcel(Parcel source) {
- return new StartLockscreenValidationRequest(source);
+ public RemoteLockscreenValidationSession createFromParcel(Parcel source) {
+ return new RemoteLockscreenValidationSession(source);
}
@Override
- public StartLockscreenValidationRequest[] newArray(int size) {
- return new StartLockscreenValidationRequest[size];
+ public RemoteLockscreenValidationSession[] newArray(int size) {
+ return new RemoteLockscreenValidationSession[size];
}
};
/**
- * Builder for {@code StartLockscreenValidationRequest}
+ * Builder for {@code RemoteLockscreenValidationSession}
*/
public static final class Builder {
- private StartLockscreenValidationRequest mInstance = new StartLockscreenValidationRequest();
+ private RemoteLockscreenValidationSession mInstance =
+ new RemoteLockscreenValidationSession();
/**
* Sets UI type.
* Default value is {@code LockTypes.PASSWORD}
*
- * @param lockscreenUiType The UI format
+ * @param lockType The UI format
* @return This builder.
*/
- public @NonNull Builder setLockscreenUiType(@LockTypes int lockscreenUiType) {
- mInstance.mLockscreenUiType = lockscreenUiType;
+ public @NonNull Builder setLockType(@LockTypes int lockType) {
+ mInstance.mLockType = lockType;
return this;
}
@@ -92,11 +93,11 @@
}
/**
- * Creates {@code StartLockscreenValidationRequest}
+ * Creates {@code RemoteLockscreenValidationSession}
*
* @throws NullPointerException if required fields are not set.
*/
- public @NonNull StartLockscreenValidationRequest build() {
+ public @NonNull RemoteLockscreenValidationSession build() {
Objects.requireNonNull(mInstance.mSourcePublicKey);
return mInstance;
}
@@ -105,8 +106,8 @@
/**
* Specifies lock screen credential type.
*/
- public @LockTypes int getLockscreenUiType() {
- return mLockscreenUiType;
+ public @LockTypes int getLockType() {
+ return mLockType;
}
/**
@@ -127,16 +128,16 @@
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeInt(mLockscreenUiType);
+ out.writeInt(mLockType);
out.writeByteArray(mSourcePublicKey);
out.writeInt(mRemainingAttempts);
}
- private StartLockscreenValidationRequest() {
+ private RemoteLockscreenValidationSession() {
}
- private StartLockscreenValidationRequest(Parcel in) {
- mLockscreenUiType = in.readInt();
+ private RemoteLockscreenValidationSession(Parcel in) {
+ mLockType = in.readInt();
mSourcePublicKey = in.createByteArray();
mRemainingAttempts = in.readInt();
}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 4532661..4b3eb3a 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -1392,10 +1392,6 @@
return sql.replaceAll("[\\s]*\\n+[\\s]*", " ");
}
- void clearPreparedStatementCache() {
- mPreparedStatementCache.evictAll();
- }
-
/**
* Holder type for a prepared statement.
*
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 6023d66..069c264 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -1126,16 +1126,6 @@
mConnectionWaiterPool = waiter;
}
- void clearAcquiredConnectionsPreparedStatementCache() {
- synchronized (mLock) {
- if (!mAcquiredConnections.isEmpty()) {
- for (SQLiteConnection connection : mAcquiredConnections.keySet()) {
- connection.clearPreparedStatementCache();
- }
- }
- }
- }
-
/**
* Dumps debugging information about this connection pool.
*
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index db898c3..c08294f 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -2088,12 +2088,10 @@
try (SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs)) {
return statement.executeUpdateDelete();
} finally {
- // If schema was updated, close non-primary connections and clear prepared
- // statement caches of active connections, otherwise they might have outdated
- // schema information.
+ // If schema was updated, close non-primary connections, otherwise they might
+ // have outdated schema information
if (statementType == DatabaseUtils.STATEMENT_DDL) {
mConnectionPoolLocked.closeAvailableNonPrimaryConnectionsAndLogExceptions();
- mConnectionPoolLocked.clearAcquiredConnectionsPreparedStatementCache();
}
}
} finally {
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index fbc0184..6cd4a2e 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1189,8 +1189,8 @@
PackageManager packageManager = context.getPackageManager();
try {
- return packageManager.getProperty(context.getOpPackageName(),
- PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT).getBoolean();
+ return packageManager.getProperty(PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT,
+ context.getOpPackageName()).getBoolean();
} catch (PackageManager.NameNotFoundException e) {
// No such property
}
diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
index 9cd5aa0..3190c69 100644
--- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java
+++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
@@ -328,7 +328,7 @@
@NonNull Context context,
@UserIdInt int userId,
boolean disableSystemAppVerificationForTests,
- Set<ServiceInfo> enabledServices) {
+ Set<ComponentName> enabledServices) {
requireNonNull(context, "context must not be null");
final List<CredentialProviderInfo> providerInfos = new ArrayList<>();
@@ -342,7 +342,7 @@
si,
/* isSystemProvider= */ true,
disableSystemAppVerificationForTests,
- enabledServices.contains(si));
+ enabledServices.contains(si.getComponentName()));
if (cpi.isSystemProvider()) {
providerInfos.add(cpi);
} else {
@@ -371,31 +371,6 @@
}
/**
- * Returns a valid credential provider that has the given package name. Returns null if no
- * match is found.
- */
- @Nullable
- public static CredentialProviderInfo getCredentialProviderFromPackageName(
- @NonNull Context context,
- int userId,
- @NonNull String packageName,
- int providerFilter,
- @NonNull Set<ServiceInfo> enabledServices) {
- requireNonNull(context, "context must not be null");
- requireNonNull(packageName, "package name must not be null");
- requireNonNull(enabledServices, "enabledServices must not be null");
-
- for (CredentialProviderInfo credentialProviderInfo : getCredentialProviderServices(context,
- userId, providerFilter, enabledServices)) {
- if (credentialProviderInfo.getServiceInfo()
- .packageName.equals(packageName)) {
- return credentialProviderInfo;
- }
- }
- return null;
- }
-
- /**
* Returns the valid credential provider services available for the user with the given {@code
* userId}.
*/
@@ -404,7 +379,7 @@
@NonNull Context context,
int userId,
int providerFilter,
- Set<ServiceInfo> enabledServices) {
+ Set<ComponentName> enabledServices) {
requireNonNull(context, "context must not be null");
// Get the device policy.
@@ -433,7 +408,7 @@
@NonNull Context context,
int userId,
int providerFilter,
- Set<ServiceInfo> enabledServices) {
+ Set<ComponentName> enabledServices) {
requireNonNull(context, "context must not be null");
// Get the device policy.
@@ -539,7 +514,7 @@
@NonNull Context context,
@UserIdInt int userId,
boolean disableSystemAppVerificationForTests,
- Set<ServiceInfo> enabledServices) {
+ Set<ComponentName> enabledServices) {
final List<CredentialProviderInfo> services = new ArrayList<>();
final List<ResolveInfo> resolveInfos =
context.getPackageManager()
@@ -549,6 +524,11 @@
userId);
for (ResolveInfo resolveInfo : resolveInfos) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ if (serviceInfo == null) {
+ Log.i(TAG, "No serviceInfo found for resolveInfo so skipping this provider");
+ continue;
+ }
+
try {
CredentialProviderInfo cpi =
CredentialProviderInfoFactory.create(
@@ -556,7 +536,7 @@
serviceInfo,
/* isSystemProvider= */ false,
disableSystemAppVerificationForTests,
- enabledServices.contains(serviceInfo));
+ enabledServices.contains(serviceInfo.getComponentName()));
if (!cpi.isSystemProvider()) {
services.add(cpi);
}
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index a2fa139..a389223 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -58,11 +58,13 @@
setTitle(title);
}
- final Bundle extras = getIntent().getExtras();
- mCallback = (DreamService.DreamActivityCallbacks) extras.getBinder(EXTRA_CALLBACK);
-
- if (mCallback != null) {
+ final Object callback = getIntent().getExtras().getBinder(EXTRA_CALLBACK);
+ if (callback instanceof DreamService.DreamActivityCallbacks) {
+ mCallback = (DreamService.DreamActivityCallbacks) callback;
mCallback.onActivityCreated(this);
+ } else {
+ mCallback = null;
+ finishAndRemoveTask();
}
}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index a646df3..a781454 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -18,7 +18,7 @@
import android.app.PendingIntent;
import android.app.RemoteLockscreenValidationResult;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.app.trust.IStrongAuthTracker;
import android.os.Bundle;
import android.security.keystore.recovery.WrappedApplicationKey;
@@ -95,7 +95,7 @@
in byte[] recoveryKeyBlob,
in List<WrappedApplicationKey> applicationKeys);
void closeSession(in String sessionId);
- StartLockscreenValidationRequest startRemoteLockscreenValidation();
+ RemoteLockscreenValidationSession startRemoteLockscreenValidation();
RemoteLockscreenValidationResult validateRemoteLockscreen(in byte[] encryptedCredential);
boolean hasSecureLockScreen();
boolean tryUnlockWithCachedUnifiedChallenge(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b86020e..4d91410 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -29,7 +29,7 @@
import android.annotation.UserIdInt;
import android.app.PropertyInvalidatedCache;
import android.app.RemoteLockscreenValidationResult;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.app.admin.DevicePolicyManager;
import android.app.admin.PasswordMetrics;
import android.app.trust.IStrongAuthTracker;
@@ -1875,7 +1875,7 @@
* Starts a session to verify lockscreen credentials provided by a remote device.
*/
@NonNull
- public StartLockscreenValidationRequest startRemoteLockscreenValidation() {
+ public RemoteLockscreenValidationSession startRemoteLockscreenValidation() {
try {
return getLockSettings().startRemoteLockscreenValidation();
} catch (RemoteException e) {
diff --git a/data/keyboards/Vendor_004c_Product_0265.idc b/data/keyboards/Vendor_004c_Product_0265.idc
deleted file mode 120000
index 707dfcf..0000000
--- a/data/keyboards/Vendor_004c_Product_0265.idc
+++ /dev/null
@@ -1 +0,0 @@
-Vendor_05ac_Product_0265.idc
\ No newline at end of file
diff --git a/data/keyboards/Vendor_03f6_Product_a001.idc b/data/keyboards/Vendor_03f6_Product_a001.idc
deleted file mode 100644
index bcb4ee3..0000000
--- a/data/keyboards/Vendor_03f6_Product_a001.idc
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2023 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.
-
-#
-# Brydge Touchpad
-#
-
-# Reports from this touchpad sometimes get bunched together due to Bluetooth
-# batching, leading to bad timestamps that mess up finger velocity calculations.
-# To fix this, set a fake delta using the touchpad's known report rate.
-gestureProp.Fake_Timestamp_Delta = 0.010
diff --git a/data/keyboards/Vendor_046d_Product_4011.idc b/data/keyboards/Vendor_046d_Product_4011.idc
deleted file mode 100644
index 3a23830..0000000
--- a/data/keyboards/Vendor_046d_Product_4011.idc
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2023 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.
-
-#
-# Logitech Wireless Touchpad
-#
-
-gestureProp.Touchpad_Stack_Version = 1
-gestureProp.IIR_b0 = 1
-gestureProp.IIR_b1 = 0
-gestureProp.IIR_b2 = 0
-gestureProp.IIR_b3 = 0
-gestureProp.IIR_a1 = 0
-gestureProp.IIR_a2 = 0
-gestureProp.Pressure_Calibration_Offset = -313.240741792594
-gestureProp.Pressure_Calibration_Slope = 4.39678062436752
-gestureProp.Max_Allowed_Pressure_Change_Per_Sec = 100000.0
-gestureProp.Max_Hysteresis_Pressure_Per_Sec = 100000.0
-gestureProp.Palm_Pressure = 100000.0
-gestureProp.Two_Finger_Vertical_Close_Distance_Thresh = 35.0
-gestureProp.Fling_Buffer_Suppress_Zero_Length_Scrolls = 0
diff --git a/data/keyboards/Vendor_046d_Product_4101.idc b/data/keyboards/Vendor_046d_Product_4101.idc
deleted file mode 100644
index 47e2530..0000000
--- a/data/keyboards/Vendor_046d_Product_4101.idc
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2023 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.
-
-#
-# Logitech T650
-#
-
-gestureProp.Touchpad_Stack_Version = 1
-gestureProp.IIR_b0 = 1
-gestureProp.IIR_b1 = 0
-gestureProp.IIR_b2 = 0
-gestureProp.IIR_b3 = 0
-gestureProp.IIR_a1 = 0
-gestureProp.IIR_a2 = 0
-gestureProp.Pressure_Calibration_Offset = -0.439288351750068
-gestureProp.Pressure_Calibration_Slope = 3.05998553523335
-gestureProp.Max_Allowed_Pressure_Change_Per_Sec = 100000.0
-gestureProp.Max_Hysteresis_Pressure_Per_Sec = 100000.0
-gestureProp.Two_Finger_Vertical_Close_Distance_Thresh = 35.0
-gestureProp.Fling_Buffer_Suppress_Zero_Length_Scrolls = 0
diff --git a/data/keyboards/Vendor_046d_Product_4102.idc b/data/keyboards/Vendor_046d_Product_4102.idc
deleted file mode 100644
index e33a28a..0000000
--- a/data/keyboards/Vendor_046d_Product_4102.idc
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2023 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.
-
-#
-# Logitech TK820
-#
-
-gestureProp.Touchpad_Stack_Version = 2
-# Pressure jumps around a lot on this touchpad, so allow that:
-gestureProp.Max_Allowed_Pressure_Change_Per_Sec = 100000.0
-gestureProp.Max_Hysteresis_Pressure_Per_Sec = 100000.0
-gestureProp.Pressure_Calibration_Offset = -18.8078435
-gestureProp.Pressure_Calibration_Slope = 2.466208137
diff --git a/data/keyboards/Vendor_046d_Product_b00c.idc b/data/keyboards/Vendor_046d_Product_b00c.idc
deleted file mode 100644
index a49970c..0000000
--- a/data/keyboards/Vendor_046d_Product_b00c.idc
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2023 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.
-
-#
-# Logitech T651
-#
-
-gestureProp.Touchpad_Stack_Version = 1
-gestureProp.IIR_b0 = 1
-gestureProp.IIR_b1 = 0
-gestureProp.IIR_b2 = 0
-gestureProp.IIR_b3 = 0
-gestureProp.IIR_a1 = 0
-gestureProp.IIR_a2 = 0
-gestureProp.Pressure_Calibration_Offset = -4.46520447177073
-gestureProp.Pressure_Calibration_Slope = 3.21071719332644
-gestureProp.Max_Allowed_Pressure_Change_Per_Sec = 100000.0
-gestureProp.Max_Hysteresis_Pressure_Per_Sec = 100000.0
-gestureProp.Two_Finger_Vertical_Close_Distance_Thresh = 35.0
-gestureProp.Fling_Buffer_Suppress_Zero_Length_Scrolls = 0
diff --git a/data/keyboards/Vendor_05ac_Product_0265.idc b/data/keyboards/Vendor_05ac_Product_0265.idc
deleted file mode 100644
index d72de64..0000000
--- a/data/keyboards/Vendor_05ac_Product_0265.idc
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright 2023 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.
-
-#
-# Apple Magic Trackpad 2 configuration file
-# Bluetooth vendor ID 004c
-# USB vendor ID 05ac
-#
-
-gestureProp.Pressure_Calibration_Offset = 30
-gestureProp.Palm_Pressure = 250.0
-gestureProp.Palm_Width = 20.0
-gestureProp.Multiple_Palm_Width = 20.0
-
-# Enable Stationary Wiggle Filter
-gestureProp.Stationary_Wiggle_Filter_Enabled = 1
-gestureProp.Finger_Moving_Energy = 0.0008
-gestureProp.Finger_Moving_Hysteresis = 0.0004
-
-# Avoid accidental scroll/move on finger lift
-gestureProp.Max_Stationary_Move_Speed = 47
-gestureProp.Max_Stationary_Move_Speed_Hysteresis = 1
-gestureProp.Max_Stationary_Move_Suppress_Distance = 0.2
diff --git a/data/keyboards/Vendor_05ac_Product_030e.idc b/data/keyboards/Vendor_05ac_Product_030e.idc
deleted file mode 100644
index 23a2e18..0000000
--- a/data/keyboards/Vendor_05ac_Product_030e.idc
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2023 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.
-
-#
-# Apple Magic Trackpad
-#
-
-gestureProp.Touchpad_Stack_Version = 1
-# We are using raw touch major value as pressure value, so set the Palm
-# pressure threshold high.
-gestureProp.Palm_Pressure = 1000
-gestureProp.Compute_Surface_Area_from_Pressure = 0
-gestureProp.IIR_b0 = 1
-gestureProp.IIR_b1 = 0
-gestureProp.IIR_b2 = 0
-gestureProp.IIR_b3 = 0
-gestureProp.IIR_a1 = 0
-gestureProp.IIR_a2 = 0
-# NOTE: bias on X-axis is uncalibrated
-gestureProp.Touchpad_Device_Output_Bias_on_X-Axis = -283.3226025266607
-gestureProp.Touchpad_Device_Output_Bias_on_Y-Axis = -283.3226025266607
-gestureProp.Max_Allowed_Pressure_Change_Per_Sec = 100000.0
-gestureProp.Max_Hysteresis_Pressure_Per_Sec = 100000.0
-# Drumroll suppression causes janky movement on this touchpad.
-gestureProp.Drumroll_Suppression_Enable = 0
-gestureProp.Two_Finger_Vertical_Close_Distance_Thresh = 35.0
-gestureProp.Fling_Buffer_Suppress_Zero_Length_Scrolls = 0
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
index 68ff806..65955b1 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Rect;
+import android.hardware.devicestate.DeviceStateManager;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -33,7 +34,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-/** A representation of a folding feature for both Extension and Sidecar.
+/**
+ * A representation of a folding feature for both Extension and Sidecar.
* For Sidecar this is the same as combining {@link androidx.window.sidecar.SidecarDeviceState} and
* {@link androidx.window.sidecar.SidecarDisplayFeature}. For Extensions this is the mirror of
* {@link androidx.window.extensions.layout.FoldingFeature}.
@@ -67,10 +69,11 @@
public static final int COMMON_STATE_UNKNOWN = -1;
/**
- * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar
- * and Extensions do not match exactly.
+ * A common state that contains no folding features. For example, an in-folding device in the
+ * "closed" device state.
*/
- public static final int COMMON_STATE_FLAT = 3;
+ public static final int COMMON_STATE_NO_FOLDING_FEATURES = 1;
+
/**
* A common state to represent a HALF_OPENED hinge. This is needed because the definitions in
* Sidecar and Extensions do not match exactly.
@@ -78,9 +81,27 @@
public static final int COMMON_STATE_HALF_OPENED = 2;
/**
- * The possible states for a folding hinge.
+ * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar
+ * and Extensions do not match exactly.
*/
- @IntDef({COMMON_STATE_UNKNOWN, COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED})
+ public static final int COMMON_STATE_FLAT = 3;
+
+ /**
+ * A common state where the hinge state should be derived using the base state from
+ * {@link DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)} instead of the
+ * emulated state. This is an internal state and must not be passed to clients.
+ */
+ public static final int COMMON_STATE_USE_BASE_STATE = 1000;
+
+ /**
+ * The possible states for a folding hinge. Common in this context means normalized between
+ * extensions and sidecar.
+ */
+ @IntDef({COMMON_STATE_UNKNOWN,
+ COMMON_STATE_NO_FOLDING_FEATURES,
+ COMMON_STATE_HALF_OPENED,
+ COMMON_STATE_FLAT,
+ COMMON_STATE_USE_BASE_STATE})
@Retention(RetentionPolicy.SOURCE)
public @interface State {
}
@@ -167,7 +188,7 @@
}
String stateString = featureMatcher.group(6);
stateString = stateString == null ? "" : stateString;
- final int state;
+ @State final int state;
switch (stateString) {
case PATTERN_STATE_FLAT:
state = COMMON_STATE_FLAT;
@@ -191,8 +212,8 @@
@NonNull
private final Rect mRect;
- CommonFoldingFeature(int type, int state, @NonNull Rect rect) {
- assertValidState(state);
+ CommonFoldingFeature(int type, @State int state, @NonNull Rect rect) {
+ assertReportableState(state);
this.mType = type;
this.mState = state;
if (rect.width() == 0 && rect.height() == 0) {
@@ -231,13 +252,22 @@
}
@Override
+ public String toString() {
+ return "CommonFoldingFeature=[Type: " + mType + ", state: " + mState + "]";
+ }
+
+ @Override
public int hashCode() {
return Objects.hash(mType, mState, mRect);
}
- private static void assertValidState(@Nullable Integer state) {
- if (state != null && state != COMMON_STATE_FLAT
- && state != COMMON_STATE_HALF_OPENED && state != COMMON_STATE_UNKNOWN) {
+ /**
+ * Checks if the provided folding feature state should be reported to clients. See
+ * {@link androidx.window.extensions.layout.FoldingFeature}
+ */
+ private static void assertReportableState(@State int state) {
+ if (state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED
+ && state != COMMON_STATE_UNKNOWN) {
throw new IllegalArgumentException("Invalid state: " + state
+ "must be either COMMON_STATE_FLAT or COMMON_STATE_HALF_OPENED");
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
index 0bdf98c..66f27f5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
@@ -19,6 +19,7 @@
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN;
+import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE;
import static androidx.window.common.CommonFoldingFeature.parseListFromString;
import android.annotation.NonNull;
@@ -52,13 +53,54 @@
DeviceStateManagerFoldingFeatureProducer.class.getSimpleName();
private static final boolean DEBUG = false;
+ /**
+ * Emulated device state {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} to
+ * {@link CommonFoldingFeature.State} map.
+ */
private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
+ /**
+ * Emulated device state received via
+ * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
+ * "Emulated" states differ from "base" state in the sense that they may not correspond 1:1 with
+ * physical device states. They represent the state of the device when various software
+ * features and APIs are applied. The emulated states generally consist of all "base" states,
+ * but may have additional states such as "concurrent" or "rear display". Concurrent mode for
+ * example is activated via public API and can be active in both the "open" and "half folded"
+ * device states.
+ */
private int mCurrentDeviceState = INVALID_DEVICE_STATE;
+ /**
+ * Base device state received via
+ * {@link DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)}.
+ * "Base" in this context means the "physical" state of the device.
+ */
+ private int mCurrentBaseDeviceState = INVALID_DEVICE_STATE;
+
@NonNull
private final BaseDataProducer<String> mRawFoldSupplier;
+ private final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() {
+ @Override
+ public void onStateChanged(int state) {
+ mCurrentDeviceState = state;
+ mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer
+ .this::notifyFoldingFeatureChange);
+ }
+
+ @Override
+ public void onBaseStateChanged(int state) {
+ mCurrentBaseDeviceState = state;
+
+ if (mDeviceStateToPostureMap.get(mCurrentDeviceState)
+ == COMMON_STATE_USE_BASE_STATE) {
+ mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer
+ .this::notifyFoldingFeatureChange);
+ }
+ }
+ };
+
public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context,
@NonNull BaseDataProducer<String> rawFoldSupplier) {
mRawFoldSupplier = rawFoldSupplier;
@@ -92,12 +134,8 @@
}
if (mDeviceStateToPostureMap.size() > 0) {
- DeviceStateCallback deviceStateCallback = (state) -> {
- mCurrentDeviceState = state;
- mRawFoldSupplier.getData(this::notifyFoldingFeatureChange);
- };
Objects.requireNonNull(context.getSystemService(DeviceStateManager.class))
- .registerCallback(context.getMainExecutor(), deviceStateCallback);
+ .registerCallback(context.getMainExecutor(), mDeviceStateCallback);
}
}
@@ -178,11 +216,18 @@
}
private List<CommonFoldingFeature> calculateFoldingFeature(String displayFeaturesString) {
- final int globalHingeState = globalHingeState();
- return parseListFromString(displayFeaturesString, globalHingeState);
+ return parseListFromString(displayFeaturesString, currentHingeState());
}
- private int globalHingeState() {
- return mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN);
+ @CommonFoldingFeature.State
+ private int currentHingeState() {
+ @CommonFoldingFeature.State
+ int posture = mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN);
+
+ if (posture == CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE) {
+ posture = mDeviceStateToPostureMap.get(mCurrentBaseDeviceState, COMMON_STATE_UNKNOWN);
+ }
+
+ return posture;
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
new file mode 100644
index 0000000..5cd66ab
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 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.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Postsubmit
+import android.tools.common.Rotation
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.graphics.Rect
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.FlickerTest
+import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test the snapping of a PIP window via dragging, releasing, and checking its final location.
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipDragThenSnapTest(flicker: FlickerTest) : PipTransition(flicker){
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ val stringExtras: Map<String, String> =
+ mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true")
+
+ // cache the starting bounds here
+ val startBounds = Rect()
+
+ setup {
+ // Launch the PIP activity and wait for it to enter PiP mode
+ setRotation(Rotation.ROTATION_0)
+ RemoveAllTasksButHomeRule.removeAllTasksButHome()
+ pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
+
+ val initRegion = pipApp.dragPipWindowAwayFromEdge(wmHelper, 50)
+ startBounds
+ .set(initRegion.left, initRegion.top, initRegion.right, initRegion.bottom)
+ }
+ transitions {
+ // continue the transition until the PIP snaps
+ pipApp.waitForPipToSnapTo(wmHelper, startBounds)
+ }
+ }
+
+ /** Checks that the visible region area of [pipApp] always moves right during the animation. */
+ @Postsubmit
+ @Test
+ fun pipLayerMovesRight() {
+ flicker.assertLayers {
+ val pipLayerList = layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
+ pipLayerList.zipWithNext { previous, current ->
+ current.visibleRegion.isToTheRight(previous.visibleRegion.region)
+ }
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(Rotation.ROTATION_0)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/build.gradle b/packages/SettingsLib/Spa/build.gradle
index 643af75..2071489 100644
--- a/packages/SettingsLib/Spa/build.gradle
+++ b/packages/SettingsLib/Spa/build.gradle
@@ -24,7 +24,7 @@
}
}
plugins {
- id 'com.android.application' version '8.0.0-beta01' apply false
- id 'com.android.library' version '8.0.0-beta01' apply false
+ id 'com.android.application' version '8.0.0-beta03' apply false
+ id 'com.android.library' version '8.0.0-beta03' apply false
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
}
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
index 53b24b0..c3d5431 100644
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
@@ -16,7 +16,7 @@
#Thu Jul 14 10:36:06 CST 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-rc-1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-rc-2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 2f4ad9fd..832c1b9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3746,7 +3746,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 214;
+ private static final int SETTINGS_VERSION = 215;
private final int mUserId;
@@ -5701,6 +5701,49 @@
currentVersion = 214;
}
+ if (currentVersion == 214) {
+ // Version 214: Set a default value for Credential Manager service.
+
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+ final Setting currentSetting = secureSettings
+ .getSettingLocked(Settings.Secure.CREDENTIAL_SERVICE);
+ if (currentSetting.isNull()) {
+ final int resourceId =
+ com.android.internal.R.string.config_defaultCredentialProviderService;
+ final Resources resources = getContext().getResources();
+ // If the config has not be defined we might get an exception. We also get
+ // values from both the string array type and the single string in case the
+ // OEM uses the wrong one.
+ final List<String> providers = new ArrayList<>();
+ try {
+ providers.addAll(Arrays.asList(resources.getStringArray(resourceId)));
+ } catch (Resources.NotFoundException e) {
+ Slog.w(LOG_TAG,
+ "Get default array Cred Provider not found: " + e.toString());
+ }
+ try {
+ final String storedValue = resources.getString(resourceId);
+ if (!TextUtils.isEmpty(storedValue)) {
+ providers.add(storedValue);
+ }
+ } catch (Resources.NotFoundException e) {
+ Slog.w(LOG_TAG,
+ "Get default Cred Provider not found: " + e.toString());
+ }
+
+ if (!providers.isEmpty()) {
+ final String defaultValue = String.join(":", providers);
+ Slog.d(LOG_TAG, "Setting [" + defaultValue + "] as CredMan Service "
+ + "for user " + userId);
+ secureSettings.insertSettingOverrideableByRestoreLocked(
+ Settings.Secure.CREDENTIAL_SERVICE, defaultValue, null, true,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ }
+
+ currentVersion = 215;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index dd60647..0d36d04 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -116,6 +116,27 @@
public static final int SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1 << 26;
// Device dreaming state
public static final int SYSUI_STATE_DEVICE_DREAMING = 1 << 27;
+ // Whether the screen is currently on. Note that the screen is considered on while turning on,
+ // but not while turning off.
+ public static final int SYSUI_STATE_SCREEN_ON = 1 << 28;
+ // Whether the screen is currently transitioning into the state indicated by
+ // SYSUI_STATE_SCREEN_ON.
+ public static final int SYSUI_STATE_SCREEN_TRANSITION = 1 << 29;
+
+ // Mask for SystemUiStateFlags to isolate SYSUI_STATE_SCREEN_ON and
+ // SYSUI_STATE_SCREEN_TRANSITION, to match SCREEN_STATE_*
+ public static final int SYSUI_STATE_SCREEN_STATE_MASK =
+ SYSUI_STATE_SCREEN_ON | SYSUI_STATE_SCREEN_TRANSITION;
+ // Screen is off.
+ public static final int SCREEN_STATE_OFF = 0;
+ // Screen is on.
+ public static final int SCREEN_STATE_ON = SYSUI_STATE_SCREEN_ON;
+ // Screen is still on, but transitioning to turn off.
+ public static final int SCREEN_STATE_TURNING_OFF = SYSUI_STATE_SCREEN_TRANSITION;
+ // Screen was off and is now turning on.
+ public static final int SCREEN_STATE_TURNING_ON =
+ SYSUI_STATE_SCREEN_TRANSITION | SYSUI_STATE_SCREEN_ON;
+
// Whether the back gesture is allowed (or ignored) by the Shade
public static final boolean ALLOW_BACK_GESTURE_IN_SHADE = SystemProperties.getBoolean(
"persist.wm.debug.shade_allow_back_gesture", false);
@@ -148,7 +169,9 @@
SYSUI_STATE_IMMERSIVE_MODE,
SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING,
SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
- SYSUI_STATE_DEVICE_DREAMING
+ SYSUI_STATE_DEVICE_DREAMING,
+ SYSUI_STATE_SCREEN_ON,
+ SYSUI_STATE_SCREEN_TRANSITION,
})
public @interface SystemUiStateFlags {}
@@ -187,6 +210,9 @@
str.add((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0
? "freeform_active_in_desktop_mode" : "");
str.add((flags & SYSUI_STATE_DEVICE_DREAMING) != 0 ? "device_dreaming" : "");
+ str.add("screen_"
+ + ((flags & SYSUI_STATE_SCREEN_TRANSITION) != 0 ? "turning_" : "")
+ + ((flags & SYSUI_STATE_SCREEN_ON) != 0 ? "on" : "off"));
return str.toString();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index f7d87fc..b62c729 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -64,6 +64,7 @@
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.traceSection
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -215,7 +216,9 @@
requests.add(request)
mainExecutor.execute {
if (overlayView == null) {
- createOverlayForDisplay(reason)
+ traceSection("SideFpsController#show(request=${request.name}, reason=$reason") {
+ createOverlayForDisplay(reason)
+ }
} else {
Log.v(TAG, "overlay already shown")
}
@@ -227,7 +230,7 @@
requests.remove(request)
mainExecutor.execute {
if (requests.isEmpty()) {
- overlayView = null
+ traceSection("SideFpsController#hide(${request.name}") { overlayView = null }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index cbd61ffc..265a9903 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -628,14 +628,12 @@
@JvmField val UDFPS_ELLIPSE_DETECTION = releasedFlag(2201, "udfps_ellipse_detection")
// 2300 - stylus
+ @JvmField val TRACK_STYLUS_EVER_USED = releasedFlag(2300, "track_stylus_ever_used")
@JvmField
- val TRACK_STYLUS_EVER_USED = unreleasedFlag(2300, "track_stylus_ever_used", teamfood = true)
- @JvmField
- val ENABLE_STYLUS_CHARGING_UI =
- unreleasedFlag(2301, "enable_stylus_charging_ui", teamfood = true)
+ val ENABLE_STYLUS_CHARGING_UI = releasedFlag(2301, "enable_stylus_charging_ui")
@JvmField
val ENABLE_USI_BATTERY_NOTIFICATIONS =
- unreleasedFlag(2302, "enable_usi_battery_notifications", teamfood = true)
+ releasedFlag(2302, "enable_usi_battery_notifications")
@JvmField val ENABLE_STYLUS_EDUCATION = unreleasedFlag(2303, "enable_stylus_education")
// 2400 - performance tools and debugging info
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 019ca52..8a3ecc6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -31,6 +31,8 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_ON;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_TRANSITION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
@@ -121,7 +123,8 @@
public class OverviewProxyService implements CallbackController<OverviewProxyListener>,
NavigationModeController.ModeChangedListener, Dumpable {
- private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
+ @VisibleForTesting
+ static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
public static final String TAG_OPS = "OverviewProxyService";
private static final long BACKOFF_MILLIS = 1000;
@@ -548,6 +551,7 @@
mUiEventLogger = uiEventLogger;
mDisplayTracker = displayTracker;
mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder;
+ mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
dumpManager.registerDumpable(getClass().getSimpleName(), this);
@@ -596,7 +600,6 @@
// Connect to the service
updateEnabledState();
startConnectionToCurrentUser();
- mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
// Listen for assistant changes
assistUtils.registerVoiceInteractionSessionListener(mVoiceInteractionSessionListener);
@@ -726,10 +729,8 @@
return;
}
mHandler.removeCallbacks(mConnectionRunnable);
- Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
- .setPackage(mRecentsComponentName.getPackageName());
try {
- mBound = mContext.bindServiceAsUser(launcherServiceIntent,
+ mBound = mContext.bindServiceAsUser(mQuickStepIntent,
mOverviewServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
UserHandle.of(mUserTracker.getUserId()));
@@ -862,6 +863,11 @@
*/
@Override
public void onScreenTurnedOn() {
+ mSysUiState
+ .setFlag(SYSUI_STATE_SCREEN_ON, true)
+ .setFlag(SYSUI_STATE_SCREEN_TRANSITION, false)
+ .commitUpdate(mContext.getDisplayId());
+
try {
if (mOverviewProxy != null) {
mOverviewProxy.onScreenTurnedOn();
@@ -874,10 +880,26 @@
}
/**
+ * Notifies the Launcher that screen turned off.
+ */
+ @Override
+ public void onScreenTurnedOff() {
+ mSysUiState
+ .setFlag(SYSUI_STATE_SCREEN_ON, false)
+ .setFlag(SYSUI_STATE_SCREEN_TRANSITION, false)
+ .commitUpdate(mContext.getDisplayId());
+ }
+
+ /**
* Notifies the Launcher that screen is starting to turn on.
*/
@Override
public void onScreenTurningOff() {
+ mSysUiState
+ .setFlag(SYSUI_STATE_SCREEN_ON, false)
+ .setFlag(SYSUI_STATE_SCREEN_TRANSITION, true)
+ .commitUpdate(mContext.getDisplayId());
+
try {
if (mOverviewProxy != null) {
mOverviewProxy.onScreenTurningOff();
@@ -894,6 +916,11 @@
*/
@Override
public void onScreenTurningOn() {
+ mSysUiState
+ .setFlag(SYSUI_STATE_SCREEN_ON, true)
+ .setFlag(SYSUI_STATE_SCREEN_TRANSITION, true)
+ .commitUpdate(mContext.getDisplayId());
+
try {
if (mOverviewProxy != null) {
mOverviewProxy.onScreenTurningOn();
@@ -1005,4 +1032,21 @@
default void onAssistantGestureCompletion(float velocity) {}
default void startAssistant(Bundle bundle) {}
}
+
+ /**
+ * Shuts down this service at the end of a testcase.
+ * <p>
+ * The in-production service is never shuts down, and it was not designed with testing in mind.
+ * This unregisters the mechanisms by which the service will be revived after a testcase.
+ * <p>
+ * NOTE: This is a stop-gap introduced when first added some tests to this class. It should
+ * probably be replaced by proper lifecycle management on this class.
+ */
+ @VisibleForTesting()
+ void shutdownForTest() {
+ mContext.unregisterReceiver(mLauncherStateChangedReceiver);
+ mIsEnabled = false;
+ mHandler.removeCallbacks(mConnectionRunnable);
+ disconnectFromLauncherService();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 664d61a..00519b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -3623,7 +3623,8 @@
boolean goingToSleepWithoutAnimation = isGoingToSleep()
&& !mDozeParameters.shouldControlScreenOff();
boolean disabled = (!mDeviceInteractive && !mDozeServiceHost.isPulsing())
- || goingToSleepWithoutAnimation;
+ || goingToSleepWithoutAnimation
+ || mDeviceProvisionedController.isFrpActive();
mNotificationPanelViewController.setTouchAndAnimationDisabled(disabled);
mNotificationIconAreaController.setAnimationsEnabled(!disabled);
}
@@ -3797,10 +3798,10 @@
boolean launchingAffordanceWithPreview = mLaunchingAffordance;
mScrimController.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
-
if (mAlternateBouncerInteractor.isVisibleState()) {
- if (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
- || mTransitionToFullShadeProgress > 0f) {
+ if ((!isOccluded() || isPanelExpanded())
+ && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
+ || mTransitionToFullShadeProgress > 0f)) {
mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
} else {
mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
index 3944c8c..0d09fc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
@@ -21,7 +21,8 @@
/**
* Controller to cache in process the state of the device provisioning.
* <p>
- * This controller keeps track of the values of device provisioning and user setup complete
+ * This controller keeps track of the values of device provisioning, user setup complete, and
+ * whether Factory Reset Protection is active.
*/
public interface DeviceProvisionedController extends CallbackController<DeviceProvisionedListener> {
@@ -49,6 +50,9 @@
*/
boolean isCurrentUserSetup();
+ /** Returns true when Factory Reset Protection is locking the device. */
+ boolean isFrpActive();
+
/**
* Interface to provide calls when the values tracked change
*/
@@ -69,5 +73,10 @@
* Call when some user changes from not provisioned to provisioned
*/
default void onUserSetupChanged() { }
+
+ /**
+ * Called when the state of FRP changes.
+ */
+ default void onFrpActiveChanged() {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
index a6b7d9c5..32c64f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
@@ -60,9 +60,11 @@
}
private val deviceProvisionedUri = globalSettings.getUriFor(Settings.Global.DEVICE_PROVISIONED)
+ private val frpActiveUri = secureSettings.getUriFor(Settings.Secure.SECURE_FRP_MODE)
private val userSetupUri = secureSettings.getUriFor(Settings.Secure.USER_SETUP_COMPLETE)
private val deviceProvisioned = AtomicBoolean(false)
+ private val frpActive = AtomicBoolean(false)
@GuardedBy("lock")
private val userSetupComplete = SparseBooleanArray()
@GuardedBy("lock")
@@ -89,11 +91,15 @@
userId: Int
) {
val updateDeviceProvisioned = deviceProvisionedUri in uris
+ val updateFrp = frpActiveUri in uris
val updateUser = if (userSetupUri in uris) userId else NO_USERS
- updateValues(updateDeviceProvisioned, updateUser)
+ updateValues(updateDeviceProvisioned, updateFrp, updateUser)
if (updateDeviceProvisioned) {
onDeviceProvisionedChanged()
}
+ if (updateFrp) {
+ onFrpActiveChanged()
+ }
if (updateUser != NO_USERS) {
onUserSetupChanged()
}
@@ -103,7 +109,7 @@
private val userChangedCallback = object : UserTracker.Callback {
@WorkerThread
override fun onUserChanged(newUser: Int, userContext: Context) {
- updateValues(updateDeviceProvisioned = false, updateUser = newUser)
+ updateValues(updateDeviceProvisioned = false, updateFrp = false, updateUser = newUser)
onUserSwitched()
}
@@ -125,19 +131,27 @@
updateValues()
userTracker.addCallback(userChangedCallback, backgroundExecutor)
globalSettings.registerContentObserver(deviceProvisionedUri, observer)
+ globalSettings.registerContentObserver(frpActiveUri, observer)
secureSettings.registerContentObserverForUser(userSetupUri, observer, UserHandle.USER_ALL)
}
@WorkerThread
- private fun updateValues(updateDeviceProvisioned: Boolean = true, updateUser: Int = ALL_USERS) {
+ private fun updateValues(
+ updateDeviceProvisioned: Boolean = true,
+ updateFrp: Boolean = true,
+ updateUser: Int = ALL_USERS
+ ) {
if (updateDeviceProvisioned) {
deviceProvisioned
.set(globalSettings.getInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0)
}
+ if (updateFrp) {
+ frpActive.set(globalSettings.getInt(Settings.Secure.SECURE_FRP_MODE, 0) != 0)
+ }
synchronized(lock) {
if (updateUser == ALL_USERS) {
- val N = userSetupComplete.size()
- for (i in 0 until N) {
+ val n = userSetupComplete.size()
+ for (i in 0 until n) {
val user = userSetupComplete.keyAt(i)
val value = secureSettings
.getIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, user) != 0
@@ -172,6 +186,10 @@
return deviceProvisioned.get()
}
+ override fun isFrpActive(): Boolean {
+ return frpActive.get()
+ }
+
override fun isUserSetup(user: Int): Boolean {
val index = synchronized(lock) {
userSetupComplete.indexOfKey(user)
@@ -196,7 +214,13 @@
override fun onDeviceProvisionedChanged() {
dispatchChange(
- DeviceProvisionedController.DeviceProvisionedListener::onDeviceProvisionedChanged
+ DeviceProvisionedController.DeviceProvisionedListener::onDeviceProvisionedChanged
+ )
+ }
+
+ override fun onFrpActiveChanged() {
+ dispatchChange(
+ DeviceProvisionedController.DeviceProvisionedListener::onFrpActiveChanged
)
}
@@ -221,6 +245,7 @@
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.println("Device provisioned: ${deviceProvisioned.get()}")
+ pw.println("Factory Reset Protection active: ${frpActive.get()}")
synchronized(lock) {
pw.println("User setup complete: $userSetupComplete")
pw.println("Listeners: $listeners")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
new file mode 100644
index 0000000..eb7b481
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2023 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.recents
+
+import android.content.ComponentName
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.testing.AndroidTestingRunner
+import android.testing.TestableContext
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.app.AssistUtils
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.ScreenLifecycle
+import com.android.systemui.model.SysUiState
+import com.android.systemui.navigationbar.NavigationBarController
+import com.android.systemui.navigationbar.NavigationModeController
+import com.android.systemui.recents.OverviewProxyService.ACTION_QUICKSTEP
+import com.android.systemui.settings.FakeDisplayTracker
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.shared.recents.IOverviewProxy
+import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_OFF
+import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_ON
+import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_TURNING_OFF
+import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_TURNING_ON
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_STATE_MASK
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder
+import com.android.systemui.util.mockito.whenever
+import com.android.wm.shell.sysui.ShellInterface
+import com.google.common.util.concurrent.MoreExecutors
+import dagger.Lazy
+import java.util.Optional
+import java.util.concurrent.Executor
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.intThat
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class OverviewProxyServiceTest : SysuiTestCase() {
+
+ @Main private val executor: Executor = MoreExecutors.directExecutor()
+
+ private lateinit var subject: OverviewProxyService
+ private val dumpManager = DumpManager()
+ private val displayTracker = FakeDisplayTracker(mContext)
+ private val sysUiState = SysUiState(displayTracker)
+ private val screenLifecycle = ScreenLifecycle(dumpManager)
+
+ @Mock private lateinit var overviewProxy: IOverviewProxy.Stub
+ @Mock private lateinit var packageManager: PackageManager
+
+ // The following mocks belong to not-yet-tested parts of OverviewProxyService.
+ @Mock private lateinit var commandQueue: CommandQueue
+ @Mock private lateinit var shellInterface: ShellInterface
+ @Mock private lateinit var navBarController: NavigationBarController
+ @Mock private lateinit var centralSurfaces: CentralSurfaces
+ @Mock private lateinit var navModeController: NavigationModeController
+ @Mock private lateinit var statusBarWinController: NotificationShadeWindowController
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var sysuiUnlockAnimationController: KeyguardUnlockAnimationController
+ @Mock private lateinit var assistUtils: AssistUtils
+ @Mock
+ private lateinit var unfoldTransitionProgressForwarder:
+ Optional<UnfoldTransitionProgressForwarder>
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ val serviceComponent = ComponentName("test_package", "service_provider")
+ context.addMockService(serviceComponent, overviewProxy)
+ context.addMockServiceResolver(
+ TestableContext.MockServiceResolver {
+ if (it.action == ACTION_QUICKSTEP) serviceComponent else null
+ }
+ )
+ whenever(overviewProxy.queryLocalInterface(ArgumentMatchers.anyString()))
+ .thenReturn(overviewProxy)
+ whenever(overviewProxy.asBinder()).thenReturn(overviewProxy)
+
+ // packageManager.resolveServiceAsUser has to return non-null for
+ // OverviewProxyService#isEnabled to become true.
+ context.setMockPackageManager(packageManager)
+ whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt()))
+ .thenReturn(mock(ResolveInfo::class.java))
+
+ subject =
+ OverviewProxyService(
+ context,
+ executor,
+ commandQueue,
+ shellInterface,
+ Lazy { navBarController },
+ Lazy { Optional.of(centralSurfaces) },
+ navModeController,
+ statusBarWinController,
+ sysUiState,
+ userTracker,
+ screenLifecycle,
+ uiEventLogger,
+ displayTracker,
+ sysuiUnlockAnimationController,
+ assistUtils,
+ dumpManager,
+ unfoldTransitionProgressForwarder
+ )
+ }
+
+ @After
+ fun tearDown() {
+ subject.shutdownForTest()
+ }
+
+ @Test
+ fun `ScreenLifecycle - screenTurnedOn triggers SysUI state flag changes `() {
+ screenLifecycle.dispatchScreenTurnedOn()
+
+ verify(overviewProxy)
+ .onSystemUiStateChanged(
+ intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_ON }
+ )
+ }
+
+ @Test
+ fun `ScreenLifecycle - screenTurningOn triggers SysUI state flag changes `() {
+ screenLifecycle.dispatchScreenTurningOn()
+
+ verify(overviewProxy)
+ .onSystemUiStateChanged(
+ intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_TURNING_ON }
+ )
+ }
+
+ @Test
+ fun `ScreenLifecycle - screenTurnedOff triggers SysUI state flag changes `() {
+ screenLifecycle.dispatchScreenTurnedOff()
+
+ verify(overviewProxy)
+ .onSystemUiStateChanged(
+ intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_OFF }
+ )
+ }
+
+ @Test
+ fun `ScreenLifecycle - screenTurningOff triggers SysUI state flag changes `() {
+ screenLifecycle.dispatchScreenTurningOff()
+
+ verify(overviewProxy)
+ .onSystemUiStateChanged(
+ intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_TURNING_OFF }
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index c4ee326..031c17f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -1091,6 +1091,34 @@
}
@Test
+ public void testOccludingQSNotExpanded_transitionToAuthScrimmed() {
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+ // GIVEN device occluded and panel is NOT expanded
+ mCentralSurfaces.setBarStateForTest(SHADE); // occluding on LS has StatusBarState = SHADE
+ when(mKeyguardStateController.isOccluded()).thenReturn(true);
+ mCentralSurfaces.mPanelExpanded = false;
+
+ mCentralSurfaces.updateScrimController();
+
+ verify(mScrimController).transitionTo(eq(ScrimState.AUTH_SCRIMMED));
+ }
+
+ @Test
+ public void testOccludingQSExpanded_transitionToAuthScrimmedShade() {
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+ // GIVEN device occluded and qs IS expanded
+ mCentralSurfaces.setBarStateForTest(SHADE); // occluding on LS has StatusBarState = SHADE
+ when(mKeyguardStateController.isOccluded()).thenReturn(true);
+ mCentralSurfaces.mPanelExpanded = true;
+
+ mCentralSurfaces.updateScrimController();
+
+ verify(mScrimController).transitionTo(eq(ScrimState.AUTH_SCRIMMED_SHADE));
+ }
+
+ @Test
public void testShowKeyguardImplementation_setsState() {
when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
@@ -1314,6 +1342,15 @@
verify(mPowerManagerService, never()).wakeUp(anyLong(), anyInt(), anyString(), anyString());
}
+ @Test
+ public void frpLockedDevice_shadeDisabled() {
+ when(mDeviceProvisionedController.isFrpActive()).thenReturn(true);
+ when(mDozeServiceHost.isPulsing()).thenReturn(true);
+ mCentralSurfaces.updateNotificationPanelTouchState();
+
+ verify(mNotificationPanelViewController).setTouchAndAnimationDisabled(true);
+ }
+
/**
* Configures the appropriate mocks and then calls {@link CentralSurfacesImpl#updateIsKeyguard}
* to reconfigure the keyguard to reflect the requested showing/occluded states.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
index 5129f85..6980a0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
@@ -90,6 +90,12 @@
}
@Test
+ fun testFrpNotActiveByDefault() {
+ init()
+ assertThat(controller.isFrpActive).isFalse()
+ }
+
+ @Test
fun testNotUserSetupByDefault() {
init()
assertThat(controller.isUserSetup(START_USER)).isFalse()
@@ -104,6 +110,14 @@
}
@Test
+ fun testFrpActiveWhenCreated() {
+ settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+ init()
+
+ assertThat(controller.isFrpActive).isTrue()
+ }
+
+ @Test
fun testUserSetupWhenCreated() {
settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
init()
@@ -122,6 +136,16 @@
}
@Test
+ fun testFrpActiveChange() {
+ init()
+
+ settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+ testableLooper.processAllMessages() // background observer
+
+ assertThat(controller.isFrpActive).isTrue()
+ }
+
+ @Test
fun testUserSetupChange() {
init()
@@ -164,6 +188,7 @@
mainExecutor.runAllReady()
verify(listener, never()).onDeviceProvisionedChanged()
+ verify(listener, never()).onFrpActiveChanged()
verify(listener, never()).onUserSetupChanged()
verify(listener, never()).onUserSwitched()
}
@@ -181,6 +206,7 @@
verify(listener).onUserSwitched()
verify(listener, never()).onUserSetupChanged()
verify(listener, never()).onDeviceProvisionedChanged()
+ verify(listener, never()).onFrpActiveChanged()
}
@Test
@@ -195,6 +221,7 @@
verify(listener, never()).onUserSwitched()
verify(listener).onUserSetupChanged()
verify(listener, never()).onDeviceProvisionedChanged()
+ verify(listener, never()).onFrpActiveChanged()
}
@Test
@@ -208,10 +235,26 @@
verify(listener, never()).onUserSwitched()
verify(listener, never()).onUserSetupChanged()
+ verify(listener, never()).onFrpActiveChanged()
verify(listener).onDeviceProvisionedChanged()
}
@Test
+ fun testListenerCalledOnFrpActiveChanged() {
+ init()
+ controller.addCallback(listener)
+
+ settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+ testableLooper.processAllMessages()
+ mainExecutor.runAllReady()
+
+ verify(listener, never()).onUserSwitched()
+ verify(listener, never()).onUserSetupChanged()
+ verify(listener, never()).onDeviceProvisionedChanged()
+ verify(listener).onFrpActiveChanged()
+ }
+
+ @Test
fun testRemoveListener() {
init()
controller.addCallback(listener)
@@ -220,11 +263,13 @@
switchUser(10)
settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
+ settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
testableLooper.processAllMessages()
mainExecutor.runAllReady()
verify(listener, never()).onDeviceProvisionedChanged()
+ verify(listener, never()).onFrpActiveChanged()
verify(listener, never()).onUserSetupChanged()
verify(listener, never()).onUserSwitched()
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 67ba078..4b2467d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17279,6 +17279,9 @@
public ComponentName startSdkSandboxService(Intent service, int clientAppUid,
String clientAppPackage, String processName) throws RemoteException {
validateSdkSandboxParams(service, clientAppUid, clientAppPackage, processName);
+ if (mAppOpsService.checkPackage(clientAppUid, clientAppPackage) != MODE_ALLOWED) {
+ throw new IllegalArgumentException("uid does not belong to provided package");
+ }
// TODO(b/269598719): Is passing the application thread of the system_server alright?
// e.g. the sandbox getting privileged access due to this.
ComponentName cn = ActivityManagerService.this.startService(
@@ -17345,6 +17348,9 @@
String processName, long flags)
throws RemoteException {
validateSdkSandboxParams(service, clientAppUid, clientAppPackage, processName);
+ if (mAppOpsService.checkPackage(clientAppUid, clientAppPackage) != MODE_ALLOWED) {
+ throw new IllegalArgumentException("uid does not belong to provided package");
+ }
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
@@ -17397,9 +17403,6 @@
if (!UserHandle.isApp(clientAppUid)) {
throw new IllegalArgumentException("uid is not within application range");
}
- if (mAppOpsService.checkPackage(clientAppUid, clientAppPackage) != MODE_ALLOWED) {
- throw new IllegalArgumentException("uid does not belong to provided package");
- }
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 809f3f7..94d08bf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -46,6 +46,7 @@
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
@@ -2222,7 +2223,6 @@
boolean wait = false;
String opt;
int displayId = Display.INVALID_DISPLAY;
- boolean forceInvisible = false;
while ((opt = getNextOption()) != null) {
switch(opt) {
case "-w":
@@ -2231,27 +2231,31 @@
case "--display":
displayId = getDisplayIdFromNextArg();
break;
- case "--force-invisible":
- forceInvisible = true;
- break;
default:
getErrPrintWriter().println("Error: unknown option: " + opt);
return -1;
}
}
final int userId = Integer.parseInt(getNextArgRequired());
- final boolean callStartProfile = !forceInvisible && isProfile(userId);
final ProgressWaiter waiter = wait ? new ProgressWaiter(userId) : null;
- Slogf.d(TAG, "runStartUser(): userId=%d, display=%d, waiter=%s, callStartProfile=%b, "
- + "forceInvisible=%b", userId, displayId, waiter, callStartProfile,
- forceInvisible);
+
+ // For backwards compatibility, if the user is a profile, we need to define whether it
+ // should be started visible (when its parent is the current user) or not (when it isn't)
+ final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+ final ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
+ final int parentUserId = umi.getProfileParentId(userId);
+ final int currentUserId = ami.getCurrentUserId();
+ final boolean isProfile = parentUserId != userId;
+ final boolean isVisibleProfile = isProfile && parentUserId == currentUserId;
+ Slogf.d(TAG, "runStartUser(): userId=%d, parentUserId=%d, currentUserId=%d, isProfile=%b, "
+ + "isVisibleProfile=%b, display=%d, waiter=%s", userId, parentUserId, currentUserId,
+ isProfile, isVisibleProfile, displayId, waiter);
boolean success;
String displaySuffix = "";
-
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "shell_runStartUser" + userId);
try {
- if (callStartProfile) {
+ if (isVisibleProfile) {
Slogf.d(TAG, "calling startProfileWithListener(%d, %s)", userId, waiter);
// startProfileWithListener() will start the profile visible (as long its parent is
// the current user), while startUserInBackgroundWithListener() will always start
@@ -3906,11 +3910,6 @@
return new Resources(AssetManager.getSystem(), metrics, config);
}
- private boolean isProfile(@UserIdInt int userId) {
- final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
- return umi.getProfileParentId(userId) != userId;
- }
-
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -4157,7 +4156,7 @@
pw.println(" execution of that user if it is currently stopped.");
pw.println(" get-current-user");
pw.println(" Returns id of the current foreground user.");
- pw.println(" start-user [-w] [--display DISPLAY_ID] [--force-invisible] <USER_ID>");
+ pw.println(" start-user [-w] [--display DISPLAY_ID] <USER_ID>");
pw.println(" Start USER_ID in background if it is currently stopped;");
pw.println(" use switch-user if you want to start the user in foreground.");
pw.println(" -w: wait for start-user to complete and the user to be unlocked.");
@@ -4165,10 +4164,6 @@
+ "which allows the user to launch activities on it.");
pw.println(" (not supported on all devices; typically only on automotive builds "
+ "where the vehicle has passenger displays)");
- pw.println(" --force-invisible: always start the user invisible, even if it's a "
- + "profile.");
- pw.println(" (by default, a profile is visible in the default display when its "
- + "parent is the current foreground user)");
pw.println(" unlock-user <USER_ID>");
pw.println(" Unlock the given user. This will only work if the user doesn't");
pw.println(" have an LSKF (PIN/pattern/password).");
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 81ca267..bef16b6 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -52,7 +52,6 @@
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -224,22 +223,12 @@
private static final int MSG_DELIVERY_TIMEOUT_HARD = 3;
private static final int MSG_BG_ACTIVITY_START_TIMEOUT = 4;
private static final int MSG_CHECK_HEALTH = 5;
- private static final int MSG_FINISH_RECEIVER = 6;
private void enqueueUpdateRunningList() {
mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
mLocalHandler.sendEmptyMessage(MSG_UPDATE_RUNNING_LIST);
}
- private void enqueueFinishReceiver(@NonNull BroadcastProcessQueue queue,
- @DeliveryState int deliveryState, @NonNull String reason) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = queue;
- args.argi1 = deliveryState;
- args.arg2 = reason;
- mLocalHandler.sendMessage(Message.obtain(mLocalHandler, MSG_FINISH_RECEIVER, args));
- }
-
private final Handler mLocalHandler;
private final Handler.Callback mLocalCallback = (msg) -> {
@@ -278,17 +267,6 @@
}
return true;
}
- case MSG_FINISH_RECEIVER: {
- synchronized (mService) {
- final SomeArgs args = (SomeArgs) msg.obj;
- final BroadcastProcessQueue queue = (BroadcastProcessQueue) args.arg1;
- final int deliveryState = args.argi1;
- final String reason = (String) args.arg2;
- args.recycle();
- finishReceiverActiveLocked(queue, deliveryState, reason);
- }
- return true;
- }
}
return false;
};
@@ -727,7 +705,7 @@
// Ignore registered receivers from a previous PID
if (receiver instanceof BroadcastFilter) {
mRunningColdStart = null;
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED,
+ finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED,
"BroadcastFilter for cold app");
return;
}
@@ -758,7 +736,7 @@
hostingRecord, zygotePolicyFlags, allowWhileBooting, false);
if (queue.app == null) {
mRunningColdStart = null;
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE,
+ finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
"startProcessLocked failed");
return;
}
@@ -800,7 +778,7 @@
@NonNull BroadcastRecord r, int index) {
final String reason = shouldSkipReceiver(queue, r, index);
if (reason != null) {
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, reason);
+ finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, reason);
return true;
}
return false;
@@ -914,7 +892,7 @@
// TODO: consider making registered receivers of unordered
// broadcasts report results to detect ANRs
if (assumeDelivered) {
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_DELIVERED,
+ finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED,
"assuming delivered");
}
} else {
@@ -932,10 +910,10 @@
logw(msg);
app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true);
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app");
+ finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app");
}
} else {
- enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE,
+ finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
"missing IApplicationThread");
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c50e275..490a33e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3928,8 +3928,10 @@
}
@Override
- @android.annotation.EnforcePermission(anyOf =
- {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SETTINGS_PRIVILEGED"})
+ @android.annotation.EnforcePermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+ })
/** @see AudioDeviceVolumeManager#setDeviceVolume(VolumeInfo, AudioDeviceAttributes)
* Part of service interface, check permissions and parameters here
* Note calling package is for logging purposes only, not to be trusted
@@ -4945,8 +4947,10 @@
}
@Override
- @android.annotation.EnforcePermission(anyOf =
- {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SETTINGS_PRIVILEGED"})
+ @android.annotation.EnforcePermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+ })
/**
* @see AudioDeviceVolumeManager#getDeviceVolume(VolumeInfo, AudioDeviceAttributes)
*/
@@ -7214,8 +7218,10 @@
* @param device the audio device to be affected
* @param deviceVolumeBehavior one of the device behaviors
*/
- @android.annotation.EnforcePermission(anyOf =
- {"MODIFY_AUDIO_ROUTING", "MODIFY_AUDIO_SETTINGS_PRIVILEGED"})
+ @android.annotation.EnforcePermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+ })
public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
@AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @Nullable String pkgName) {
// verify permissions
@@ -7295,8 +7301,11 @@
* @param device the audio output device type
* @return the volume behavior for the device
*/
- @android.annotation.EnforcePermission(anyOf =
- {"MODIFY_AUDIO_ROUTING", "QUERY_AUDIO_STATE", "MODIFY_AUDIO_SETTINGS_PRIVILEGED"})
+ @android.annotation.EnforcePermission(anyOf = {
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.QUERY_AUDIO_STATE,
+ android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
+ })
public @AudioManager.DeviceVolumeBehavior
int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
// verify permissions
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 12134f7..4e3de3c 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -499,7 +499,8 @@
if ((recentTasks != null) && (!recentTasks.getList().isEmpty())) {
for (ActivityManager.RecentTaskInfo task : recentTasks.getList()) {
- if (packageName.equals(task.topActivityInfo.packageName)) {
+ if (task.topActivityInfo != null && packageName.equals(
+ task.topActivityInfo.packageName)) {
taskInfo = new TaskInfo();
taskInfo.frontTaskId = task.taskId;
taskInfo.isResizeable =
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index cc41207..afae08d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -56,7 +56,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.RemoteLockscreenValidationResult;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DeviceStateCache;
@@ -2514,7 +2514,7 @@
* Starts a session to verify lock screen credentials provided by a remote device.
*/
@NonNull
- public StartLockscreenValidationRequest startRemoteLockscreenValidation() {
+ public RemoteLockscreenValidationSession startRemoteLockscreenValidation() {
return mRecoverableKeyStoreManager.startRemoteLockscreenValidation(this);
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index c08958b..f073756 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -31,7 +31,7 @@
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.RemoteLockscreenValidationResult;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
@@ -999,7 +999,7 @@
/**
* Starts a session to verify lock screen credentials provided by a remote device.
*/
- public StartLockscreenValidationRequest startRemoteLockscreenValidation(
+ public RemoteLockscreenValidationSession startRemoteLockscreenValidation(
LockSettingsService lockSettingsService) {
if (mRemoteLockscreenValidationSessionStorage == null) {
throw new UnsupportedOperationException("Under development");
@@ -1021,8 +1021,8 @@
int badGuesses = mDatabase.getBadRemoteGuessCounter(userId);
int remainingAttempts = Math.max(INVALID_REMOTE_GUESS_LIMIT - badGuesses, 0);
// TODO(b/254335492): Schedule task to remove inactive session
- return new StartLockscreenValidationRequest.Builder()
- .setLockscreenUiType(keyguardCredentialsType)
+ return new RemoteLockscreenValidationSession.Builder()
+ .setLockType(keyguardCredentialsType)
.setRemainingAttempts(remainingAttempts)
.setSourcePublicKey(encodedPublicKey)
.build();
@@ -1046,7 +1046,9 @@
.build();
}
if (session == null) {
- throw new IllegalStateException("There is no active lock screen check session");
+ return new RemoteLockscreenValidationResult.Builder()
+ .setResultCode(RemoteLockscreenValidationResult.RESULT_SESSION_EXPIRED)
+ .build();
}
byte[] decryptedCredentials;
try {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 2f98d34..3343172 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3504,15 +3504,15 @@
return;
}
final int oldMainUserId = getMainUserIdUnchecked();
- final int oldFlags = systemUserData.info.flags;
- final int newFlags;
+ final int oldSysFlags = systemUserData.info.flags;
+ final int newSysFlags;
final String newUserType;
if (newHeadlessSystemUserMode) {
newUserType = UserManager.USER_TYPE_SYSTEM_HEADLESS;
- newFlags = oldFlags & ~UserInfo.FLAG_FULL & ~UserInfo.FLAG_MAIN;
+ newSysFlags = oldSysFlags & ~UserInfo.FLAG_FULL & ~UserInfo.FLAG_MAIN;
} else {
newUserType = UserManager.USER_TYPE_FULL_SYSTEM;
- newFlags = oldFlags | UserInfo.FLAG_FULL;
+ newSysFlags = oldSysFlags | UserInfo.FLAG_FULL | UserInfo.FLAG_MAIN;
}
if (systemUserData.info.userType.equals(newUserType)) {
@@ -3523,18 +3523,19 @@
Slogf.i(LOG_TAG, "Persisting emulated system user data: type changed from %s to "
+ "%s, flags changed from %s to %s",
systemUserData.info.userType, newUserType,
- UserInfo.flagsToString(oldFlags), UserInfo.flagsToString(newFlags));
+ UserInfo.flagsToString(oldSysFlags), UserInfo.flagsToString(newSysFlags));
systemUserData.info.userType = newUserType;
- systemUserData.info.flags = newFlags;
+ systemUserData.info.flags = newSysFlags;
writeUserLP(systemUserData);
- // Switch the MainUser to a reasonable choice if needed.
- // (But if there was no MainUser, we deliberately continue to have no MainUser.)
+ // Designate the MainUser to a reasonable choice if needed.
final UserData oldMain = getUserDataNoChecks(oldMainUserId);
if (newHeadlessSystemUserMode) {
- if (oldMain != null && (oldMain.info.flags & UserInfo.FLAG_SYSTEM) != 0) {
- // System was MainUser. So we need a new choice for Main. Pick the oldest.
+ final boolean mainIsAlreadyNonSystem =
+ oldMain != null && (oldMain.info.flags & UserInfo.FLAG_SYSTEM) == 0;
+ if (!mainIsAlreadyNonSystem && isMainUserPermanentAdmin()) {
+ // We need a new choice for Main. Pick the oldest.
// If no oldest, don't set any. Let the BootUserInitializer do that later.
final UserInfo newMainUser = getEarliestCreatedFullUser();
if (newMainUser != null) {
@@ -3544,16 +3545,16 @@
}
}
} else {
+ // We already made user 0 Main above. Now strip it from the old Main user.
// TODO(b/256624031): For now, we demand the Main user (if there is one) is
// always the system in non-HSUM. In the future, when we relax this, change how
// we handle MAIN.
if (oldMain != null && (oldMain.info.flags & UserInfo.FLAG_SYSTEM) == 0) {
- // Someone else was the MainUser; transfer it to System.
Slogf.i(LOG_TAG, "Transferring Main to user 0 from " + oldMain.info.id);
oldMain.info.flags &= ~UserInfo.FLAG_MAIN;
- systemUserData.info.flags |= UserInfo.FLAG_MAIN;
writeUserLP(oldMain);
- writeUserLP(systemUserData);
+ } else {
+ Slogf.i(LOG_TAG, "Designated user 0 to be Main");
}
}
}
@@ -3817,12 +3818,14 @@
if (userVersion < 11) {
// Add FLAG_MAIN
if (isHeadlessSystemUserMode()) {
- final UserInfo earliestCreatedUser = getEarliestCreatedFullUser();
- if (earliestCreatedUser != null) {
- earliestCreatedUser.flags |= UserInfo.FLAG_MAIN;
- userIdsToWrite.add(earliestCreatedUser.id);
+ if (isMainUserPermanentAdmin()) {
+ final UserInfo earliestCreatedUser = getEarliestCreatedFullUser();
+ if (earliestCreatedUser != null) {
+ earliestCreatedUser.flags |= UserInfo.FLAG_MAIN;
+ userIdsToWrite.add(earliestCreatedUser.id);
+ }
}
- } else {
+ } else { // not isHeadlessSystemUserMode
synchronized (mUsersLock) {
final UserData userData = mUsers.get(UserHandle.USER_SYSTEM);
userData.info.flags |= UserInfo.FLAG_MAIN;
diff --git a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
index 98b24ea..333c98c 100644
--- a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
+++ b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
@@ -380,6 +380,7 @@
final int pid = Process.myPid();
Slogf.i(LOG_TAG, "Restarting Android runtime(PID=%d) to finalize changes", pid);
pw.println("Restarting Android runtime to finalize changes");
+ pw.println("The restart may trigger a 'Broken pipe' message; this is to be expected.");
pw.flush();
// Ideally there should be a cleaner / safer option to restart system_server, but
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c775419..faa0cc9 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2098,7 +2098,7 @@
mTaskSupervisor = supervisor;
info.taskAffinity = computeTaskAffinity(info.taskAffinity, info.applicationInfo.uid,
- launchMode);
+ info.launchMode, mActivityComponent);
taskAffinity = info.taskAffinity;
final String uid = Integer.toString(info.applicationInfo.uid);
if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
@@ -2199,12 +2199,18 @@
* @param affinity The affinity of the activity.
* @param uid The user-ID that has been assigned to this application.
* @param launchMode The activity launch mode
+ * @param componentName The activity component name. This is only useful when the given
+ * launchMode is {@link ActivityInfo#LAUNCH_SINGLE_INSTANCE}
* @return The task affinity
*/
- static String computeTaskAffinity(String affinity, int uid, int launchMode) {
+ static String computeTaskAffinity(String affinity, int uid, int launchMode,
+ ComponentName componentName) {
final String uidStr = Integer.toString(uid);
if (affinity != null && !affinity.startsWith(uidStr)) {
- affinity = uidStr + (launchMode == LAUNCH_SINGLE_INSTANCE ? "-si:" : ":") + affinity;
+ affinity = uidStr + ":" + affinity;
+ if (launchMode == LAUNCH_SINGLE_INSTANCE && componentName != null) {
+ affinity += ":" + componentName.hashCode();
+ }
}
return affinity;
}
@@ -7855,7 +7861,6 @@
if (task != null && requestedOrientation == SCREEN_ORIENTATION_BEHIND) {
// We use Task here because we want to be consistent with what happens in
// multi-window mode where other tasks orientations are ignored.
- android.util.Log.d("orientation", "We are here");
final ActivityRecord belowCandidate = task.getActivity(
a -> a.canDefineOrientationForActivitiesAbove() /* callback */,
this /* boundary */, false /* includeBoundary */,
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 14b845c..cb94146 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -37,6 +37,7 @@
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
@@ -1221,7 +1222,7 @@
void onActivityIdle(ActivityRecord r) {
// Clean up the hidden tasks when going to home because the user may not be unable to return
// to the task from recents.
- if (!mHiddenTasks.isEmpty() && r.isActivityTypeHome()) {
+ if (!mHiddenTasks.isEmpty() && r.isActivityTypeHome() && r.isState(RESUMED)) {
removeUnreachableHiddenTasks(r.getWindowingMode());
}
if (mCheckTrimmableTasksOnIdle) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 254c911..ebdc537 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5332,7 +5332,7 @@
// the task if the affinity has changed.
final String affinity = ActivityRecord.computeTaskAffinity(destAffinity, srec.getUid(),
- srec.launchMode);
+ srec.launchMode, srec.mActivityComponent);
if (srec == null || srec.getTask().affinity == null
|| !srec.getTask().affinity.equals(affinity)) {
return true;
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index e84f0cc..94260e20 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -46,9 +46,11 @@
public ClearRequestSession(Context context, int userId, int callingUid,
IClearCredentialStateCallback callback, ClearCredentialStateRequest request,
- CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal) {
+ CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
+ long startedTimestamp) {
super(context, userId, callingUid, request, callback, RequestInfo.TYPE_UNDEFINED,
- callingAppInfo, cancellationSignal);
+ callingAppInfo, cancellationSignal, startedTimestamp);
+ setupInitialPhaseMetric(ApiName.CLEAR_CREDENTIAL.getMetricCode(), MetricUtilities.ZERO);
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 7e1780d..47b8c7d 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -53,9 +53,11 @@
CreateCredentialRequest request,
ICreateCredentialCallback callback,
CallingAppInfo callingAppInfo,
- CancellationSignal cancellationSignal) {
+ CancellationSignal cancellationSignal,
+ long startedTimestamp) {
super(context, userId, callingUid, request, callback, RequestInfo.TYPE_CREATE,
- callingAppInfo, cancellationSignal);
+ callingAppInfo, cancellationSignal, startedTimestamp);
+ setupInitialPhaseMetric(ApiName.CREATE_CREDENTIAL.getMetricCode(), MetricUtilities.UNIT);
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 55973fa..a58dbe5 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -29,7 +29,6 @@
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialRequest;
@@ -229,8 +228,10 @@
if (hasPermission(android.Manifest.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS)) {
return;
}
-
- throw new SecurityException("Caller is missing permission: QUERY_ALL_PACKAGES or LIST_ENABLED_CREDENTIAL_PROVIDERS");
+
+ throw new SecurityException(
+ "Caller is missing permission: QUERY_ALL_PACKAGES or "
+ + "LIST_ENABLED_CREDENTIAL_PROVIDERS");
}
private boolean hasPermission(String permission) {
@@ -402,6 +403,7 @@
GetCredentialRequest request,
IGetCredentialCallback callback,
final String callingPackage) {
+ final long timestampBegan = System.nanoTime();
Log.i(TAG, "starting executeGetCredential with callingPackage: " + callingPackage);
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
@@ -423,7 +425,8 @@
callback,
request,
constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
- CancellationSignal.fromTransport(cancelTransport));
+ CancellationSignal.fromTransport(cancelTransport),
+ timestampBegan);
processGetCredential(request, callback, session);
return cancelTransport;
@@ -502,6 +505,9 @@
+ e.getMessage());
}
}
+
+ finalizeAndEmitInitialPhaseMetric(session);
+ // TODO(b/271135048) - May still be worth emitting in the empty cases above.
providerSessions.forEach(ProviderSession::invokeSession);
}
@@ -510,6 +516,7 @@
CreateCredentialRequest request,
ICreateCredentialCallback callback,
String callingPackage) {
+ final long timestampBegan = System.nanoTime();
Log.i(TAG, "starting executeCreateCredential with callingPackage: "
+ callingPackage);
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
@@ -532,7 +539,8 @@
request,
callback,
constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
- CancellationSignal.fromTransport(cancelTransport));
+ CancellationSignal.fromTransport(cancelTransport),
+ timestampBegan);
processCreateCredential(request, callback, session);
return cancelTransport;
@@ -560,10 +568,17 @@
}
}
+ finalizeAndEmitInitialPhaseMetric(session);
// Iterate over all provider sessions and invoke the request
providerSessions.forEach(ProviderSession::invokeSession);
}
+ private void finalizeAndEmitInitialPhaseMetric(RequestSession session) {
+ var initMetric = session.mInitialPhaseMetric;
+ initMetric.setCredentialServiceBeginQueryTimeNanoseconds(System.nanoTime());
+ MetricUtilities.logApiCalled(initMetric);
+ }
+
@Override
public void setEnabledProviders(
List<String> providers, int userId, ISetEnabledProvidersCallback callback) {
@@ -648,6 +663,7 @@
}
MetricUtilities.logApiCalled(ApiName.IS_ENABLED_CREDENTIAL_PROVIDER_SERVICE,
ApiStatus.SUCCESS, callingUid);
+ // TODO(b/271135048) - Update asap to use the new logging types
return true;
}
}
@@ -677,12 +693,22 @@
mContext, userId, providerFilter, getEnabledProviders());
}
- private Set<ServiceInfo> getEnabledProviders() {
- Set<ServiceInfo> enabledProviders = new HashSet<>();
+ @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
+ // this.mLock
+ private Set<ComponentName> getEnabledProviders() {
+ Set<ComponentName> enabledProviders = new HashSet<>();
synchronized (mLock) {
runForUser(
(service) -> {
- enabledProviders.add(service.getCredentialProviderInfo().getServiceInfo());
+ try {
+ enabledProviders.add(
+ service.getCredentialProviderInfo()
+ .getServiceInfo().getComponentName());
+ } catch (NullPointerException e) {
+ // Safe check
+ Log.i(TAG, "Skipping provider as either the providerInfo"
+ + "or serviceInfo is null - weird");
+ }
});
}
return enabledProviders;
@@ -693,6 +719,7 @@
ClearCredentialStateRequest request,
IClearCredentialStateCallback callback,
String callingPackage) {
+ final long timestampBegan = System.nanoTime();
Log.i(TAG, "starting clearCredentialState with callingPackage: " + callingPackage);
final int userId = UserHandle.getCallingUserId();
int callingUid = Binder.getCallingUid();
@@ -710,7 +737,8 @@
callback,
request,
constructCallingAppInfo(callingPackage, userId, null),
- CancellationSignal.fromTransport(cancelTransport));
+ CancellationSignal.fromTransport(cancelTransport),
+ timestampBegan);
// Initiate all provider sessions
// TODO: Determine if provider needs to have clear capability in their manifest
@@ -729,6 +757,8 @@
}
}
+ finalizeAndEmitInitialPhaseMetric(session);
+
// Iterate over all provider sessions and invoke the request
providerSessions.forEach(ProviderSession::invokeSession);
return cancelTransport;
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index f59b32c..8e90c09 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.credentials.CredentialOption;
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialRequest;
@@ -36,6 +37,7 @@
import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import java.util.ArrayList;
+import java.util.stream.Collectors;
/**
* Central session for a single getCredentials request. This class listens to the
@@ -47,9 +49,14 @@
private static final String TAG = "GetRequestSession";
public GetRequestSession(Context context, int userId, int callingUid,
IGetCredentialCallback callback, GetCredentialRequest request,
- CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal) {
+ CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
+ long startedTimestamp) {
super(context, userId, callingUid, request, callback, RequestInfo.TYPE_GET,
- callingAppInfo, cancellationSignal);
+ callingAppInfo, cancellationSignal, startedTimestamp);
+ int numTypes = (request.getCredentialOptions().stream()
+ .map(CredentialOption::getType).collect(
+ Collectors.toSet())).size(); // Dedupe type strings
+ setupInitialPhaseMetric(ApiName.GET_CREDENTIAL.getMetricCode(), numTypes);
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
index 2dc930d..1b3e37a 100644
--- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -26,6 +26,7 @@
import com.android.server.credentials.metrics.ApiStatus;
import com.android.server.credentials.metrics.CandidatePhaseMetric;
import com.android.server.credentials.metrics.ChosenProviderMetric;
+import com.android.server.credentials.metrics.InitialPhaseMetric;
import java.util.Map;
@@ -39,7 +40,10 @@
public static final int DEFAULT_INT_32 = -1;
public static final int[] DEFAULT_REPEATED_INT_32 = new int[0];
-
+ // Used for single count metric emits, such as singular amounts of various types
+ public static final int UNIT = 1;
+ // Used for zero count metric emits, such as zero amounts of various types
+ public static final int ZERO = 0;
/**
* This retrieves the uid of any package name, given a context and a component name for the
@@ -155,4 +159,18 @@
}
}
+ /**
+ * Handles the metric emit for the initial phase.
+ *
+ * @param initialPhaseMetric contains all the data for this emit
+ */
+ protected static void logApiCalled(InitialPhaseMetric initialPhaseMetric) {
+ /*
+ FrameworkStatsLog.write(FrameworkStatsLog.INITIAL_PHASE,
+ .. session_id .. initialPhaseMetric.getSessionId(),
+ ...
+ TODO Immediately - Fill in asap now that the split atom is checked in.
+ */
+ }
+
}
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 42ec42b..ebd155a 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -38,6 +38,7 @@
import com.android.server.credentials.metrics.ApiStatus;
import com.android.server.credentials.metrics.CandidatePhaseMetric;
import com.android.server.credentials.metrics.ChosenProviderMetric;
+import com.android.server.credentials.metrics.InitialPhaseMetric;
import java.util.ArrayList;
import java.util.HashMap;
@@ -75,7 +76,7 @@
protected final Map<String, ProviderSession> mProviders = new HashMap<>();
protected ChosenProviderMetric mChosenProviderMetric = new ChosenProviderMetric();
- //TODO improve design to allow grouped metrics per request
+ protected InitialPhaseMetric mInitialPhaseMetric = new InitialPhaseMetric();
protected final String mHybridService;
@NonNull
@@ -96,7 +97,7 @@
@UserIdInt int userId, int callingUid, @NonNull T clientRequest, U clientCallback,
@NonNull String requestType,
CallingAppInfo callingAppInfo,
- CancellationSignal cancellationSignal) {
+ CancellationSignal cancellationSignal, long timestampStarted) {
mContext = context;
mUserId = userId;
mCallingUid = callingUid;
@@ -111,6 +112,9 @@
mUserId, this);
mHybridService = context.getResources().getString(
R.string.config_defaultCredentialManagerHybridService);
+ mInitialPhaseMetric.setCredentialServiceStartedTimeNanoseconds(timestampStarted);
+ mInitialPhaseMetric.setSessionId(mRequestId.hashCode());
+ mInitialPhaseMetric.setCallerUid(mCallingUid);
}
public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo,
@@ -118,6 +122,12 @@
protected abstract void launchUiWithProviderData(ArrayList<ProviderData> providerDataList);
+ // Sets up the initial metric collector for use across all request session impls
+ protected void setupInitialPhaseMetric(int metricCode, int requestClassType) {
+ this.mInitialPhaseMetric.setApiName(metricCode);
+ this.mInitialPhaseMetric.setCountRequestClassType(requestClassType);
+ }
+
// UI callbacks
@Override // from CredentialManagerUiCallbacks
diff --git a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
index 5f062b0..31c6f6f 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
@@ -25,6 +25,8 @@
*/
public class InitialPhaseMetric {
private static final String TAG = "PreCandidateMetric";
+ // A sequence id to order united emits, due to split, this will statically always be 1
+ public static final int SEQUENCE_ID = 1;
// The api being called, default set to unknown
private int mApiName = ApiName.UNKNOWN.getMetricCode();
@@ -32,8 +34,6 @@
private int mCallerUid = -1;
// The session id to unite multiple atom emits, default to -1
private long mSessionId = -1;
- // A sequence id to order united emits, default to -1
- private int mSequenceId = -1;
private int mCountRequestClassType = -1;
// Raw timestamps in nanoseconds, *the only* one logged as such (i.e. 64 bits) since it is a
@@ -50,7 +50,7 @@
/* ---------- Latencies ---------- */
- /* -- Direct Latencies -- */
+ /* -- Direct Latency Utility -- */
public int getServiceStartToQueryLatencyMicroseconds() {
return (int) ((this.mCredentialServiceStartedTimeNanoseconds
@@ -108,15 +108,6 @@
return mSessionId;
}
- /* ------ SequenceId ------ */
-
- public void setSequenceId(int sequenceId) {
- mSequenceId = sequenceId;
- }
-
- public int getSequenceId() {
- return mSequenceId;
- }
/* ------ Count Request Class Types ------ */
diff --git a/services/tests/servicestests/src/com/android/server/dreams/OWNERS b/services/tests/servicestests/src/com/android/server/dreams/OWNERS
new file mode 100644
index 0000000..2f19cf5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/dreams/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/dreams/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index c9612cd..ad63da5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -39,6 +39,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.Resources;
import android.hardware.authsecret.IAuthSecret;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
@@ -97,6 +98,7 @@
MockLockSettingsContext mContext;
LockSettingsStorageTestable mStorage;
+ Resources mResources;
FakeGateKeeperService mGateKeeperService;
NotificationManager mNotificationManager;
UserManager mUserManager;
@@ -122,6 +124,7 @@
@Before
public void setUp_baseServices() throws Exception {
+ mResources = createMockResources();
mGateKeeperService = new FakeGateKeeperService();
mNotificationManager = mock(NotificationManager.class);
mUserManager = mock(UserManager.class);
@@ -146,7 +149,7 @@
LocalServices.addService(WindowManagerInternal.class, mMockWindowManager);
final Context origContext = InstrumentationRegistry.getContext();
- mContext = new MockLockSettingsContext(origContext,
+ mContext = new MockLockSettingsContext(origContext, mResources,
mSettingsRule.mockContentResolver(origContext), mUserManager, mNotificationManager,
mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class),
mock(KeyguardManager.class), mFingerprintManager, mFaceManager, mPackageManager);
@@ -245,6 +248,22 @@
mLocalService = LocalServices.getService(LockSettingsInternal.class);
}
+ private Resources createMockResources() {
+ Resources res = mock(Resources.class);
+
+ // Set up some default configs, copied from core/res/res/values/config.xml
+ when(res.getBoolean(eq(com.android.internal.R.bool.config_disableLockscreenByDefault)))
+ .thenReturn(false);
+ when(res.getBoolean(
+ eq(com.android.internal.R.bool.config_enableCredentialFactoryResetProtection)))
+ .thenReturn(true);
+ when(res.getBoolean(eq(com.android.internal.R.bool.config_isMainUserPermanentAdmin)))
+ .thenReturn(true);
+ when(res.getBoolean(eq(com.android.internal.R.bool.config_strongAuthRequiredOnBoot)))
+ .thenReturn(true);
+ return res;
+ }
+
protected void setDeviceProvisioned(boolean provisioned) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, provisioned ? 1 : 0);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index 05208441e..10ed882 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
@@ -106,8 +107,8 @@
when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
MockLockSettingsContext context = new MockLockSettingsContext(origContext,
- mSettingsRule.mockContentResolver(origContext), mockUserManager,
- mock(NotificationManager.class), mock(DevicePolicyManager.class),
+ mock(Resources.class), mSettingsRule.mockContentResolver(origContext),
+ mockUserManager, mock(NotificationManager.class), mock(DevicePolicyManager.class),
mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class),
mock(FingerprintManager.class), mock(FaceManager.class),
mock(PackageManager.class));
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
index 21c367b..96d7cbe 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
@@ -27,6 +27,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Handler;
@@ -36,6 +37,7 @@
public class MockLockSettingsContext extends ContextWrapper {
+ private final Resources mResources;
private final ContentResolver mContentResolver;
private final UserManager mUserManager;
private final NotificationManager mNotificationManager;
@@ -47,13 +49,14 @@
private final FaceManager mFaceManager;
private final PackageManager mPackageManager;
- public MockLockSettingsContext(Context base, ContentResolver contentResolver,
- UserManager userManager, NotificationManager notificationManager,
- DevicePolicyManager devicePolicyManager, StorageManager storageManager,
- TrustManager trustManager, KeyguardManager keyguardManager,
- FingerprintManager fingerprintManager, FaceManager faceManager,
- PackageManager packageManager) {
+ public MockLockSettingsContext(Context base, Resources resources,
+ ContentResolver contentResolver, UserManager userManager,
+ NotificationManager notificationManager, DevicePolicyManager devicePolicyManager,
+ StorageManager storageManager, TrustManager trustManager,
+ KeyguardManager keyguardManager, FingerprintManager fingerprintManager,
+ FaceManager faceManager, PackageManager packageManager) {
super(base);
+ mResources = resources;
mContentResolver = contentResolver;
mUserManager = userManager;
mNotificationManager = notificationManager;
@@ -67,6 +70,11 @@
}
@Override
+ public Resources getResources() {
+ return mResources;
+ }
+
+ @Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 2affe92..8b178dd 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -41,7 +41,7 @@
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.RemoteLockscreenValidationResult;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@@ -1326,11 +1326,10 @@
when(mLockSettingsService.getCredentialType(anyInt())).thenReturn(
LockPatternUtils.CREDENTIAL_TYPE_PIN);
- StartLockscreenValidationRequest request =
+ RemoteLockscreenValidationSession request =
mRecoverableKeyStoreManager.startRemoteLockscreenValidation(mLockSettingsService);
- int credetialsType = request.getLockscreenUiType();
- assertThat(credetialsType).isEqualTo(KeyguardManager.PIN);
+ assertThat(request.getLockType()).isEqualTo(KeyguardManager.PIN);
assertThat(request.getRemainingAttempts()).isEqualTo(5);
verify(mLockSettingsService).getCredentialType(anyInt());
}
@@ -1340,11 +1339,10 @@
LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
mRecoverableKeyStoreDb.setBadRemoteGuessCounter(mUserId, 3);
- StartLockscreenValidationRequest request =
+ RemoteLockscreenValidationSession request =
mRecoverableKeyStoreManager.startRemoteLockscreenValidation(mLockSettingsService);
- int credetialsType = request.getLockscreenUiType();
- assertThat(credetialsType).isEqualTo(KeyguardManager.PATTERN);
+ assertThat(request.getLockType()).isEqualTo(KeyguardManager.PATTERN);
assertThat(request.getRemainingAttempts()).isEqualTo(2);
}
@Test
@@ -1353,24 +1351,23 @@
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
mRecoverableKeyStoreDb.setBadRemoteGuessCounter(mUserId, 7);
- StartLockscreenValidationRequest request =
+ RemoteLockscreenValidationSession request =
mRecoverableKeyStoreManager.startRemoteLockscreenValidation(mLockSettingsService);
- int credetialsType = request.getLockscreenUiType();
assertThat(request.getRemainingAttempts()).isEqualTo(0);
- assertThat(credetialsType).isEqualTo(KeyguardManager.PASSWORD);
+ assertThat(request.getLockType()).isEqualTo(KeyguardManager.PASSWORD);
}
@Test
public void validateRemoteLockscreen_noActiveSession() throws Exception {
when(mLockSettingsService.getCredentialType(anyInt())).thenReturn(
- LockPatternUtils.CREDENTIAL_TYPE_NONE);
- try {
- mRecoverableKeyStoreManager.validateRemoteLockscreen(INVALID_GUESS,
- mLockSettingsService);
- fail("should have thrown");
- } catch (IllegalStateException e) {
- assertThat(e.getMessage()).contains("session");
- }
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
+
+ RemoteLockscreenValidationResult result =
+ mRecoverableKeyStoreManager.validateRemoteLockscreen(INVALID_GUESS,
+ mLockSettingsService);
+
+ assertThat(result.getResultCode()).isEqualTo(
+ RemoteLockscreenValidationResult.RESULT_SESSION_EXPIRED);
}
@Test
public void validateRemoteLockscreen_decryptionError() throws Exception {
@@ -1456,7 +1453,7 @@
}
private byte[] encryptCredentialsForNewSession(byte[] credentials) throws Exception {
- StartLockscreenValidationRequest request =
+ RemoteLockscreenValidationSession request =
mRecoverableKeyStoreManager.startRemoteLockscreenValidation(mLockSettingsService);
PublicKey publicKey = SecureBox.decodePublicKey(request.getSourcePublicKey());
return SecureBox.encrypt(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index e3cb5fb..b46a3b9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1728,7 +1728,7 @@
final ActivityInfo info = new ActivityInfo();
info.applicationInfo = new ApplicationInfo();
info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID,
- 0 /* launchMode */);
+ 0 /* launchMode */, null /* componentName */);
info.requiredDisplayCategory = "automotive";
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info)
.build();
@@ -1754,7 +1754,7 @@
final ActivityInfo info = new ActivityInfo();
info.applicationInfo = new ApplicationInfo();
info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID,
- 0 /* launchMode */);
+ 0 /* launchMode */, null /* componentName */);
info.requiredDisplayCategory = "automotive";
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info)
.build();
@@ -1780,7 +1780,7 @@
final ActivityInfo info = new ActivityInfo();
info.applicationInfo = new ApplicationInfo();
info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID,
- 0 /* launchMode */);
+ 0 /* launchMode */, null /* componentName */);
info.requiredDisplayCategory = "automotive";
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info)
.build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 74dd361..12f9a9e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -448,12 +448,15 @@
final String taskAffinity = "affinity";
final int uid = 10123;
final Task task1 = createTaskBuilder(".Task1").build();
- task1.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ final ComponentName componentName = getUniqueComponentName();
+ task1.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE,
+ componentName);
mRecentTasks.add(task1);
// Add another task to recents, and make sure the previous task was removed.
final Task task2 = createTaskBuilder(".Task2").build();
- task2.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ task2.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE,
+ componentName);
mRecentTasks.add(task2);
assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
@@ -461,7 +464,7 @@
// Add another single-instance task to recents, and make sure no task is removed.
final Task task3 = createTaskBuilder(".Task3").build();
task3.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid,
- LAUNCH_SINGLE_INSTANCE);
+ LAUNCH_SINGLE_INSTANCE, componentName);
mRecentTasks.add(task3);
assertEquals(2, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index c4d760f..dd7e2d7 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -997,7 +997,8 @@
*/
public static final int IWLAN_CONGESTION = 0x3C8C;
- /** IKE configuration error resulting in failure */
+ // Below IWLAN error codes are defined by the UE and do not relate to any 3GPP spec value
+ /** IKE configuration error resulting in failure */
public static final int IWLAN_IKEV2_CONFIG_FAILURE = 0x4000;
/**
* Sent in the response to an IKE_AUTH message when, for some reason,
@@ -1014,6 +1015,57 @@
public static final int IWLAN_DNS_RESOLUTION_TIMEOUT = 0x4005;
/** Expected to update or bring down an ePDG tunnel, but no tunnel found*/
public static final int IWLAN_TUNNEL_NOT_FOUND = 0x4006;
+ /**
+ * Failed to apply tunnel transform
+ *
+ * @hide
+ */
+ public static final int IWLAN_TUNNEL_TRANSFORM_FAILED = 0x4007;
+ /**
+ * IWLAN PDN setup failed due to Wi-Fi lost during IKE tunnel setup,
+ * match exception reported by IKE module
+ *
+ * @hide
+ */
+ public static final int IWLAN_IKE_NETWORK_LOST_EXCEPTION = 0x4008;
+ /**
+ * Carrier-specific error codes during IKEv2 SA setup
+ *
+ * @hide
+ */
+ public static final int IWLAN_IKE_PRIVATE_PROTOCOL_ERROR = 0x4009;
+ /**
+ * IKE Session closed before child session opened
+ *
+ * @hide
+ */
+ public static final int IWLAN_IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED = 0x400A;
+ /**
+ * IKE Init timeout, no response from EPDG
+ *
+ * @hide
+ */
+ public static final int IWLAN_IKE_INIT_TIMEOUT = 0x400B;
+ /**
+ * DPD message does not get an ack after the re-tx attempts and duration, i.e., times out.
+ *
+ * @hide
+ */
+ public static final int IWLAN_IKE_DPD_TIMEOUT = 0x400C;
+ /**
+ * The Wi-Fi to Wi-Fi handover of the IMS PDN fails because the network does not respond to the
+ * MOBIKE/rekey mobility message in the expected manner
+ *
+ * @hide
+ */
+ public static final int IWLAN_IKE_MOBILITY_TIMEOUT = 0x400D;
+ /**
+ * IKE client sent "IKE AUTH request 3" to the network but got "Internal address failure" from
+ * the network since no internal addresses can be assigned.
+ *
+ * @hide
+ */
+ public static final int IWLAN_EPDG_INTERNAL_ADDRESS_FAILURE = 0x400E;
// OEM sepecific error codes. To be used by OEMs when they don't
// want to reveal error code which would be replaced by ERROR_UNSPECIFIED
@@ -1508,6 +1560,16 @@
sFailCauseMap.put(IWLAN_DNS_RESOLUTION_NAME_FAILURE, "IWLAN_DNS_RESOLUTION_NAME_FAILURE");
sFailCauseMap.put(IWLAN_DNS_RESOLUTION_TIMEOUT, "IWLAN_DNS_RESOLUTION_TIMEOUT");
sFailCauseMap.put(IWLAN_TUNNEL_NOT_FOUND, "IWLAN_TUNNEL_NOT_FOUND");
+ sFailCauseMap.put(IWLAN_TUNNEL_TRANSFORM_FAILED, "IWLAN_TUNNEL_TRANSFORM_FAILED");
+ sFailCauseMap.put(IWLAN_IKE_INIT_TIMEOUT, "IWLAN_IKE_INIT_TIMEOUT");
+ sFailCauseMap.put(IWLAN_IKE_NETWORK_LOST_EXCEPTION, "IWLAN_IKE_NETWORK_LOST_EXCEPTION");
+ sFailCauseMap.put(IWLAN_IKE_PRIVATE_PROTOCOL_ERROR, "IWLAN_IKE_PRIVATE_PROTOCOL_ERROR");
+ sFailCauseMap.put(IWLAN_IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED,
+ "IWLAN_IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED");
+ sFailCauseMap.put(IWLAN_IKE_DPD_TIMEOUT, "IWLAN_IKE_DPD_TIMEOUT");
+ sFailCauseMap.put(IWLAN_IKE_MOBILITY_TIMEOUT, "IWLAN_IKE_MOBILITY_TIMEOUT");
+ sFailCauseMap.put(IWLAN_EPDG_INTERNAL_ADDRESS_FAILURE,
+ "IWLAN_EPDG_INTERNAL_ADDRESS_FAILURE");
sFailCauseMap.put(OEM_DCFAILCAUSE_1, "OEM_DCFAILCAUSE_1");
sFailCauseMap.put(OEM_DCFAILCAUSE_2, "OEM_DCFAILCAUSE_2");
sFailCauseMap.put(OEM_DCFAILCAUSE_3, "OEM_DCFAILCAUSE_3");
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 758372a..5cbbe37 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -4374,7 +4374,6 @@
*
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION)
public void setSubscriptionUserHandle(int subscriptionId, @Nullable UserHandle userHandle) {
if (!isValidSubscriptionId(subscriptionId)) {
@@ -4409,7 +4408,6 @@
*
* @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION)
public @Nullable UserHandle getSubscriptionUserHandle(int subscriptionId) {
if (!isValidSubscriptionId(subscriptionId)) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index 0e852b6..6e4e937 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -58,7 +58,51 @@
}
/**
- * Expands the PIP window my using the pinch out gesture.
+ * Drags the PIP window away from the screen edge while not crossing the display center.
+ *
+ * @throws IllegalStateException if default display bounds are not available
+ * @return initial bounds of the PIP window
+ */
+ fun dragPipWindowAwayFromEdge(wmHelper: WindowManagerStateHelper, steps: Int): Rect {
+ val initWindowRect = getWindowRect(wmHelper).clone()
+
+ // initial pointer at the center of the window
+ val startX = initWindowRect.centerX()
+ val y = initWindowRect.centerY()
+
+ val displayRect = wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect
+ ?: throw IllegalStateException("Default display is null")
+
+ // the offset to the right of the display center to drag the window to
+ val offset = 20
+
+ // the actual final x coordinate with the offset included
+ // if the pip window is closer to the right edge of the display the offset is positive
+ // otherwise the offset is negative
+ val endX = displayRect.centerX() + offset * (if (isCloserToRightEdge(wmHelper)) 1 else -1)
+
+ // drag the window to the left but not beyond the center of the display
+ uiDevice.drag(startX, y, endX, y, steps)
+
+ return initWindowRect
+ }
+
+ /**
+ * Returns true if PIP window is closer to the right edge of the display than left.
+ *
+ * @throws IllegalStateException if default display bounds are not available
+ */
+ private fun isCloserToRightEdge(wmHelper: WindowManagerStateHelper): Boolean {
+ val windowRect = getWindowRect(wmHelper)
+
+ val displayRect = wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect
+ ?: throw IllegalStateException("Default display is null")
+
+ return windowRect.centerX() > displayRect.centerX()
+ }
+
+ /**
+ * Expands the PIP window by using the pinch out gesture.
*
* @param percent The percentage by which to increase the pip window size.
* @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f
@@ -106,7 +150,7 @@
}
/**
- * Minimizes the PIP window my using the pinch in gesture.
+ * Minimizes the PIP window by using the pinch in gesture.
*
* @param percent The percentage by which to decrease the pip window size.
* @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f
@@ -307,6 +351,27 @@
.waitForAndVerify()
}
+ /**
+ * Waits until the PIP window snaps horizontally to the provided bounds.
+ *
+ * @param finalRightX the final x coordinate of the right edge of the pip window
+ */
+ fun waitForPipToSnapTo(wmHelper: WindowManagerStateHelper, finalBounds: android.graphics.Rect) {
+ wmHelper
+ .StateSyncBuilder()
+ .add("pipWindowSnapped") {
+ val pipAppWindow =
+ it.wmState.visibleWindows.firstOrNull { window ->
+ this.windowMatchesAnyOf(window)
+ }
+ ?: return@add false
+ val pipRegionBounds = pipAppWindow.frameRegion.bounds
+ return@add pipRegionBounds.left == finalBounds.left &&
+ pipRegionBounds.right == finalBounds.right
+ }
+ .waitForAndVerify()
+ }
+
companion object {
private const val TAG = "PipAppHelper"
private const val ENTER_PIP_BUTTON_ID = "enter_pip"
diff --git a/tests/testables/src/android/testing/TestableContext.java b/tests/testables/src/android/testing/TestableContext.java
index e2668bc..0f04d6a 100644
--- a/tests/testables/src/android/testing/TestableContext.java
+++ b/tests/testables/src/android/testing/TestableContext.java
@@ -33,11 +33,15 @@
import android.util.ArrayMap;
import android.view.LayoutInflater;
+import androidx.annotation.Nullable;
+
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import java.util.ArrayList;
+
/**
* A ContextWrapper with utilities specifically designed to make Testing easier.
*
@@ -61,6 +65,7 @@
private final TestableContentResolver mTestableContentResolver;
private final TestableSettingsProvider mSettingsProvider;
+ private ArrayList<MockServiceResolver> mMockServiceResolvers;
private ArrayMap<String, Object> mMockSystemServices;
private ArrayMap<ComponentName, IBinder> mMockServices;
private ArrayMap<ServiceConnection, ComponentName> mActiveServices;
@@ -214,12 +219,15 @@
/**
* Adds a mock service to be connected to by a bindService call.
* <p>
- * Normally a TestableContext will pass through all bind requests to the base context
- * but when addMockService has been called for a ComponentName being bound, then
- * TestableContext will immediately trigger a {@link ServiceConnection#onServiceConnected}
- * with the specified service, and will call {@link ServiceConnection#onServiceDisconnected}
- * when the service is unbound.
+ * Normally a TestableContext will pass through all bind requests to the base context
+ * but when addMockService has been called for a ComponentName being bound, then
+ * TestableContext will immediately trigger a {@link ServiceConnection#onServiceConnected}
+ * with the specified service, and will call {@link ServiceConnection#onServiceDisconnected}
+ * when the service is unbound.
* </p>
+ *
+ * @see #addMockServiceResolver(MockServiceResolver) for custom resolution of service Intents to
+ * ComponentNames
*/
public void addMockService(ComponentName component, IBinder service) {
if (mMockServices == null) mMockServices = new ArrayMap<>();
@@ -227,12 +235,38 @@
}
/**
+ * Strategy to resolve a service {@link Intent} to a mock service {@link ComponentName}.
+ */
+ public interface MockServiceResolver {
+ @Nullable
+ ComponentName resolve(Intent service);
+ }
+
+ /**
+ * Registers a strategy to resolve service intents to registered mock services.
+ * <p>
+ * The result of the first {@link MockServiceResolver} to return a non-null
+ * {@link ComponentName} is used to look up a mock service. The mock service must be registered
+ * via {@link #addMockService(ComponentName, IBinder)} separately, using the same component
+ * name.
+ *
+ * If none of the resolvers return a non-null value, or the first returned component name
+ * does not link to a registered mock service, the bind requests are passed to the base context
+ *
+ * The resolvers are queried in order of registration.
+ */
+ public void addMockServiceResolver(MockServiceResolver resolver) {
+ if (mMockServiceResolvers == null) mMockServiceResolvers = new ArrayList<>();
+ mMockServiceResolvers.add(resolver);
+ }
+
+ /**
* @see #addMockService(ComponentName, IBinder)
*/
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
- if (checkMocks(service.getComponent(), conn)) return true;
+ if (checkMocks(service, conn)) return true;
return super.bindService(service, conn, flags);
}
@@ -243,7 +277,7 @@
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
Handler handler, UserHandle user) {
if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
- if (checkMocks(service.getComponent(), conn)) return true;
+ if (checkMocks(service, conn)) return true;
return super.bindServiceAsUser(service, conn, flags, handler, user);
}
@@ -254,18 +288,36 @@
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
- if (checkMocks(service.getComponent(), conn)) return true;
+ if (checkMocks(service, conn)) return true;
return super.bindServiceAsUser(service, conn, flags, user);
}
- private boolean checkMocks(ComponentName component, ServiceConnection conn) {
- if (mMockServices != null && component != null && mMockServices.containsKey(component)) {
- if (mActiveServices == null) mActiveServices = new ArrayMap<>();
- mActiveServices.put(conn, component);
- conn.onServiceConnected(component, mMockServices.get(component));
- return true;
+ private boolean checkMocks(Intent service, ServiceConnection conn) {
+ if (mMockServices == null) return false;
+
+ ComponentName serviceComponent = resolveMockServiceComponent(service);
+ if (serviceComponent == null) return false;
+
+ IBinder serviceImpl = mMockServices.get(serviceComponent);
+ if (serviceImpl == null) return false;
+
+ if (mActiveServices == null) mActiveServices = new ArrayMap<>();
+ mActiveServices.put(conn, serviceComponent);
+ conn.onServiceConnected(serviceComponent, serviceImpl);
+ return true;
+ }
+
+ private ComponentName resolveMockServiceComponent(Intent service) {
+ ComponentName specifiedComponentName = service.getComponent();
+ if (specifiedComponentName != null) return specifiedComponentName;
+
+ if (mMockServiceResolvers == null) return null;
+
+ for (MockServiceResolver resolver : mMockServiceResolvers) {
+ ComponentName resolvedComponent = resolver.resolve(service);
+ if (resolvedComponent != null) return resolvedComponent;
}
- return false;
+ return null;
}
/**
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
index d3b7b12..9bfeb63 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
@@ -207,10 +207,14 @@
}
}
- private static void validate(long deviceId, @NetworkType int networkType, String networkName) {
+ private static void validate(long deviceId, @NetworkType int networkType, String networkName,
+ NetworkProviderInfo networkProviderInfo) {
if (deviceId < 0) {
throw new IllegalArgumentException("DeviceId must be set");
}
+ if (Objects.isNull(networkProviderInfo)) {
+ throw new IllegalArgumentException("NetworkProviderInfo must be set");
+ }
if (networkType != NETWORK_TYPE_CELLULAR && networkType != NETWORK_TYPE_WIFI
&& networkType != NETWORK_TYPE_ETHERNET && networkType != NETWORK_TYPE_UNKNOWN) {
throw new IllegalArgumentException("Illegal network type");
@@ -230,7 +234,8 @@
@Nullable @SecurityType ArraySet<Integer> hotspotSecurityTypes) {
validate(deviceId,
networkType,
- networkName);
+ networkName,
+ networkProviderInfo);
mDeviceId = deviceId;
mNetworkProviderInfo = networkProviderInfo;
mNetworkType = networkType;
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
index 8e396b6..8302094 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
@@ -26,12 +26,16 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
+
import android.os.Parcel;
import android.util.ArraySet;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Arrays;
@@ -39,6 +43,7 @@
* Unit tests for {@link HotspotNetwork}.
*/
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class HotspotNetworkTest {
private static final long DEVICE_ID = 11L;
private static final NetworkProviderInfo NETWORK_PROVIDER_INFO =
@@ -67,7 +72,7 @@
*/
@Test
public void testParcelOperation() {
- HotspotNetwork network = buildHotspotNetworkBuilder().build();
+ HotspotNetwork network = buildHotspotNetworkBuilder(true).build();
Parcel parcelW = Parcel.obtain();
network.writeToParcel(parcelW, 0);
@@ -88,30 +93,30 @@
*/
@Test
public void testEqualsOperation() {
- HotspotNetwork network1 = buildHotspotNetworkBuilder().build();
- HotspotNetwork network2 = buildHotspotNetworkBuilder().build();
+ HotspotNetwork network1 = buildHotspotNetworkBuilder(true).build();
+ HotspotNetwork network2 = buildHotspotNetworkBuilder(true).build();
assertThat(network1).isEqualTo(network2);
- HotspotNetwork.Builder builder = buildHotspotNetworkBuilder().setDeviceId(DEVICE_ID_1);
+ HotspotNetwork.Builder builder = buildHotspotNetworkBuilder(true).setDeviceId(DEVICE_ID_1);
assertThat(builder.build()).isNotEqualTo(network1);
- builder = buildHotspotNetworkBuilder().setNetworkProviderInfo(NETWORK_PROVIDER_INFO1);
+ builder = buildHotspotNetworkBuilder(true).setNetworkProviderInfo(NETWORK_PROVIDER_INFO1);
assertThat(builder.build()).isNotEqualTo(network1);
- builder = buildHotspotNetworkBuilder().setHostNetworkType(NETWORK_TYPE_1);
+ builder = buildHotspotNetworkBuilder(true).setHostNetworkType(NETWORK_TYPE_1);
assertThat(builder.build()).isNotEqualTo(network1);
- builder = buildHotspotNetworkBuilder().setNetworkName(NETWORK_NAME_1);
+ builder = buildHotspotNetworkBuilder(true).setNetworkName(NETWORK_NAME_1);
assertThat(builder.build()).isNotEqualTo(network1);
- builder = buildHotspotNetworkBuilder().setHotspotSsid(HOTSPOT_SSID_1);
+ builder = buildHotspotNetworkBuilder(true).setHotspotSsid(HOTSPOT_SSID_1);
assertThat(builder.build()).isNotEqualTo(network1);
- builder = buildHotspotNetworkBuilder().setHotspotBssid(HOTSPOT_BSSID_1);
+ builder = buildHotspotNetworkBuilder(true).setHotspotBssid(HOTSPOT_BSSID_1);
assertThat(builder.build()).isNotEqualTo(network1);
- builder = buildHotspotNetworkBuilder();
- HotspotNetwork.Builder builder1 = buildHotspotNetworkBuilder();
+ builder = buildHotspotNetworkBuilder(true);
+ HotspotNetwork.Builder builder1 = buildHotspotNetworkBuilder(true);
Arrays.stream(HOTSPOT_SECURITY_TYPES_1).forEach(builder1::addHotspotSecurityType);
assertThat(builder1.build()).isNotEqualTo(builder.build());
@@ -122,7 +127,7 @@
*/
@Test
public void testGetMethods() {
- HotspotNetwork network = buildHotspotNetworkBuilder().build();
+ HotspotNetwork network = buildHotspotNetworkBuilder(true).build();
ArraySet<Integer> securityTypes = new ArraySet<>();
Arrays.stream(HOTSPOT_SECURITY_TYPES).forEach(securityTypes::add);
@@ -137,21 +142,30 @@
@Test
public void testHashCode() {
- HotspotNetwork network1 = buildHotspotNetworkBuilder().build();
- HotspotNetwork network2 = buildHotspotNetworkBuilder().build();
+ HotspotNetwork network1 = buildHotspotNetworkBuilder(true).build();
+ HotspotNetwork network2 = buildHotspotNetworkBuilder(true).build();
assertThat(network1.hashCode()).isEqualTo(network2.hashCode());
}
- private HotspotNetwork.Builder buildHotspotNetworkBuilder() {
+ @Test
+ public void networkProviderInfoNotSet_shouldThrowException() {
+ Exception e = assertThrows(IllegalArgumentException.class,
+ () -> buildHotspotNetworkBuilder(false).build());
+ assertThat(e.getMessage()).contains("NetworkProviderInfo");
+ }
+
+ private HotspotNetwork.Builder buildHotspotNetworkBuilder(boolean withNetworkProviderInfo) {
HotspotNetwork.Builder builder = new HotspotNetwork.Builder()
.setDeviceId(DEVICE_ID)
- .setNetworkProviderInfo(NETWORK_PROVIDER_INFO)
.setHostNetworkType(NETWORK_TYPE)
.setNetworkName(NETWORK_NAME)
.setHotspotSsid(HOTSPOT_SSID)
.setHotspotBssid(HOTSPOT_BSSID);
Arrays.stream(HOTSPOT_SECURITY_TYPES).forEach(builder::addHotspotSecurityType);
+ if (withNetworkProviderInfo) {
+ builder.setNetworkProviderInfo(NETWORK_PROVIDER_INFO);
+ }
return builder;
}
}