Merge "API feedback: make bubble pref an int def" into sc-dev
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java
index e585d91..4357905 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java
@@ -16,6 +16,7 @@
package android.app.appsearch;
+import static android.app.appsearch.AppSearchResult.RESULT_INVALID_SCHEMA;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
@@ -27,6 +28,7 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.util.ArraySet;
import com.android.internal.infra.AndroidFuture;
@@ -39,8 +41,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
/**
@@ -55,23 +57,23 @@
private final String mDatabaseName;
private final int mUserId;
private final File mMigratedFile;
- private final Map<String, Integer> mCurrentVersionMap;
- private final Map<String, Integer> mFinalVersionMap;
+ private final Set<String> mDestinationTypes;
private boolean mAreDocumentsMigrated = false;
AppSearchMigrationHelper(@NonNull IAppSearchManager service,
@UserIdInt int userId,
- @NonNull Map<String, Integer> currentVersionMap,
- @NonNull Map<String, Integer> finalVersionMap,
@NonNull String packageName,
- @NonNull String databaseName) throws IOException {
+ @NonNull String databaseName,
+ @NonNull Set<AppSearchSchema> newSchemas) throws IOException {
mService = Objects.requireNonNull(service);
- mCurrentVersionMap = Objects.requireNonNull(currentVersionMap);
- mFinalVersionMap = Objects.requireNonNull(finalVersionMap);
mPackageName = Objects.requireNonNull(packageName);
mDatabaseName = Objects.requireNonNull(databaseName);
mUserId = userId;
mMigratedFile = File.createTempFile(/*prefix=*/"appsearch", /*suffix=*/null);
+ mDestinationTypes = new ArraySet<>(newSchemas.size());
+ for (AppSearchSchema newSchema : newSchemas) {
+ mDestinationTypes.add(newSchema.getSchemaType());
+ }
}
/**
@@ -87,7 +89,8 @@
* GenericDocument} to new version.
*/
@WorkerThread
- public void queryAndTransform(@NonNull String schemaType, @NonNull Migrator migrator)
+ public void queryAndTransform(@NonNull String schemaType, @NonNull Migrator migrator,
+ int currentVersion, int finalVersion)
throws IOException, AppSearchException, InterruptedException, ExecutionException {
File queryFile = File.createTempFile(/*prefix=*/"appsearch", /*suffix=*/null);
try (ParcelFileDescriptor fileDescriptor =
@@ -111,7 +114,7 @@
if (!result.isSuccess()) {
throw new AppSearchException(result.getResultCode(), result.getErrorMessage());
}
- readAndTransform(queryFile, migrator);
+ readAndTransform(queryFile, migrator, currentVersion, finalVersion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} finally {
@@ -173,8 +176,9 @@
*
* <p>Save migrated {@link GenericDocument}s to the {@link #mMigratedFile}.
*/
- private void readAndTransform(@NonNull File file, @NonNull Migrator migrator)
- throws IOException {
+ private void readAndTransform(@NonNull File file, @NonNull Migrator migrator,
+ int currentVersion, int finalVersion)
+ throws IOException, AppSearchException {
try (DataInputStream inputStream = new DataInputStream(new FileInputStream(file));
DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(
mMigratedFile, /*append=*/ true))) {
@@ -187,9 +191,6 @@
// Nothing wrong. We just finished reading.
}
- int currentVersion = mCurrentVersionMap.get(document.getSchemaType());
- int finalVersion = mFinalVersionMap.get(document.getSchemaType());
-
GenericDocument newDocument;
if (currentVersion < finalVersion) {
newDocument = migrator.onUpgrade(currentVersion, finalVersion, document);
@@ -197,6 +198,18 @@
// currentVersion == finalVersion case won't trigger migration and get here.
newDocument = migrator.onDowngrade(currentVersion, finalVersion, document);
}
+
+ if (!mDestinationTypes.contains(newDocument.getSchemaType())) {
+ // we exit before the new schema has been set to AppSearch. So no
+ // observable changes will be applied to stored schemas and documents.
+ // And the temp file will be deleted at close(), which will be triggered at
+ // the end of try-with-resources block of SearchSessionImpl.
+ throw new AppSearchException(
+ RESULT_INVALID_SCHEMA,
+ "Receive a migrated document with schema type: "
+ + newDocument.getSchemaType()
+ + ". But the schema types doesn't exist in the request");
+ }
writeBundleToOutputStream(outputStream, newDocument.getBundle());
}
mAreDocumentsMigrated = true;
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 4dd1b79..3677489 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -19,7 +19,6 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
-import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.util.SchemaMigrationUtil;
import android.os.Bundle;
import android.os.ParcelableException;
@@ -647,8 +646,8 @@
new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
schemasPackageAccessibleBundles,
request.isForceOverride(),
- mUserId,
request.getVersion(),
+ mUserId,
new IAppSearchResultCallback.Stub() {
public void onResult(AppSearchResult result) {
executor.execute(() -> {
@@ -661,7 +660,7 @@
// Throw exception if there is any deleted types or
// incompatible types. That's the only case we swallowed
// in the AppSearchImpl#setSchema().
- checkDeletedAndIncompatible(
+ SchemaMigrationUtil.checkDeletedAndIncompatible(
setSchemaResponse.getDeletedTypes(),
setSchemaResponse.getIncompatibleTypes());
}
@@ -698,7 +697,7 @@
workExecutor.execute(() -> {
try {
// Migration process
- // 1. Generate the current and the final version map.
+ // 1. Validate and retrieve all active migrators.
AndroidFuture<AppSearchResult<GetSchemaResponse>> getSchemaFuture =
new AndroidFuture<>();
getSchema(callbackExecutor, getSchemaFuture::complete);
@@ -709,11 +708,18 @@
return;
}
GetSchemaResponse getSchemaResponse = getSchemaResult.getResultValue();
- Set<AppSearchSchema> currentSchemas = getSchemaResponse.getSchemas();
- Map<String, Integer> currentVersionMap = SchemaMigrationUtil.buildVersionMap(
- currentSchemas, getSchemaResponse.getVersion());
- Map<String, Integer> finalVersionMap = SchemaMigrationUtil.buildVersionMap(
- request.getSchemas(), request.getVersion());
+ int currentVersion = getSchemaResponse.getVersion();
+ int finalVersion = request.getVersion();
+ Map<String, Migrator> activeMigrators = SchemaMigrationUtil.getActiveMigrators(
+ getSchemaResponse.getSchemas(), request.getMigrators(), currentVersion,
+ finalVersion);
+
+ // No need to trigger migration if no migrator is active.
+ if (activeMigrators.isEmpty()) {
+ setSchemaNoMigrations(request, schemaBundles, schemasPackageAccessibleBundles,
+ callbackExecutor, callback);
+ return;
+ }
// 2. SetSchema with forceOverride=false, to retrieve the list of
// incompatible/deleted types.
@@ -725,8 +731,8 @@
new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
schemasPackageAccessibleBundles,
/*forceOverride=*/ false,
- mUserId,
request.getVersion(),
+ mUserId,
new IAppSearchResultCallback.Stub() {
public void onResult(AppSearchResult result) {
setSchemaFuture.complete(result);
@@ -741,46 +747,27 @@
SetSchemaResponse setSchemaResponse =
new SetSchemaResponse(setSchemaResult.getResultValue());
- // 1. If forceOverride is false, check that all incompatible types will be migrated.
+ // 3. If forceOverride is false, check that all incompatible types will be migrated.
// If some aren't we must throw an error, rather than proceeding and deleting those
// types.
if (!request.isForceOverride()) {
- Set<String> unmigratedTypes =
- SchemaMigrationUtil.getUnmigratedIncompatibleTypes(
- setSchemaResponse.getIncompatibleTypes(),
- request.getMigrators(),
- currentVersionMap,
- finalVersionMap);
-
- // check if there are any unmigrated types or deleted types. If there are, we
- // will throw an exception.
- // Since the force override is false, the schema will not have been set if there
- // are any incompatible or deleted types.
- checkDeletedAndIncompatible(
- setSchemaResponse.getDeletedTypes(), unmigratedTypes);
+ SchemaMigrationUtil.checkDeletedAndIncompatibleAfterMigration(setSchemaResponse,
+ activeMigrators.keySet());
}
- try (AppSearchMigrationHelper migrationHelper =
- new AppSearchMigrationHelper(
- mService, mUserId, currentVersionMap, finalVersionMap,
- mPackageName, mDatabaseName)) {
- Map<String, Migrator> migratorMap = request.getMigrators();
+ try (AppSearchMigrationHelper migrationHelper = new AppSearchMigrationHelper(
+ mService, mUserId, mPackageName, mDatabaseName, request.getSchemas())) {
- // 2. Trigger migration for all migrators.
+ // 4. Trigger migration for all migrators.
// TODO(b/177266929) trigger migration for all types together rather than
// separately.
- Set<String> migratedTypes = new ArraySet<>();
- for (Map.Entry<String, Migrator> entry : migratorMap.entrySet()) {
- String schemaType = entry.getKey();
- Migrator migrator = entry.getValue();
- if (SchemaMigrationUtil.shouldTriggerMigration(
- schemaType, migrator, currentVersionMap, finalVersionMap)) {
- migrationHelper.queryAndTransform(schemaType, migrator);
- migratedTypes.add(schemaType);
- }
+ for (Map.Entry<String, Migrator> entry : activeMigrators.entrySet()) {
+ migrationHelper.queryAndTransform(/*schemaType=*/ entry.getKey(),
+ /*migrator=*/ entry.getValue(), currentVersion,
+ finalVersion);
}
- // 3. SetSchema a second time with forceOverride=true if the first attempted
+ // 5. SetSchema a second time with forceOverride=true if the first attempted
// failed.
if (!setSchemaResponse.getIncompatibleTypes().isEmpty()
|| !setSchemaResponse.getDeletedTypes().isEmpty()) {
@@ -809,13 +796,16 @@
// error in the first setSchema call, all other errors will be thrown at
// the first time.
callbackExecutor.execute(() -> callback.accept(
- AppSearchResult.newFailedResult(setSchemaResult)));
+ AppSearchResult.newFailedResult(setSchema2Result)));
return;
}
}
SetSchemaResponse.Builder responseBuilder = setSchemaResponse.toBuilder()
- .addMigratedTypes(migratedTypes);
+ .addMigratedTypes(activeMigrators.keySet());
+
+ // 6. Put all the migrated documents into the index, now that the new schema is
+ // set.
AppSearchResult<SetSchemaResponse> putResult =
migrationHelper.putMigratedDocuments(responseBuilder);
callbackExecutor.execute(() -> callback.accept(putResult));
@@ -826,17 +816,4 @@
}
});
}
-
- /** Checks the setSchema() call won't delete any types or has incompatible types. */
- //TODO(b/177266929) move this method to util
- private void checkDeletedAndIncompatible(Set<String> deletedTypes,
- Set<String> incompatibleTypes)
- throws AppSearchException {
- if (!deletedTypes.isEmpty() || !incompatibleTypes.isEmpty()) {
- String newMessage = "Schema is incompatible."
- + "\n Deleted types: " + deletedTypes
- + "\n Incompatible types: " + incompatibleTypes;
- throw new AppSearchException(AppSearchResult.RESULT_INVALID_SCHEMA, newMessage);
- }
- }
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
index a8ac27c..4d05ad7 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -40,6 +40,7 @@
* packages. The value List contains PackageIdentifier Bundles.
* @param forceOverride Whether to apply the new schema even if it is incompatible. All
* incompatible documents will be deleted.
+ * @param schemaVersion The overall schema version number of the request.
* @param userId Id of the calling user
* @param callback {@link IAppSearchResultCallback#onResult} will be called with an
* {@link AppSearchResult}<{@link Bundle}>, where the value are
@@ -52,8 +53,8 @@
in List<String> schemasNotDisplayedBySystem,
in Map<String, List<Bundle>> schemasPackageAccessibleBundles,
boolean forceOverride,
- in int userId,
in int schemaVersion,
+ in int userId,
in IAppSearchResultCallback callback);
/**
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index 1324451..5672bc7 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -297,11 +297,26 @@
}
/**
- * Sets the {@link Migrator}.
+ * Sets the {@link Migrator} associated with the given SchemaType.
+ *
+ * <p>The {@link Migrator} migrates all {@link GenericDocument}s under given schema type
+ * from the current version number stored in AppSearch to the final version set via {@link
+ * #setVersion}.
+ *
+ * <p>A {@link Migrator} will be invoked if the current version number stored in AppSearch
+ * is different from the final version set via {@link #setVersion} and {@link
+ * Migrator#shouldMigrate} returns {@code true}.
+ *
+ * <p>The target schema type of the output {@link GenericDocument} of {@link
+ * Migrator#onUpgrade} or {@link Migrator#onDowngrade} must exist in this {@link
+ * SetSchemaRequest}.
*
* @param schemaType The schema type to set migrator on.
- * @param migrator The migrator translate a document from it's old version to a new
- * incompatible version.
+ * @param migrator The migrator translates a document from its current version to the final
+ * version set via {@link #setVersion}.
+ * @see SetSchemaRequest.Builder#setVersion
+ * @see SetSchemaRequest.Builder#addSchemas
+ * @see AppSearchSession#setSchema
*/
@NonNull
@SuppressLint("MissingGetterMatchingBuilder") // Getter return plural objects.
@@ -313,10 +328,25 @@
}
/**
- * Sets {@link Migrator}s.
+ * Sets a Map of {@link Migrator}s.
*
- * @param migrators A {@link Map} of migrators that translate a document from its old
- * version to a new incompatible version.
+ * <p>The {@link Migrator} migrates all {@link GenericDocument}s under given schema type
+ * from the current version number stored in AppSearch to the final version set via {@link
+ * #setVersion}.
+ *
+ * <p>A {@link Migrator} will be invoked if the current version number stored in AppSearch
+ * is different from the final version set via {@link #setVersion} and {@link
+ * Migrator#shouldMigrate} returns {@code true}.
+ *
+ * <p>The target schema type of the output {@link GenericDocument} of {@link
+ * Migrator#onUpgrade} or {@link Migrator#onDowngrade} must exist in this {@link
+ * SetSchemaRequest}.
+ *
+ * @param migrators A {@link Map} of migrators that translate a document from it's current
+ * version to the final version set via {@link #setVersion}.
+ * @see SetSchemaRequest.Builder#setVersion
+ * @see SetSchemaRequest.Builder#addSchemas
+ * @see AppSearchSession#setSchema
*/
@NonNull
public Builder setMigrators(@NonNull Map<String, Migrator> migrators) {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
index c9473bd..32d7e043 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
@@ -20,12 +20,11 @@
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.Migrator;
+import android.app.appsearch.SetSchemaResponse;
import android.app.appsearch.exceptions.AppSearchException;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Log;
-import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@@ -36,84 +35,70 @@
* @hide
*/
public final class SchemaMigrationUtil {
- private static final String TAG = "AppSearchMigrateUtil";
-
private SchemaMigrationUtil() {}
- /**
- * Finds out which incompatible schema type won't be migrated by comparing its current and final
- * version number.
- */
+ /** Returns all active {@link Migrator}s that need to be triggered in this migration. */
@NonNull
- public static Set<String> getUnmigratedIncompatibleTypes(
- @NonNull Set<String> incompatibleSchemaTypes,
+ public static Map<String, Migrator> getActiveMigrators(
+ @NonNull Set<AppSearchSchema> existingSchemas,
@NonNull Map<String, Migrator> migrators,
- @NonNull Map<String, Integer> currentVersionMap,
- @NonNull Map<String, Integer> finalVersionMap)
- throws AppSearchException {
- Set<String> unmigratedSchemaTypes = new ArraySet<>();
- for (String unmigratedSchemaType : incompatibleSchemaTypes) {
- Integer currentVersion = currentVersionMap.get(unmigratedSchemaType);
- Integer finalVersion = finalVersionMap.get(unmigratedSchemaType);
- if (currentVersion == null) {
- // impossible, we have done something wrong.
- throw new AppSearchException(
- AppSearchResult.RESULT_UNKNOWN_ERROR,
- "Cannot find the current version number for schema type: "
- + unmigratedSchemaType);
- }
- if (finalVersion == null) {
- // The schema doesn't exist in the SetSchemaRequest.
- unmigratedSchemaTypes.add(unmigratedSchemaType);
- continue;
- }
- // we don't have migrator or won't trigger migration for this schema type.
- Migrator migrator = migrators.get(unmigratedSchemaType);
- if (migrator == null
- || !migrator.shouldMigrate(currentVersion, finalVersion)) {
- unmigratedSchemaTypes.add(unmigratedSchemaType);
+ int currentVersion,
+ int finalVersion) {
+ if (currentVersion == finalVersion) {
+ return Collections.emptyMap();
+ }
+ Set<String> existingTypes = new ArraySet<>(existingSchemas.size());
+ for (AppSearchSchema schema : existingSchemas) {
+ existingTypes.add(schema.getSchemaType());
+ }
+
+ Map<String, Migrator> activeMigrators = new ArrayMap<>();
+ for (Map.Entry<String, Migrator> entry : migrators.entrySet()) {
+ // The device contains the source type, and we should trigger migration for the type.
+ String schemaType = entry.getKey();
+ Migrator migrator = entry.getValue();
+ if (existingTypes.contains(schemaType)
+ && migrator.shouldMigrate(currentVersion, finalVersion)) {
+ activeMigrators.put(schemaType, migrator);
}
}
- return Collections.unmodifiableSet(unmigratedSchemaTypes);
+ return activeMigrators;
}
/**
- * Triggers upgrade or downgrade migration for the given schema type if its version stored in
- * AppSearch is different with the version in the request.
- *
- * @return {@code True} if we trigger the migration for the given type.
+ * Checks the setSchema() call won't delete any types or has incompatible types after all {@link
+ * Migrator} has been triggered..
*/
- public static boolean shouldTriggerMigration(
- @NonNull String schemaType,
- @NonNull Migrator migrator,
- @NonNull Map<String, Integer> currentVersionMap,
- @NonNull Map<String, Integer> finalVersionMap)
+ public static void checkDeletedAndIncompatibleAfterMigration(
+ @NonNull SetSchemaResponse setSchemaResponse, @NonNull Set<String> activeMigrators)
throws AppSearchException {
- Integer currentVersion = currentVersionMap.get(schemaType);
- Integer finalVersion = finalVersionMap.get(schemaType);
- if (currentVersion == null) {
- Log.d(TAG, "The SchemaType: " + schemaType + " not present in AppSearch.");
- return false;
- }
- if (finalVersion == null) {
- throw new AppSearchException(
- AppSearchResult.RESULT_INVALID_ARGUMENT,
- "Receive a migrator for schema type : "
- + schemaType
- + ", but the schema doesn't exist in the request.");
- }
- return migrator.shouldMigrate(currentVersion, finalVersion);
+ Set<String> unmigratedIncompatibleTypes =
+ new ArraySet<>(setSchemaResponse.getIncompatibleTypes());
+ unmigratedIncompatibleTypes.removeAll(activeMigrators);
+
+ Set<String> unmigratedDeletedTypes = new ArraySet<>(setSchemaResponse.getDeletedTypes());
+ unmigratedDeletedTypes.removeAll(activeMigrators);
+
+ // check if there are any unmigrated incompatible types or deleted types. If there
+ // are, we will getActiveMigratorsthrow an exception. That's the only case we
+ // swallowed in the AppSearchImpl#setSchema().
+ // Since the force override is false, the schema will not have been set if there are
+ // any incompatible or deleted types.
+ checkDeletedAndIncompatible(unmigratedDeletedTypes, unmigratedIncompatibleTypes);
}
- /** Builds a Map of SchemaType and its version of given set of {@link AppSearchSchema}. */
- //TODO(b/182620003) remove this method once support migrate to another type
- @NonNull
- public static Map<String, Integer> buildVersionMap(
- @NonNull Collection<AppSearchSchema> schemas, int version) {
- Map<String, Integer> currentVersionMap = new ArrayMap<>(schemas.size());
- for (AppSearchSchema currentSchema : schemas) {
- currentVersionMap.put(currentSchema.getSchemaType(), version);
+ /** Checks the setSchema() call won't delete any types or has incompatible types. */
+ public static void checkDeletedAndIncompatible(
+ @NonNull Set<String> deletedTypes, @NonNull Set<String> incompatibleTypes)
+ throws AppSearchException {
+ if (deletedTypes.size() > 0 || incompatibleTypes.size() > 0) {
+ String newMessage =
+ "Schema is incompatible."
+ + "\n Deleted types: "
+ + deletedTypes
+ + "\n Incompatible types: "
+ + incompatibleTypes;
+ throw new AppSearchException(AppSearchResult.RESULT_INVALID_SCHEMA, newMessage);
}
- return currentVersionMap;
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 877dacb..b46e85d 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.appsearch;
import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
+import static android.os.UserHandle.USER_NULL;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -34,7 +35,10 @@
import android.app.appsearch.SearchSpec;
import android.app.appsearch.SetSchemaResponse;
import android.app.appsearch.StorageInfo;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.Bundle;
@@ -46,6 +50,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -63,14 +68,27 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
/** TODO(b/142567528): add comments when implement this class */
public class AppSearchManagerService extends SystemService {
private static final String TAG = "AppSearchManagerService";
+ private final Context mContext;
private PackageManagerInternal mPackageManagerInternal;
private ImplInstanceManager mImplInstanceManager;
private UserManager mUserManager;
+ // Never call shutdownNow(). It will cancel the futures it's returned. And since
+ // Executor#execute won't return anything, we will hang forever waiting for the execution.
+ // AppSearch multi-thread execution is guarded by Read & Write Lock in AppSearchImpl, all
+ // mutate requests will need to gain write lock and query requests need to gain read lock.
+ private static final Executor EXECUTOR = new ThreadPoolExecutor(/*corePoolSize=*/1,
+ Runtime.getRuntime().availableProcessors(), /*keepAliveTime*/ 60L, TimeUnit.SECONDS,
+ new SynchronousQueue<Runnable>());
+
// Cache of unlocked user ids so we don't have to query UserManager service each time. The
// "locked" suffix refers to the fact that access to the field should be locked; unrelated to
// the unlocked status of user ids.
@@ -79,14 +97,60 @@
public AppSearchManagerService(Context context) {
super(context);
+ mContext = context;
}
@Override
public void onStart() {
publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mImplInstanceManager = ImplInstanceManager.getInstance(getContext());
- mUserManager = getContext().getSystemService(UserManager.class);
+ mImplInstanceManager = ImplInstanceManager.getInstance(mContext);
+ mUserManager = mContext.getSystemService(UserManager.class);
+ registerReceivers();
+ }
+
+ private void registerReceivers() {
+ mContext.registerReceiverAsUser(new UserActionReceiver(), UserHandle.ALL,
+ new IntentFilter(Intent.ACTION_USER_REMOVED), /*broadcastPermission=*/ null,
+ /*scheduler=*/ null);
+ }
+
+ private class UserActionReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
+ switch (intent.getAction()) {
+ case Intent.ACTION_USER_REMOVED:
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+ if (userId == USER_NULL) {
+ Slog.e(TAG, "userId is missing in the intent: " + intent);
+ return;
+ }
+ handleUserRemoved(userId);
+ break;
+ default:
+ Slog.e(TAG, "Received unknown intent: " + intent);
+ }
+ }
+ }
+
+ /**
+ * Handles user removed action.
+ *
+ * <p>Only need to clear the AppSearchImpl instance. The data of AppSearch is saved in the
+ * "credential encrypted" system directory of each user. That directory will be auto-deleted
+ * when a user is removed.
+ *
+ * @param userId The multi-user userId of the user that need to be removed.
+ *
+ * @see android.os.Environment#getDataSystemCeDirectory
+ */
+ private void handleUserRemoved(@UserIdInt int userId) {
+ try {
+ mImplInstanceManager.removeAppSearchImplForUser(userId);
+ Slog.i(TAG, "Removed AppSearchImpl instance for user: " + userId);
+ } catch (Throwable t) {
+ Slog.e(TAG, "Unable to remove data for user: " + userId, t);
+ }
}
@Override
@@ -105,8 +169,8 @@
@NonNull List<String> schemasNotDisplayedBySystem,
@NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles,
boolean forceOverride,
- @UserIdInt int userId,
int schemaVersion,
+ @UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(databaseName);
@@ -114,41 +178,41 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
- for (int i = 0; i < schemaBundles.size(); i++) {
- schemas.add(new AppSearchSchema(schemaBundles.get(i)));
- }
- Map<String, List<PackageIdentifier>> schemasPackageAccessible =
- new ArrayMap<>(schemasPackageAccessibleBundles.size());
- for (Map.Entry<String, List<Bundle>> entry :
- schemasPackageAccessibleBundles.entrySet()) {
- List<PackageIdentifier> packageIdentifiers =
- new ArrayList<>(entry.getValue().size());
- for (int i = 0; i < entry.getValue().size(); i++) {
- packageIdentifiers.add(new PackageIdentifier(entry.getValue().get(i)));
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
+ for (int i = 0; i < schemaBundles.size(); i++) {
+ schemas.add(new AppSearchSchema(schemaBundles.get(i)));
}
- schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
+ Map<String, List<PackageIdentifier>> schemasPackageAccessible =
+ new ArrayMap<>(schemasPackageAccessibleBundles.size());
+ for (Map.Entry<String, List<Bundle>> entry :
+ schemasPackageAccessibleBundles.entrySet()) {
+ List<PackageIdentifier> packageIdentifiers =
+ new ArrayList<>(entry.getValue().size());
+ for (int i = 0; i < entry.getValue().size(); i++) {
+ packageIdentifiers.add(
+ new PackageIdentifier(entry.getValue().get(i)));
+ }
+ schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
+ }
+ AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUserId);
+ SetSchemaResponse setSchemaResponse = impl.setSchema(
+ packageName,
+ databaseName,
+ schemas,
+ schemasNotDisplayedBySystem,
+ schemasPackageAccessible,
+ forceOverride,
+ schemaVersion);
+ invokeCallbackOnResult(callback,
+ AppSearchResult.newSuccessfulResult(setSchemaResponse.getBundle()));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
}
- AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUserId);
- SetSchemaResponse setSchemaResponse = impl.setSchema(
- packageName,
- databaseName,
- schemas,
- schemasNotDisplayedBySystem,
- schemasPackageAccessible,
- forceOverride,
- schemaVersion);
- invokeCallbackOnResult(callback,
- AppSearchResult.newSuccessfulResult(setSchemaResponse.getBundle()));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ });
}
@Override
@@ -162,20 +226,20 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- GetSchemaResponse response = impl.getSchema(packageName, databaseName);
- invokeCallbackOnResult(
- callback, AppSearchResult.newSuccessfulResult(response.getBundle()));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ GetSchemaResponse response = impl.getSchema(packageName, databaseName);
+ invokeCallbackOnResult(
+ callback,
+ AppSearchResult.newSuccessfulResult(response.getBundle()));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ }
+ });
}
@Override
@@ -189,19 +253,19 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- List<String> namespaces = impl.getNamespaces(packageName, databaseName);
- invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(namespaces));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ List<String> namespaces = impl.getNamespaces(packageName, databaseName);
+ invokeCallbackOnResult(callback,
+ AppSearchResult.newSuccessfulResult(namespaces));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ }
+ });
}
@Override
@@ -217,31 +281,30 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- AppSearchBatchResult.Builder<String, Void> resultBuilder =
- new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- for (int i = 0; i < documentBundles.size(); i++) {
- GenericDocument document = new GenericDocument(documentBundles.get(i));
- try {
- // TODO(b/173451571): reduce burden of binder thread by enqueue request onto
- // a separate thread.
- impl.putDocument(packageName, databaseName, document, /*logger=*/ null);
- resultBuilder.setSuccess(document.getUri(), /*result=*/ null);
- } catch (Throwable t) {
- resultBuilder.setResult(document.getUri(), throwableToFailedResult(t));
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchBatchResult.Builder<String, Void> resultBuilder =
+ new AppSearchBatchResult.Builder<>();
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ for (int i = 0; i < documentBundles.size(); i++) {
+ GenericDocument document = new GenericDocument(documentBundles.get(i));
+ try {
+ impl.putDocument(packageName, databaseName, document,
+ /*logger=*/ null);
+ resultBuilder.setSuccess(document.getUri(), /*result=*/ null);
+ } catch (Throwable t) {
+ resultBuilder.setResult(document.getUri(),
+ throwableToFailedResult(t));
+ }
}
+ invokeCallbackOnResult(callback, resultBuilder.build());
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
}
- invokeCallbackOnResult(callback, resultBuilder.build());
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ });
}
@Override
@@ -260,38 +323,36 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
- new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- for (int i = 0; i < uris.size(); i++) {
- String uri = uris.get(i);
- try {
- GenericDocument document =
- impl.getDocument(
- packageName,
- databaseName,
- namespace,
- uri,
- typePropertyPaths);
- resultBuilder.setSuccess(uri, document.getBundle());
- } catch (Throwable t) {
- resultBuilder.setResult(uri, throwableToFailedResult(t));
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
+ new AppSearchBatchResult.Builder<>();
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ for (int i = 0; i < uris.size(); i++) {
+ String uri = uris.get(i);
+ try {
+ GenericDocument document =
+ impl.getDocument(
+ packageName,
+ databaseName,
+ namespace,
+ uri,
+ typePropertyPaths);
+ resultBuilder.setSuccess(uri, document.getBundle());
+ } catch (Throwable t) {
+ resultBuilder.setResult(uri, throwableToFailedResult(t));
+ }
}
+ invokeCallbackOnResult(callback, resultBuilder.build());
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
}
- invokeCallbackOnResult(callback, resultBuilder.build());
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ });
}
- // TODO(sidchhabra): Do this in a threadpool.
@Override
public void query(
@NonNull String packageName,
@@ -307,26 +368,25 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- SearchResultPage searchResultPage =
- impl.query(
- packageName,
- databaseName,
- queryExpression,
- new SearchSpec(searchSpecBundle));
- invokeCallbackOnResult(
- callback,
- AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ SearchResultPage searchResultPage =
+ impl.query(
+ packageName,
+ databaseName,
+ queryExpression,
+ new SearchSpec(searchSpecBundle));
+ invokeCallbackOnResult(
+ callback,
+ AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ }
+ });
}
@Override
@@ -342,26 +402,25 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- SearchResultPage searchResultPage =
- impl.globalQuery(
- queryExpression,
- new SearchSpec(searchSpecBundle),
- packageName,
- callingUid);
- invokeCallbackOnResult(
- callback,
- AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ SearchResultPage searchResultPage =
+ impl.globalQuery(
+ queryExpression,
+ new SearchSpec(searchSpecBundle),
+ packageName,
+ callingUid);
+ invokeCallbackOnResult(
+ callback,
+ AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ }
+ });
}
@Override
@@ -372,39 +431,37 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
// TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
// opened it
- try {
- verifyUserUnlocked(callingUserId);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
- invokeCallbackOnResult(
- callback,
- AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
+ invokeCallbackOnResult(
+ callback,
+ AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ }
+ });
}
@Override
public void invalidateNextPageToken(long nextPageToken, @UserIdInt int userId) {
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- impl.invalidateNextPageToken(nextPageToken);
- } catch (Throwable t) {
- Log.e(TAG, "Unable to invalidate the query page token", t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ impl.invalidateNextPageToken(nextPageToken);
+ } catch (Throwable t) {
+ Log.e(TAG, "Unable to invalidate the query page token", t);
+ }
+ });
}
@Override
@@ -418,34 +475,34 @@
@NonNull IAppSearchResultCallback callback) {
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- // we don't need to append the file. The file is always brand new.
- try (DataOutputStream outputStream = new DataOutputStream(
- new FileOutputStream(fileDescriptor.getFileDescriptor()))) {
- SearchResultPage searchResultPage = impl.query(
- packageName,
- databaseName,
- queryExpression,
- new SearchSpec(searchSpecBundle));
- while (!searchResultPage.getResults().isEmpty()) {
- for (int i = 0; i < searchResultPage.getResults().size(); i++) {
- AppSearchMigrationHelper.writeBundleToOutputStream(
- outputStream, searchResultPage.getResults().get(i)
- .getGenericDocument().getBundle());
+ EXECUTOR.execute(() -> {
+ try {
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ // we don't need to append the file. The file is always brand new.
+ try (DataOutputStream outputStream = new DataOutputStream(
+ new FileOutputStream(fileDescriptor.getFileDescriptor()))) {
+ SearchResultPage searchResultPage = impl.query(
+ packageName,
+ databaseName,
+ queryExpression,
+ new SearchSpec(searchSpecBundle));
+ while (!searchResultPage.getResults().isEmpty()) {
+ for (int i = 0; i < searchResultPage.getResults().size(); i++) {
+ AppSearchMigrationHelper.writeBundleToOutputStream(
+ outputStream, searchResultPage.getResults().get(i)
+ .getGenericDocument().getBundle());
+ }
+ searchResultPage = impl.getNextPage(
+ searchResultPage.getNextPageToken());
}
- searchResultPage = impl.getNextPage(searchResultPage.getNextPageToken());
}
+ invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
}
- invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ });
}
@Override
@@ -457,46 +514,46 @@
@NonNull IAppSearchResultCallback callback) {
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
+ EXECUTOR.execute(() -> {
+ try {
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
- GenericDocument document;
- ArrayList<Bundle> migrationFailureBundles = new ArrayList<>();
- try (DataInputStream inputStream = new DataInputStream(
- new FileInputStream(fileDescriptor.getFileDescriptor()))) {
- while (true) {
- try {
- document = AppSearchMigrationHelper
- .readDocumentFromInputStream(inputStream);
- } catch (EOFException e) {
- // nothing wrong, we just finish the reading.
- break;
- }
- try {
- impl.putDocument(packageName, databaseName, document, /*logger=*/ null);
- } catch (Throwable t) {
- migrationFailureBundles.add(
- new SetSchemaResponse.MigrationFailure.Builder()
- .setNamespace(document.getNamespace())
- .setSchemaType(document.getSchemaType())
- .setUri(document.getUri())
- .setAppSearchResult(
- AppSearchResult.throwableToFailedResult(t))
- .build().getBundle());
+ GenericDocument document;
+ ArrayList<Bundle> migrationFailureBundles = new ArrayList<>();
+ try (DataInputStream inputStream = new DataInputStream(
+ new FileInputStream(fileDescriptor.getFileDescriptor()))) {
+ while (true) {
+ try {
+ document = AppSearchMigrationHelper
+ .readDocumentFromInputStream(inputStream);
+ } catch (EOFException e) {
+ // nothing wrong, we just finish the reading.
+ break;
+ }
+ try {
+ impl.putDocument(packageName, databaseName, document,
+ /*logger=*/ null);
+ } catch (Throwable t) {
+ migrationFailureBundles.add(
+ new SetSchemaResponse.MigrationFailure.Builder()
+ .setNamespace(document.getNamespace())
+ .setSchemaType(document.getSchemaType())
+ .setUri(document.getUri())
+ .setAppSearchResult(AppSearchResult
+ .throwableToFailedResult(t))
+ .build().getBundle());
+ }
}
}
+ impl.persistToDisk();
+ invokeCallbackOnResult(callback,
+ AppSearchResult.newSuccessfulResult(migrationFailureBundles));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
}
- impl.persistToDisk();
- invokeCallbackOnResult(callback,
- AppSearchResult.newSuccessfulResult(migrationFailureBundles));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ });
}
@Override
@@ -515,26 +572,25 @@
Objects.requireNonNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
- if (systemUsage) {
- // TODO(b/183031844): Validate that the call comes from the system
+ if (systemUsage) {
+ // TODO(b/183031844): Validate that the call comes from the system
+ }
+
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ impl.reportUsage(
+ packageName, databaseName, namespace, uri,
+ usageTimeMillis, systemUsage);
+ invokeCallbackOnResult(
+ callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
}
-
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- impl.reportUsage(
- packageName, databaseName, namespace, uri,
- usageTimeMillis, systemUsage);
- invokeCallbackOnResult(
- callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ });
}
@Override
@@ -551,29 +607,28 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- AppSearchBatchResult.Builder<String, Void> resultBuilder =
- new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- for (int i = 0; i < uris.size(); i++) {
- String uri = uris.get(i);
- try {
- impl.remove(packageName, databaseName, namespace, uri);
- resultBuilder.setSuccess(uri, /*result= */ null);
- } catch (Throwable t) {
- resultBuilder.setResult(uri, throwableToFailedResult(t));
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchBatchResult.Builder<String, Void> resultBuilder =
+ new AppSearchBatchResult.Builder<>();
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ for (int i = 0; i < uris.size(); i++) {
+ String uri = uris.get(i);
+ try {
+ impl.remove(packageName, databaseName, namespace, uri);
+ resultBuilder.setSuccess(uri, /*result= */ null);
+ } catch (Throwable t) {
+ resultBuilder.setResult(uri, throwableToFailedResult(t));
+ }
}
+ invokeCallbackOnResult(callback, resultBuilder.build());
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
}
- invokeCallbackOnResult(callback, resultBuilder.build());
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ });
}
@Override
@@ -591,23 +646,22 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- impl.removeByQuery(
- packageName,
- databaseName,
- queryExpression,
- new SearchSpec(searchSpecBundle));
- invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ impl.removeByQuery(
+ packageName,
+ databaseName,
+ queryExpression,
+ new SearchSpec(searchSpecBundle));
+ invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ }
+ });
}
@Override
@@ -621,38 +675,37 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- verifyCallingPackage(callingUid, packageName);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- StorageInfo storageInfo = impl.getStorageInfoForDatabase(packageName, databaseName);
- Bundle storageInfoBundle = storageInfo.getBundle();
- invokeCallbackOnResult(
- callback, AppSearchResult.newSuccessfulResult(storageInfoBundle));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ StorageInfo storageInfo = impl.getStorageInfoForDatabase(packageName,
+ databaseName);
+ Bundle storageInfoBundle = storageInfo.getBundle();
+ invokeCallbackOnResult(
+ callback, AppSearchResult.newSuccessfulResult(storageInfoBundle));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ }
+ });
}
@Override
public void persistToDisk(@UserIdInt int userId) {
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(callingUserId);
- impl.persistToDisk();
- } catch (Throwable t) {
- Log.e(TAG, "Unable to persist the data to disk", t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ AppSearchImpl impl =
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
+ impl.persistToDisk();
+ } catch (Throwable t) {
+ Log.e(TAG, "Unable to persist the data to disk", t);
+ }
+ });
}
@Override
@@ -660,16 +713,15 @@
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
int callingUserId = handleIncomingUser(userId, callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- verifyUserUnlocked(callingUserId);
- mImplInstanceManager.getOrCreateAppSearchImpl(getContext(), callingUserId);
- invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
- } catch (Throwable t) {
- invokeCallbackOnError(callback, t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
+ EXECUTOR.execute(() -> {
+ try {
+ verifyUserUnlocked(callingUserId);
+ mImplInstanceManager.getOrCreateAppSearchImpl(mContext, callingUserId);
+ invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ }
+ });
}
private void verifyUserUnlocked(int callingUserId) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index cacf880..e82dd9a 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -95,6 +95,23 @@
}
}
+ /**
+ * Remove an instance of {@link AppSearchImpl} for the given user.
+ *
+ * <p>This method should only be called if {@link AppSearchManagerService} receives an
+ * ACTION_USER_REMOVED, which the instance of given user should be removed.
+ *
+ * <p>If the user is removed, the "credential encrypted" system directory where icing lives will
+ * be auto-deleted. So we shouldn't worry about persist data or close the AppSearchImpl.
+ *
+ * @param userId The multi-user userId of the user that need to be removed.
+ */
+ @NonNull
+ public void removeAppSearchImplForUser(@UserIdInt int userId) {
+ synchronized (mInstancesLocked) {
+ mInstancesLocked.remove(userId);
+ }
+ }
/**
* Gets an instance of AppSearchImpl for the given user.
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING b/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
index ca5b884..38cd7a8 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
+++ b/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
@@ -4,6 +4,9 @@
"name": "CtsAppSearchTestCases"
},
{
+ "name": "CtsAppSearchHostTestCases"
+ },
+ {
"name": "FrameworksServicesTests",
"options": [
{
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 5b43ac3..5f8cbee 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -1127,6 +1127,40 @@
}
/**
+ * Remove all {@link AppSearchSchema}s and {@link GenericDocument}s under the given package.
+ *
+ * @param packageName The name of package to be removed.
+ * @throws AppSearchException if we cannot remove the data.
+ */
+ public void clearPackageData(@NonNull String packageName) throws AppSearchException {
+ mReadWriteLock.writeLock().lock();
+ try {
+ throwIfClosedLocked();
+
+ SchemaProto existingSchema = getSchemaProtoLocked();
+ SchemaProto.Builder newSchemaBuilder = SchemaProto.newBuilder();
+
+ String prefix = createPackagePrefix(packageName);
+ for (int i = 0; i < existingSchema.getTypesCount(); i++) {
+ if (!existingSchema.getTypes(i).getSchemaType().startsWith(prefix)) {
+ newSchemaBuilder.addTypes(existingSchema.getTypes(i));
+ }
+ }
+
+ // Apply schema, set force override to true to remove all schemas and documents under
+ // that package.
+ SetSchemaResultProto setSchemaResultProto =
+ mIcingSearchEngineLocked.setSchema(
+ newSchemaBuilder.build(), /*ignoreErrorsAndDeleteDocuments=*/ true);
+
+ // Determine whether it succeeded.
+ checkSuccess(setSchemaResultProto.getStatus());
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ }
+
+ /**
* Clears documents and schema across all packages and databaseNames.
*
* <p>This method also clear all data in {@link VisibilityStore}, an {@link
@@ -1624,7 +1658,12 @@
@NonNull
static String createPrefix(@NonNull String packageName, @NonNull String databaseName) {
- return packageName + PACKAGE_DELIMITER + databaseName + DATABASE_DELIMITER;
+ return createPackagePrefix(packageName) + databaseName + DATABASE_DELIMITER;
+ }
+
+ @NonNull
+ private static String createPackagePrefix(@NonNull String packageName) {
+ return packageName + PACKAGE_DELIMITER;
}
/**
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 29bd541..e46c147 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-Ibbd3a92ad091f6911de652e2ba7e44f555a70a72
+I925ec12f4901c7759976c344ba3428210aada8ad
diff --git a/apex/appsearch/testing/Android.bp b/apex/appsearch/testing/Android.bp
index 3c5082e..2518394 100644
--- a/apex/appsearch/testing/Android.bp
+++ b/apex/appsearch/testing/Android.bp
@@ -31,6 +31,7 @@
"truth-prebuilt",
],
visibility: [
+ "//cts/hostsidetests/appsearch",
"//cts/tests/appsearch",
"//vendor:__subpackages__",
],
diff --git a/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl b/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl
index 2f21ce3..a10cbbe 100644
--- a/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl
+++ b/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl
@@ -42,4 +42,5 @@
AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
long currentNetworkTimeMillis();
boolean canScheduleExactAlarms();
+ int getConfigVersion();
}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index 60f6475..e1bfde1 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -64,6 +64,16 @@
*/
public static final int REASON_RESTRICTED_BUCKET =
JobProtoEnums.STOP_REASON_RESTRICTED_BUCKET; // 6.
+ /**
+ * The app was uninstalled.
+ * @hide
+ */
+ public static final int DEBUG_REASON_UNINSTALL = 7;
+ /**
+ * The app's data was cleared.
+ * @hide
+ */
+ public static final int DEBUG_REASON_DATA_CLEARED = 8;
/**
* All the stop reason codes. This should be regarded as an immutable array at runtime.
@@ -187,8 +197,8 @@
*/
public static final int STOP_REASON_APP_STANDBY = 12;
/**
- * The user stopped the job. This can happen either through force-stop, or via adb shell
- * commands.
+ * The user stopped the job. This can happen either through force-stop, adb shell commands,
+ * or uninstalling.
*/
public static final int STOP_REASON_USER = 13;
/** The system is doing some processing that requires stopping this job. */
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 6ae91a0..6d2bd47 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -37,7 +37,8 @@
/**
* Cancel the jobs for a given uid (e.g. when app data is cleared)
*/
- void cancelJobsForUid(int uid, @JobParameters.StopReason int reason, String debugReason);
+ void cancelJobsForUid(int uid, @JobParameters.StopReason int reason, int debugReasonCode,
+ String debugReason);
/**
* These are for activity manager to communicate to use what is currently performing backups.
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 901daa7..08e1a95 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -538,6 +538,7 @@
public long PRIORITY_ALARM_DELAY = DEFAULT_PRIORITY_ALARM_DELAY;
private long mLastAllowWhileIdleWhitelistDuration = -1;
+ private int mVersion = 0;
Constants() {
updateAllowWhileIdleWhitelistDurationLocked();
@@ -546,6 +547,12 @@
}
}
+ public int getVersion() {
+ synchronized (mLock) {
+ return mVersion;
+ }
+ }
+
public void start() {
mInjector.registerDeviceConfigListener(this);
onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ALARM_MANAGER));
@@ -568,6 +575,7 @@
public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
boolean standbyQuotaUpdated = false;
synchronized (mLock) {
+ mVersion++;
for (String name : properties.getKeyset()) {
if (name == null) {
continue;
@@ -749,6 +757,9 @@
pw.increaseIndent();
+ pw.print("version", mVersion);
+ pw.println();
+
pw.print(KEY_MIN_FUTURITY);
pw.print("=");
TimeUtils.formatDuration(MIN_FUTURITY, pw);
@@ -2219,6 +2230,13 @@
}
@Override
+ public int getConfigVersion() {
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.DUMP,
+ "getConfigVersion");
+ return mConstants.getVersion();
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
@@ -4698,6 +4716,10 @@
final String tz = getNextArgRequired();
getBinderService().setTimeZone(tz);
return 0;
+ case "get-config-version":
+ final int version = getBinderService().getConfigVersion();
+ pw.println(version);
+ return 0;
default:
return handleDefaultCommands(cmd);
}
@@ -4718,6 +4740,10 @@
pw.println(" since the Epoch.");
pw.println(" set-timezone TZ");
pw.println(" Set the system timezone to TZ where TZ is an Olson id.");
+ pw.println(" get-config-version");
+ pw.println(" Returns an integer denoting the version of device_config keys the"
+ + " service is sync'ed to. As long as this returns the same version, the values"
+ + " of the config are guaranteed to remain the same.");
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 41b342c..8b9eca6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -747,12 +747,14 @@
+ " in user " + userId);
}
synchronized (mLock) {
- // By the time we get here, the process should have
- // already been stopped, so the app wouldn't get the
- // stop reason, so just put USER instead of UNINSTALL
- // or DISABLED.
+ // There's no guarantee that the process has been
+ // stopped by the time we get here, but since this is
+ // a user-initiated action, it should be fine to just
+ // put USER instead of UNINSTALL or DISABLED.
cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
- JobParameters.STOP_REASON_USER, "app disabled");
+ JobParameters.STOP_REASON_USER,
+ JobParameters.DEBUG_REASON_UNINSTALL,
+ "app disabled");
}
}
} catch (RemoteException|IllegalArgumentException e) {
@@ -783,25 +785,22 @@
} else {
Slog.w(TAG, "PACKAGE_CHANGED for " + pkgName + " / uid " + pkgUid);
}
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- // If this is an outright uninstall rather than the first half of an
- // app update sequence, cancel the jobs associated with the app.
- if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
- if (DEBUG) {
- Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+ } else if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
+ int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (DEBUG) {
+ Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+ }
+ synchronized (mLock) {
+ // There's no guarantee that the process has been stopped by the time we
+ // get here, but since this is generally a user-initiated action, it should
+ // be fine to just put USER instead of UNINSTALL or DISABLED.
+ cancelJobsForPackageAndUidLocked(pkgName, uidRemoved,
+ JobParameters.STOP_REASON_USER,
+ JobParameters.DEBUG_REASON_UNINSTALL, "app uninstalled");
+ for (int c = 0; c < mControllers.size(); ++c) {
+ mControllers.get(c).onAppRemovedLocked(pkgName, pkgUid);
}
- // By the time we get here, the process should have already
- // been stopped, so the app wouldn't get the stop reason,
- // so just put USER instead of UNINSTALL or DISABLED.
- synchronized (mLock) {
- cancelJobsForPackageAndUidLocked(pkgName, uidRemoved,
- JobParameters.STOP_REASON_USER, "app uninstalled");
- for (int c = 0; c < mControllers.size(); ++c) {
- mControllers.get(c).onAppRemovedLocked(pkgName, pkgUid);
- }
- mDebuggableApps.remove(pkgName);
- }
+ mDebuggableApps.remove(pkgName);
}
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
@@ -849,7 +848,8 @@
}
synchronized (mLock) {
cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
- JobParameters.STOP_REASON_USER, "app force stopped");
+ JobParameters.STOP_REASON_USER, JobParameters.REASON_CANCELED,
+ "app force stopped");
}
}
}
@@ -1038,7 +1038,7 @@
if (toCancel != null) {
// Implicitly replaces the existing job record with the new instance
cancelJobImplLocked(toCancel, jobStatus, JobParameters.STOP_REASON_CANCELLED_BY_APP,
- "job rescheduled by app");
+ JobParameters.REASON_CANCELED, "job rescheduled by app");
} else {
startTrackingJobLocked(jobStatus, null);
}
@@ -1115,10 +1115,11 @@
final List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
for (int i = 0; i < jobsForUser.size(); i++) {
JobStatus toRemove = jobsForUser.get(i);
- // By the time we get here, the process should have already been stopped, so the
- // app wouldn't get the stop reason, so just put USER instead of UNINSTALL.
+ // There's no guarantee that the process has been stopped by the time we get here,
+ // but since this is a user-initiated action, it should be fine to just put USER
+ // instead of UNINSTALL or DISABLED.
cancelJobImplLocked(toRemove, null, JobParameters.STOP_REASON_USER,
- "user removed");
+ JobParameters.DEBUG_REASON_UNINSTALL, "user removed");
}
}
@@ -1130,7 +1131,7 @@
}
private void cancelJobsForPackageAndUidLocked(String pkgName, int uid,
- @JobParameters.StopReason int reason, String debugReason) {
+ @JobParameters.StopReason int reason, int debugReasonCode, String debugReason) {
if ("android".equals(pkgName)) {
Slog.wtfStack(TAG, "Can't cancel all jobs for system package");
return;
@@ -1139,7 +1140,7 @@
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
final JobStatus job = jobsForUid.get(i);
if (job.getSourcePackageName().equals(pkgName)) {
- cancelJobImplLocked(job, null, reason, debugReason);
+ cancelJobImplLocked(job, null, reason, debugReasonCode, debugReason);
}
}
}
@@ -1152,7 +1153,7 @@
* @param uid Uid to check against for removal of a job.
*/
public boolean cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
- String debugReason) {
+ int debugReasonCode, String debugReason) {
if (uid == Process.SYSTEM_UID) {
Slog.wtfStack(TAG, "Can't cancel all jobs for system uid");
return false;
@@ -1161,9 +1162,9 @@
boolean jobsCanceled = false;
synchronized (mLock) {
final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
- for (int i=0; i<jobsForUid.size(); i++) {
+ for (int i = 0; i < jobsForUid.size(); i++) {
JobStatus toRemove = jobsForUid.get(i);
- cancelJobImplLocked(toRemove, null, reason, debugReason);
+ cancelJobImplLocked(toRemove, null, reason, debugReasonCode, debugReason);
jobsCanceled = true;
}
}
@@ -1185,8 +1186,9 @@
toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
if (toCancel != null) {
cancelJobImplLocked(toCancel, null, reason,
+ JobParameters.REASON_CANCELED,
"cancel() called by app, callingUid=" + callingUid
- + " uid=" + uid + " jobId=" + jobId);
+ + " uid=" + uid + " jobId=" + jobId);
}
return (toCancel != null);
}
@@ -1199,7 +1201,7 @@
* currently scheduled jobs.
*/
private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob,
- @JobParameters.StopReason int reason, String debugReason) {
+ @JobParameters.StopReason int reason, int debugReasonCode, String debugReason) {
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
cancelled.unprepareLocked();
stopTrackingJobLocked(cancelled, incomingJob, true /* writeBack */);
@@ -1208,8 +1210,7 @@
mJobPackageTracker.noteNonpending(cancelled);
}
// Cancel if running.
- stopJobOnServiceContextLocked(cancelled, reason, JobParameters.REASON_CANCELED,
- debugReason);
+ stopJobOnServiceContextLocked(cancelled, reason, debugReasonCode, debugReason);
// If this is a replacement, bring in the new version of the job
if (incomingJob != null) {
if (DEBUG) Slog.i(TAG, "Tracking replacement job " + incomingJob.toShortString());
@@ -1459,7 +1460,7 @@
Slog.v(TAG, " replacing " + oldJob + " with " + newJob);
}
cancelJobImplLocked(oldJob, newJob, JobParameters.STOP_REASON_SYSTEM_PROCESSING,
- "deferred rtc calculation");
+ JobParameters.REASON_CANCELED, "deferred rtc calculation");
}
}
};
@@ -1482,7 +1483,7 @@
// Register br for package removals and user removals.
final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
@@ -1786,15 +1787,26 @@
* @param needsReschedule Whether the implementing class should reschedule this job.
*/
@Override
- public void onJobCompletedLocked(JobStatus jobStatus, int stopReason, boolean needsReschedule) {
+ public void onJobCompletedLocked(JobStatus jobStatus, int debugStopReason,
+ boolean needsReschedule) {
if (DEBUG) {
- Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
+ Slog.d(TAG, "Completed " + jobStatus + ", reason=" + debugStopReason
+ + ", reschedule=" + needsReschedule);
}
mLastCompletedJobs[mLastCompletedJobIndex] = jobStatus;
mLastCompletedJobTimeElapsed[mLastCompletedJobIndex] = sElapsedRealtimeClock.millis();
mLastCompletedJobIndex = (mLastCompletedJobIndex + 1) % NUM_COMPLETED_JOB_HISTORY;
+ if (debugStopReason == JobParameters.DEBUG_REASON_UNINSTALL
+ || debugStopReason == JobParameters.DEBUG_REASON_DATA_CLEARED) {
+ // The job should have already been cleared from the rest of the JS tracking. No need
+ // to go through all that flow again.
+ jobStatus.unprepareLocked();
+ reportActiveLocked();
+ return;
+ }
+
// Intentionally not checking expedited job quota here. An app can't find out if it's run
// out of quota when it asks JS to reschedule an expedited job. Instead, the rescheduled
// EJ will just be demoted to a regular job if the app has no EJ quota left.
@@ -1805,8 +1817,8 @@
final JobStatus rescheduledJob = needsReschedule
? getRescheduleJobForFailureLocked(jobStatus) : null;
if (rescheduledJob != null
- && (stopReason == JobParameters.REASON_TIMEOUT
- || stopReason == JobParameters.REASON_PREEMPT)) {
+ && (debugStopReason == JobParameters.REASON_TIMEOUT
+ || debugStopReason == JobParameters.REASON_PREEMPT)) {
rescheduledJob.disallowRunInBatterySaverAndDoze();
}
@@ -1911,6 +1923,7 @@
break;
case MSG_STOP_JOB:
cancelJobImplLocked((JobStatus) message.obj, null, message.arg1,
+ JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
"app no longer allowed to run");
break;
@@ -1927,7 +1940,7 @@
if (disabled) {
cancelJobsForUid(uid,
JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
- "uid gone");
+ JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED, "uid gone");
}
synchronized (mLock) {
mDeviceIdleJobsController.setUidActiveLocked(uid, false);
@@ -1947,7 +1960,7 @@
if (disabled) {
cancelJobsForUid(uid,
JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
- "app uid idle");
+ JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED, "app uid idle");
}
synchronized (mLock) {
mDeviceIdleJobsController.setUidActiveLocked(uid, false);
@@ -2409,8 +2422,8 @@
@Override
public void cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
- String debugReason) {
- JobSchedulerService.this.cancelJobsForUid(uid, reason, debugReason);
+ int debugReasonCode, String debugReason) {
+ JobSchedulerService.this.cancelJobsForUid(uid, reason, debugReasonCode, debugReason);
}
@Override
@@ -2749,6 +2762,7 @@
try {
JobSchedulerService.this.cancelJobsForUid(uid,
JobParameters.STOP_REASON_CANCELLED_BY_APP,
+ JobParameters.REASON_CANCELED,
"cancelAll() called by app, callingUid=" + uid);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2969,7 +2983,7 @@
if (!hasJobId) {
pw.println("Canceling all jobs for " + pkgName + " in user " + userId);
if (!cancelJobsForUid(pkgUid, JobParameters.STOP_REASON_USER,
- "cancel shell command for package")) {
+ JobParameters.REASON_CANCELED, "cancel shell command for package")) {
pw.println("No matching jobs found.");
}
} else {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index f30b75c..b4e167a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -244,7 +244,10 @@
getUidStats(jobStatus.getSourceUid(), jobStatus.getSourcePackageName(), true);
uidStats.numReadyWithConnectivity--;
if (jobStatus.madeActive != 0) {
- uidStats.numRunning--;
+ // numRunning would be 0 if the UidStats object didn't exist before this method
+ // was called. getUidStats() handles logging, so just make sure we don't save a
+ // negative value.
+ uidStats.numRunning = Math.max(0, uidStats.numRunning - 1);
}
maybeRevokeStandbyExceptionLocked(jobStatus);
postAdjustCallbacks();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 91189e4..158a0b9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -735,6 +735,7 @@
mTempAllowlistCache.delete(uid);
mTempAllowlistGraceCache.delete(uid);
mTopAppCache.delete(uid);
+ mTopAppTrackers.delete(uid);
mTopAppGraceCache.delete(uid);
}
diff --git a/apex/media/framework/TEST_MAPPING b/apex/media/framework/TEST_MAPPING
index 70c9087..3d21914 100644
--- a/apex/media/framework/TEST_MAPPING
+++ b/apex/media/framework/TEST_MAPPING
@@ -4,7 +4,7 @@
"name": "CtsMediaParserTestCases"
},
{
- "name": "CtsMediaParserHostSideTestCases"
+ "name": "CtsMediaParserHostTestCases"
}
]
}
diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt
index 7df0b4b..ce68447 100644
--- a/apex/media/framework/api/system-current.txt
+++ b/apex/media/framework/api/system-current.txt
@@ -25,7 +25,7 @@
}
public static final class MediaTranscodeManager.TranscodingSession {
- method public void addClientUid(int);
+ method public boolean addClientUid(int);
method public void cancel();
method @NonNull public java.util.List<java.lang.Integer> getClientUids();
method public int getErrorCode();
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index a7de602..d7e9609 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -1361,8 +1361,6 @@
private @TranscodingSessionErrorCode int mErrorCode = ERROR_NONE;
@GuardedBy("mLock")
private boolean mHasRetried = false;
- @GuardedBy("mLock")
- private @NonNull List<Integer> mClientUidList = new ArrayList<>();
// The original request that associated with this session.
private final TranscodingRequest mRequest;
@@ -1381,7 +1379,6 @@
mListenerExecutor = executor;
mListener = listener;
mRequest = request;
- mClientUidList.add(request.getClientUid());
}
/**
@@ -1532,17 +1529,31 @@
* Only privilege caller with android.permission.WRITE_MEDIA_STORAGE could add the
* uid. Note that the permission check happens on the service side upon starting the
* transcoding. If the client does not have the permission, the transcoding will fail.
+ * @param uid the additional client uid to be added.
+ * @return true if successfully added, false otherwise.
*/
- public void addClientUid(int uid) {
+ public boolean addClientUid(int uid) {
if (uid < 0) {
throw new IllegalArgumentException("Invalid Uid");
}
- synchronized (mLock) {
- if (!mClientUidList.contains(uid)) {
- // see ag/14023202 for implementation
- mClientUidList.add(uid);
- }
+
+ // Get the client interface.
+ ITranscodingClient client = mManager.getTranscodingClient();
+ if (client == null) {
+ Log.e(TAG, "Service is dead...");
+ return false;
}
+
+ try {
+ if (!client.addClientUid(mSessionId, uid)) {
+ Log.e(TAG, "Failed to add client uid");
+ return false;
+ }
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to get client uids due to " + ex);
+ return false;
+ }
+ return true;
}
/**
@@ -1551,9 +1562,25 @@
*/
@NonNull
public List<Integer> getClientUids() {
- synchronized (mLock) {
- return mClientUidList;
+ List<Integer> uidList = new ArrayList<Integer>();
+
+ // Get the client interface.
+ ITranscodingClient client = mManager.getTranscodingClient();
+ if (client == null) {
+ Log.e(TAG, "Service is dead...");
+ return uidList;
}
+
+ try {
+ int[] clientUids = client.getClientUids(mSessionId);
+ for (int i : clientUids) {
+ uidList.add(i);
+ }
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to get client uids due to " + ex);
+ }
+
+ return uidList;
}
/**
diff --git a/api/dump_api_shas.sh b/api/dump_api_shas.sh
new file mode 100755
index 0000000..c023b31
--- /dev/null
+++ b/api/dump_api_shas.sh
@@ -0,0 +1,56 @@
+#!/bin/bash -e
+# This script dumps the git SHAs of all commits inside api tracking directories.
+# It can used by tools wanting to track API changes, and the primary original
+# purpose is to verify verify all API change SHAs have been tracked by the
+# server-side API-council tools.
+#
+# The only argument is used to specify a git commit range to filter by.
+#
+# Example invocation (API changes between O and P):
+# frameworks/base/api/dump_api_shas.sh origin/oreo-dev..origin/pie-dev
+
+set -o pipefail
+
+eecho() { echo $@ >&2 ; }
+
+if [[ $1 == *..* ]]; then
+ exclude=${1/..*}
+ include=${1/*..}
+else
+ eecho No range or invalid range specified, defaulting to all commits from HEAD.
+ exclude=
+ include=HEAD
+fi
+
+eecho -n building queryview...
+{ source build/envsetup.sh && lunch aosp_arm && m queryview; } >/dev/null 2>&1 \
+ || { eecho failed; exit 1; }
+eecho "done"
+
+# This finds the directories where the dependant java_sdk_libs are defined
+bpdirs=$(
+ bazel query --config=queryview --output=package \
+ 'kind(java_sdk_library, deps(//frameworks/base/api/..., 1))' 2>/dev/null
+ echo frameworks/base/core/api # Not a java_sdk_library.
+ echo frameworks/base/services/api # Not a java_sdk_library.
+)
+
+# Find relevant api subdirectories
+apidirs=$(
+ find $bpdirs -type f -name '*current.txt' -path '*/api/*' \
+ | xargs realpath --relative-to=$(pwd) | xargs dirname | sort | uniq
+)
+
+# Dump sorted SHAs of commits in these directories
+{ for d in $apidirs; do
+ ( cd $d
+ eecho inspecting $d
+ exclude_arg=$(test -n "$exclude" && {
+ git rev-parse -q --verify $exclude > /dev/null && echo "--not $exclude" \
+ || eecho "$d has no revision $exclude, including all commits"; } || true)
+ for f in $(find . -name '*current.txt'); do
+ git --no-pager log --pretty=format:%H --no-merges --follow $include $exclude_arg -- $f
+ echo # No trailing newline with --no-pager
+ done
+ )
+done; } | sort | uniq
diff --git a/config/hiddenapi-force-blocked.txt b/boot/hiddenapi/hiddenapi-force-blocked.txt
similarity index 100%
rename from config/hiddenapi-force-blocked.txt
rename to boot/hiddenapi/hiddenapi-force-blocked.txt
diff --git a/config/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
similarity index 100%
rename from config/hiddenapi-max-target-o.txt
rename to boot/hiddenapi/hiddenapi-max-target-o.txt
diff --git a/config/hiddenapi-max-target-p.txt b/boot/hiddenapi/hiddenapi-max-target-p.txt
similarity index 100%
rename from config/hiddenapi-max-target-p.txt
rename to boot/hiddenapi/hiddenapi-max-target-p.txt
diff --git a/config/hiddenapi-max-target-q.txt b/boot/hiddenapi/hiddenapi-max-target-q.txt
similarity index 100%
rename from config/hiddenapi-max-target-q.txt
rename to boot/hiddenapi/hiddenapi-max-target-q.txt
diff --git a/config/hiddenapi-max-target-r-loprio.txt b/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
similarity index 100%
rename from config/hiddenapi-max-target-r-loprio.txt
rename to boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
diff --git a/config/hiddenapi-unsupported-packages.txt b/boot/hiddenapi/hiddenapi-unsupported-packages.txt
similarity index 100%
rename from config/hiddenapi-unsupported-packages.txt
rename to boot/hiddenapi/hiddenapi-unsupported-packages.txt
diff --git a/config/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt
similarity index 100%
rename from config/hiddenapi-unsupported.txt
rename to boot/hiddenapi/hiddenapi-unsupported.txt
diff --git a/core/api/current.txt b/core/api/current.txt
index bdd0f17..8a642e6 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1182,7 +1182,7 @@
field public static final int reqNavigation = 16843306; // 0x101022a
field public static final int reqTouchScreen = 16843303; // 0x1010227
field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
- field public static final int requestOptimizedExternalStorageAccess;
+ field public static final int requestRawExternalStorageAccess;
field public static final int requireDeviceScreenOn;
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
@@ -8552,8 +8552,8 @@
ctor public AppWidgetProviderInfo(android.os.Parcel);
method public android.appwidget.AppWidgetProviderInfo clone();
method public int describeContents();
+ method @NonNull public android.content.pm.ActivityInfo getActivityInfo();
method public final android.os.UserHandle getProfile();
- method @NonNull public android.content.pm.ActivityInfo getProviderInfo();
method @Nullable public final CharSequence loadDescription(@NonNull android.content.Context);
method public final android.graphics.drawable.Drawable loadIcon(@NonNull android.content.Context, int);
method public final String loadLabel(android.content.pm.PackageManager);
@@ -18826,10 +18826,10 @@
public final class DeviceProductInfo implements android.os.Parcelable {
method public int describeContents();
method public int getConnectionToSinkType();
- method public int getManufactureWeek();
- method public int getManufactureYear();
+ method @IntRange(from=0xffffffff, to=53) public int getManufactureWeek();
+ method @IntRange(from=0xffffffff) public int getManufactureYear();
method @NonNull public String getManufacturerPnpId();
- method public int getModelYear();
+ method @IntRange(from=0xffffffff) public int getModelYear();
method @Nullable public String getName();
method @NonNull public String getProductId();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -20332,6 +20332,7 @@
field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
+ field public static final int ENCODING_DTS_UHD = 27; // 0x1b
field public static final int ENCODING_E_AC3 = 6; // 0x6
field public static final int ENCODING_E_AC3_JOC = 18; // 0x12
field public static final int ENCODING_IEC61937 = 13; // 0xd
@@ -35478,8 +35479,8 @@
public static final class SimPhonebookContract.SimRecords {
method @NonNull public static android.net.Uri getContentUri(int, int);
- method @WorkerThread public static int getEncodedNameLength(@NonNull android.content.ContentResolver, @NonNull String);
- method @NonNull public static android.net.Uri getItemUri(int, int, int);
+ method @IntRange(from=0) @WorkerThread public static int getEncodedNameLength(@NonNull android.content.ContentResolver, @NonNull String);
+ method @NonNull public static android.net.Uri getItemUri(int, int, @IntRange(from=1) int);
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sim-contact_v2";
field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-contact_v2";
field public static final String ELEMENTARY_FILE_TYPE = "elementary_file_type";
@@ -41921,42 +41922,42 @@
@Deprecated public class PhoneStateListener {
ctor @Deprecated public PhoneStateListener();
ctor @Deprecated public PhoneStateListener(@NonNull java.util.concurrent.Executor);
- method @Deprecated public void onActiveDataSubscriptionIdChanged(int);
- method @Deprecated public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onActiveDataSubscriptionIdChanged(int);
+ method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
- method @Deprecated public void onCallForwardingIndicatorChanged(boolean);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onCallForwardingIndicatorChanged(boolean);
method @Deprecated @RequiresPermission(value=android.Manifest.permission.READ_PHONE_STATE, conditional=true) public void onCallStateChanged(int, String);
- method @Deprecated public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
- method @Deprecated public void onCellLocationChanged(android.telephony.CellLocation);
+ method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellLocationChanged(android.telephony.CellLocation);
method @Deprecated public void onDataActivity(int);
method @Deprecated public void onDataConnectionStateChanged(int);
method @Deprecated public void onDataConnectionStateChanged(int, int);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
- method @Deprecated public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
- method @Deprecated public void onMessageWaitingIndicatorChanged(boolean);
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
- method @Deprecated public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onMessageWaitingIndicatorChanged(boolean);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
+ method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
method @Deprecated public void onServiceStateChanged(android.telephony.ServiceState);
method @Deprecated public void onSignalStrengthChanged(int);
method @Deprecated public void onSignalStrengthsChanged(android.telephony.SignalStrength);
method @Deprecated public void onUserMobileDataStateChanged(boolean);
- field @Deprecated public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
- field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
+ field @Deprecated @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
- field @Deprecated public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
field @Deprecated public static final int LISTEN_CALL_STATE = 32; // 0x20
- field @Deprecated public static final int LISTEN_CELL_INFO = 1024; // 0x400
- field @Deprecated public static final int LISTEN_CELL_LOCATION = 16; // 0x10
+ field @Deprecated @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int LISTEN_CELL_INFO = 1024; // 0x400
+ field @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int LISTEN_CELL_LOCATION = 16; // 0x10
field @Deprecated public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80
field @Deprecated public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40
field @Deprecated public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000
- field @Deprecated public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
- field @Deprecated public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
field @Deprecated public static final int LISTEN_NONE = 0; // 0x0
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
- field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
+ field @Deprecated @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
field @Deprecated public static final int LISTEN_SERVICE_STATE = 1; // 0x1
field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2
field @Deprecated public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
@@ -42455,10 +42456,6 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onActiveDataSubscriptionIdChanged(int);
}
- public static interface TelephonyCallback.AlwaysReportedSignalStrengthListener {
- method @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
- }
-
public static interface TelephonyCallback.BarringInfoListener {
method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
}
@@ -42480,7 +42477,7 @@
}
public static interface TelephonyCallback.CellInfoListener {
- method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellInfoChanged(@NonNull java.util.List<android.telephony.CellInfo>);
+ method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onCellInfoChanged(@NonNull java.util.List<android.telephony.CellInfo>);
}
public static interface TelephonyCallback.CellLocationListener {
@@ -42488,15 +42485,15 @@
}
public static interface TelephonyCallback.DataActivationStateListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivationStateChanged(int);
+ method public void onDataActivationStateChanged(int);
}
public static interface TelephonyCallback.DataActivityListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivity(int);
+ method public void onDataActivity(int);
}
public static interface TelephonyCallback.DataConnectionStateListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataConnectionStateChanged(int, int);
+ method public void onDataConnectionStateChanged(int, int);
}
public static interface TelephonyCallback.DisplayInfoListener {
@@ -42528,15 +42525,15 @@
}
public static interface TelephonyCallback.ServiceStateListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onServiceStateChanged(@NonNull android.telephony.ServiceState);
+ method public void onServiceStateChanged(@NonNull android.telephony.ServiceState);
}
public static interface TelephonyCallback.SignalStrengthsListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
+ method public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
}
public static interface TelephonyCallback.UserMobileDataStateListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onUserMobileDataStateChanged(boolean);
+ method public void onUserMobileDataStateChanged(boolean);
}
public final class TelephonyDisplayInfo implements android.os.Parcelable {
@@ -50825,6 +50822,7 @@
field @NonNull public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
field public static final String EXTRA_DATA_RENDERING_INFO_KEY = "android.view.accessibility.extra.DATA_RENDERING_INFO_KEY";
field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ field public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; // 0x4e20
field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
@@ -52860,7 +52858,7 @@
method @NonNull public android.view.translation.TranslationResponse.Builder setFinalResponse(boolean);
method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int, @NonNull android.view.translation.TranslationResponseValue);
method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationResponseValues(@NonNull android.util.SparseArray<android.view.translation.TranslationResponseValue>);
- method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationStatus(int);
+ method @Deprecated @NonNull public android.view.translation.TranslationResponse.Builder setTranslationStatus(int);
method @NonNull public android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int, @NonNull android.view.translation.ViewTranslationResponse);
method @NonNull public android.view.translation.TranslationResponse.Builder setViewTranslationResponses(@NonNull android.util.SparseArray<android.view.translation.ViewTranslationResponse>);
}
@@ -55495,6 +55493,7 @@
public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable {
ctor public RemoteViews(String, int);
+ ctor public RemoteViews(@NonNull String, @LayoutRes int, @IdRes int);
ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews);
ctor public RemoteViews(@NonNull java.util.Map<android.util.SizeF,android.widget.RemoteViews>);
ctor public RemoteViews(android.widget.RemoteViews);
@@ -55568,7 +55567,6 @@
method public void setTextViewText(@IdRes int, CharSequence);
method public void setTextViewTextSize(@IdRes int, int, float);
method public void setUri(@IdRes int, String, android.net.Uri);
- method public void setViewId(@IdRes int);
method public void setViewLayoutHeight(@IdRes int, float, int);
method public void setViewLayoutHeightDimen(@IdRes int, @DimenRes int);
method public void setViewLayoutMargin(@IdRes int, int, float, int);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 869d790..5379468 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -65,10 +65,6 @@
field public static final String TEST_NETWORK_SERVICE = "test_network";
}
- public class Intent implements java.lang.Cloneable android.os.Parcelable {
- field public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
- }
-
}
package android.content.pm {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 930c298..0772478 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -28,6 +28,7 @@
field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
+ field public static final String ASSOCIATE_COMPANION_DEVICES = "android.permission.ASSOCIATE_COMPANION_DEVICES";
field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
field public static final String BACKUP = "android.permission.BACKUP";
field public static final String BATTERY_PREDICTION = "android.permission.BATTERY_PREDICTION";
@@ -68,6 +69,7 @@
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS";
field @Deprecated public static final String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
+ field public static final String BYPASS_ROLE_QUALIFICATION = "android.permission.BYPASS_ROLE_QUALIFICATION";
field public static final String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED";
field public static final String CAMERA_OPEN_CLOSE_LISTENER = "android.permission.CAMERA_OPEN_CLOSE_LISTENER";
field public static final String CAPTURE_AUDIO_HOTWORD = "android.permission.CAPTURE_AUDIO_HOTWORD";
@@ -1923,6 +1925,7 @@
method public boolean disableBLE();
method public boolean enableBLE();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void generateLocalOobData(int, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OobDataCallback);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getDiscoveryEndMillis();
method public boolean isBleScanAlwaysAvailable();
method public boolean isLeEnabled();
@@ -1934,12 +1937,18 @@
field public static final int ACTIVE_DEVICE_ALL = 2; // 0x2
field public static final int ACTIVE_DEVICE_AUDIO = 0; // 0x0
field public static final int ACTIVE_DEVICE_PHONE_CALL = 1; // 0x1
+ field public static final int OOB_ERROR_ADAPTER_DISABLED = 2; // 0x2
+ field public static final int OOB_ERROR_ANOTHER_ACTIVE_REQUEST = 1; // 0x1
+ field public static final int OOB_ERROR_UNKNOWN = 0; // 0x0
}
public static interface BluetoothAdapter.OnMetadataChangedListener {
method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]);
}
+ public static interface BluetoothAdapter.OobDataCallback {
+ }
+
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean canBondWithoutDialog();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean cancelBondProcess();
@@ -2220,7 +2229,7 @@
package android.companion {
public final class CompanionDeviceManager {
- method @RequiresPermission("android.permission.ASSOCIATE_COMPANION_DEVICES") public boolean associate(@NonNull String, @NonNull android.net.MacAddress);
+ method @RequiresPermission(android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES) public boolean associate(@NonNull String, @NonNull android.net.MacAddress);
method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean canPairWithoutPrompt(@NonNull String, @NonNull String, int);
method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociatedForWifiConnection(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
}
@@ -2500,7 +2509,7 @@
package android.content.pm {
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
- method @Nullable public Boolean hasRequestOptimizedExternalStorageAccess();
+ method @Nullable public Boolean hasRequestRawExternalStorageAccess();
method public boolean isEncryptionAware();
method public boolean isInstantApp();
method public boolean isOem();
@@ -3005,12 +3014,19 @@
}
public static final class FontFamilyUpdateRequest.Font {
- ctor public FontFamilyUpdateRequest.Font(@NonNull String, @NonNull android.graphics.fonts.FontStyle, @NonNull java.util.List<android.graphics.fonts.FontVariationAxis>);
method @NonNull public java.util.List<android.graphics.fonts.FontVariationAxis> getAxes();
+ method @IntRange(from=0) public int getIndex();
method @NonNull public String getPostScriptName();
method @NonNull public android.graphics.fonts.FontStyle getStyle();
}
+ public static final class FontFamilyUpdateRequest.Font.Builder {
+ ctor public FontFamilyUpdateRequest.Font.Builder(@NonNull String, @NonNull android.graphics.fonts.FontStyle);
+ method @NonNull public android.graphics.fonts.FontFamilyUpdateRequest.Font build();
+ method @NonNull public android.graphics.fonts.FontFamilyUpdateRequest.Font.Builder setAxes(@NonNull java.util.List<android.graphics.fonts.FontVariationAxis>);
+ method @NonNull public android.graphics.fonts.FontFamilyUpdateRequest.Font.Builder setIndex(@IntRange(from=0) int);
+ }
+
public static final class FontFamilyUpdateRequest.FontFamily {
method @NonNull public java.util.List<android.graphics.fonts.FontFamilyUpdateRequest.Font> getFonts();
method @NonNull public String getName();
@@ -7921,12 +7937,18 @@
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnStateCallback(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
}
+ public static interface NfcAdapter.ControllerAlwaysOnStateCallback {
+ method public void onStateChanged(boolean);
+ }
+
public static interface NfcAdapter.NfcUnlockHandler {
method public boolean onUnlockAttempted(android.nfc.Tag);
}
@@ -9418,7 +9440,7 @@
}
public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
- method @Nullable public int[] getAttestationIds();
+ method @NonNull public int[] getAttestationIds();
method public int getNamespace();
}
@@ -11364,15 +11386,15 @@
}
@Deprecated public class PhoneStateListener {
- method @Deprecated public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
- method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
- method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
- method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
- method @Deprecated public void onRadioPowerStateChanged(int);
- method @Deprecated public void onSrvccStateChanged(int);
- method @Deprecated public void onVoiceActivationStateChanged(int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSrvccStateChanged(int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onVoiceActivationStateChanged(int);
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
@@ -11721,14 +11743,14 @@
public class TelephonyCallback {
field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23; // 0x17
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED = 35; // 0x23
- field @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; // 0xa
+ field public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; // 0xa
field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_BARRING_INFO_CHANGED = 32; // 0x20
field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; // 0x1b
field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26; // 0x1a
field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4
field public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6
field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11
- field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb
+ field @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb
field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5
field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13
field public static final int EVENT_DATA_ACTIVITY_CHANGED = 8; // 0x8
@@ -11783,7 +11805,7 @@
}
public static interface TelephonyCallback.PhoneCapabilityListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
+ method public void onPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
}
public static interface TelephonyCallback.PreciseCallStateListener {
@@ -13594,10 +13616,11 @@
method public int describeContents();
method @Nullable public String getCallIdParameter();
method @NonNull public byte[] getContent();
- method @NonNull public byte[] getEncodedMessage();
+ method @Deprecated @NonNull public byte[] getEncodedMessage();
method @NonNull public String getHeaderSection();
method @NonNull public String getStartLine();
method @NonNull public String getViaBranchParameter();
+ method @NonNull public byte[] toEncodedMessage();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipMessage> CREATOR;
}
@@ -14149,7 +14172,7 @@
public final class DistanceMeasurement implements android.os.Parcelable {
method public int describeContents();
method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
- method public double getErrorMeters();
+ method @FloatRange(from=0.0) public double getErrorMeters();
method public double getMeters();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.DistanceMeasurement> CREATOR;
@@ -14158,8 +14181,8 @@
public static final class DistanceMeasurement.Builder {
ctor public DistanceMeasurement.Builder();
method @NonNull public android.uwb.DistanceMeasurement build();
- method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(double);
- method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(double);
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(@FloatRange(from=0.0, to=1.0) double);
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(@FloatRange(from=0.0) double);
method @NonNull public android.uwb.DistanceMeasurement.Builder setMeters(double);
}
@@ -14218,7 +14241,7 @@
method public void onStartFailed(int, @NonNull android.os.PersistableBundle);
method public void onStarted(@NonNull android.os.PersistableBundle);
method public void onStopFailed(int, @NonNull android.os.PersistableBundle);
- method public void onStopped();
+ method public void onStopped(int, @NonNull android.os.PersistableBundle);
field public static final int REASON_BAD_PARAMETERS = 3; // 0x3
field public static final int REASON_GENERIC_ERROR = 4; // 0x4
field public static final int REASON_LOCAL_REQUEST = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index a2634da..906524e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -233,6 +233,8 @@
field public static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
field public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME = "fg_service_state_settle_time";
field public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
+ field public static final String OPSTR_ACTIVITY_RECOGNITION = "android:activity_recognition";
+ field public static final String OPSTR_ACTIVITY_RECOGNITION_SOURCE = "android:activity_recognition_source";
field public static final String OPSTR_MANAGE_ONGOING_CALLS = "android:manage_ongoing_calls";
field public static final String OPSTR_PHONE_CALL_CAMERA = "android:phone_call_camera";
field public static final String OPSTR_PHONE_CALL_MICROPHONE = "android:phone_call_microphone";
@@ -281,6 +283,11 @@
method public abstract void onHomeVisibilityChanged(boolean);
}
+ public class KeyguardManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"}) public boolean checkLock(int, @Nullable byte[]);
+ method @RequiresPermission(anyOf={android.Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"}) public boolean setLock(int, @Nullable byte[], int, @Nullable byte[]);
+ }
+
public class Notification implements android.os.Parcelable {
method public boolean shouldShowForegroundImmediately();
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 36c66e5..db42803 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -794,6 +794,9 @@
/** @hide Flag for registerUidObserver: report uid cached state has changed. */
public static final int UID_OBSERVER_CACHED = 1<<4;
+ /** @hide Flag for registerUidObserver: report uid capability has changed. */
+ public static final int UID_OBSERVER_CAPABILITY = 1<<5;
+
/** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: normal free-to-run operation. */
public static final int APP_START_MODE_NORMAL = 0;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e596e7c..e50432e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -236,12 +236,6 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
-final class RemoteServiceException extends AndroidRuntimeException {
- public RemoteServiceException(String msg) {
- super(msg);
- }
-}
-
/**
* This manages the execution of the main thread in an
* application process, scheduling and executing activities,
@@ -1274,8 +1268,9 @@
sendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);
}
- public void scheduleCrash(String msg) {
- sendMessage(H.SCHEDULE_CRASH, msg);
+ @Override
+ public void scheduleCrash(String msg, int typeId) {
+ sendMessage(H.SCHEDULE_CRASH, msg, typeId);
}
public void dumpActivity(ParcelFileDescriptor pfd, IBinder activitytoken,
@@ -1892,6 +1887,17 @@
}
}
+ private void throwRemoteServiceException(String message, int typeId) {
+ // Use a switch to ensure all the type IDs are unique.
+ switch (typeId) {
+ case ForegroundServiceDidNotStartInTimeException.TYPE_ID: // 1
+ throw new ForegroundServiceDidNotStartInTimeException(message);
+ case RemoteServiceException.TYPE_ID: // 0
+ default:
+ throw new RemoteServiceException(message);
+ }
+ }
+
class H extends Handler {
public static final int BIND_APPLICATION = 110;
@UnsupportedAppUsage
@@ -2105,7 +2111,8 @@
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SCHEDULE_CRASH:
- throw new RemoteServiceException((String)msg.obj);
+ throwRemoteServiceException((String) msg.obj, msg.arg1);
+ break;
case DUMP_HEAP:
handleDumpHeap((DumpHeapData) msg.obj);
break;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 436007ca..8e2626a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1225,9 +1225,19 @@
/** @hide */
public static final int OP_UWB_RANGING = AppProtoEnums.APP_OP_UWB_RANGING;
+ /**
+ * Activity recognition being accessed by an activity recognition source, which
+ * is a component that already has access since it is the one that detects
+ * activity recognition.
+ *
+ * @hide
+ */
+ public static final int OP_ACTIVITY_RECOGNITION_SOURCE =
+ AppProtoEnums.APP_OP_ACTIVITY_RECOGNITION_SOURCE;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 113;
+ public static final int _NUM_OP = 114;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1478,6 +1488,7 @@
public static final String OPSTR_USE_BIOMETRIC = "android:use_biometric";
/** @hide Recognize physical activity. */
+ @TestApi
public static final String OPSTR_ACTIVITY_RECOGNITION = "android:activity_recognition";
/** @hide Financial app read sms. */
@@ -1643,6 +1654,17 @@
/** @hide */
public static final String OPSTR_UWB_RANGING = "android:uwb_ranging";
+ /**
+ * Activity recognition being accessed by an activity recognition source, which
+ * is a component that already has access since it is the one that detects
+ * activity recognition.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String OPSTR_ACTIVITY_RECOGNITION_SOURCE =
+ "android:activity_recognition_source";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1853,6 +1875,7 @@
OP_MANAGE_MEDIA, // MANAGE_MEDIA
OP_BLUETOOTH_CONNECT, // OP_BLUETOOTH_CONNECT
OP_UWB_RANGING, // OP_UWB_RANGING
+ OP_ACTIVITY_RECOGNITION_SOURCE // OP_ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -1972,6 +1995,7 @@
OPSTR_MANAGE_MEDIA,
OPSTR_BLUETOOTH_CONNECT,
OPSTR_UWB_RANGING,
+ OPSTR_ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -2091,7 +2115,8 @@
"COARSE_LOCATION_SOURCE",
"MANAGE_MEDIA",
"BLUETOOTH_CONNECT",
- "UWB_RANGING"
+ "UWB_RANGING",
+ "ACTIVITY_RECOGNITION_SOURCE"
};
/**
@@ -2213,6 +2238,7 @@
Manifest.permission.MANAGE_MEDIA,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.UWB_RANGING,
+ null, // no permission for OP_ACTIVITY_RECOGNITION_SOURCE,
};
/**
@@ -2334,6 +2360,7 @@
null, // MANAGE_MEDIA
null, // BLUETOOTH_CONNECT
null, // UWB_RANGING
+ null, // ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -2454,6 +2481,7 @@
null, // MANAGE_MEDIA
null, // BLUETOOTH_CONNECT
null, // UWB_RANGING
+ null // ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -2573,6 +2601,7 @@
AppOpsManager.MODE_DEFAULT, // MANAGE_MEDIA
AppOpsManager.MODE_ALLOWED, // BLUETOOTH_CONNECT
AppOpsManager.MODE_ALLOWED, // UWB_RANGING
+ AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION_SOURCE
};
/**
@@ -2696,6 +2725,7 @@
false, // MANAGE_MEDIA
false, // BLUETOOTH_CONNECT
false, // UWB_RANGING
+ false, // ACTIVITY_RECOGNITION_SOURCE
};
/**
diff --git a/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java b/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java
new file mode 100644
index 0000000..364291e
--- /dev/null
+++ b/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+/**
+ * Exception used to crash an app process when it didn't call {@link Service#startForeground}
+ * in time after the service was started with
+ * {@link android.content.Context#startForegroundService}.
+ *
+ * @hide
+ */
+public class ForegroundServiceDidNotStartInTimeException extends RemoteServiceException {
+ /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
+ public static final int TYPE_ID = 1;
+
+ public ForegroundServiceDidNotStartInTimeException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 1b8eb8a..f9279da 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -321,6 +321,8 @@
boolean isTopActivityImmersive();
void crashApplication(int uid, int initialPid, in String packageName, int userId,
in String message, boolean force);
+ void crashApplicationWithType(int uid, int initialPid, in String packageName, int userId,
+ in String message, boolean force, int exceptionTypeId);
/** @deprecated -- use getProviderMimeTypeAsync */
@UnsupportedAppUsage(maxTargetSdk = 29, publicAlternatives =
"Use {@link android.content.ContentResolver#getType} public API instead.")
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index b5294d5..78e7ce8 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -106,7 +106,7 @@
void scheduleOnNewActivityOptions(IBinder token, in Bundle options);
void scheduleSuicide();
void dispatchPackageBroadcast(int cmd, in String[] packages);
- void scheduleCrash(in String msg);
+ void scheduleCrash(in String msg, int typeId);
void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path,
in ParcelFileDescriptor fd, in RemoteCallback finishCallback);
void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix,
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 4326c2d..dc71a32 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -24,6 +24,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.PasswordMetrics;
@@ -51,6 +52,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockscreenCredential;
+import com.android.internal.widget.VerifyCredentialResponse;
import java.nio.charset.Charset;
import java.util.Arrays;
@@ -696,14 +698,15 @@
}
private boolean checkInitialLockMethodUsage() {
- if (mContext.checkCallingOrSelfPermission(Manifest.permission.SET_INITIAL_LOCK)
- != PackageManager.PERMISSION_GRANTED) {
+ if (!hasPermission(Manifest.permission.SET_INITIAL_LOCK)) {
throw new SecurityException("Requires SET_INITIAL_LOCK permission.");
}
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
- return false;
- }
- return true;
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
+
+ private boolean hasPermission(String permission) {
+ return PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+ permission);
}
/**
@@ -792,38 +795,14 @@
Log.e(TAG, "Password is not valid, rejecting call to setLock");
return false;
}
- boolean success = false;
+ boolean success;
try {
- switch (lockType) {
- case PASSWORD:
- CharSequence passwordStr = new String(password, Charset.forName("UTF-8"));
- lockPatternUtils.setLockCredential(
- LockscreenCredential.createPassword(passwordStr),
- /* savedPassword= */ LockscreenCredential.createNone(),
- userId);
- success = true;
- break;
- case PIN:
- CharSequence pinStr = new String(password);
- lockPatternUtils.setLockCredential(
- LockscreenCredential.createPin(pinStr),
- /* savedPassword= */ LockscreenCredential.createNone(),
- userId);
- success = true;
- break;
- case PATTERN:
- List<LockPatternView.Cell> pattern =
- LockPatternUtils.byteArrayToPattern(password);
- lockPatternUtils.setLockCredential(
- LockscreenCredential.createPattern(pattern),
- /* savedPassword= */ LockscreenCredential.createNone(),
- userId);
- pattern.clear();
- success = true;
- break;
- default:
- Log.e(TAG, "Unknown lock type, returning a failure");
- }
+ LockscreenCredential credential = createLockscreenCredential(
+ lockType, password);
+ success = lockPatternUtils.setLockCredential(
+ credential,
+ /* savedPassword= */ LockscreenCredential.createNone(),
+ userId);
} catch (Exception e) {
Log.e(TAG, "Save lock exception", e);
success = false;
@@ -832,4 +811,81 @@
}
return success;
}
+
+ /**
+ * Set the lockscreen password to {@code newPassword} after validating the current password
+ * against {@code currentPassword}.
+ * <p>If no password is currently set, {@code currentPassword} should be set to {@code null}.
+ * <p>To clear the current password, {@code newPassword} should be set to {@code null}.
+ *
+ * @return {@code true} if password successfully set.
+ *
+ * @throws IllegalArgumentException if {@code newLockType} or {@code currentLockType}
+ * is invalid.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {
+ Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS,
+ Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE
+ })
+ public boolean setLock(@LockTypes int newLockType, @Nullable byte[] newPassword,
+ @LockTypes int currentLockType, @Nullable byte[] currentPassword) {
+ final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+ final int userId = mContext.getUserId();
+ LockscreenCredential currentCredential = createLockscreenCredential(
+ currentLockType, currentPassword);
+ LockscreenCredential newCredential = createLockscreenCredential(
+ newLockType, newPassword);
+ return lockPatternUtils.setLockCredential(newCredential, currentCredential, userId);
+ }
+
+ /**
+ * Verifies the current lock credentials against {@code password}.
+ * <p>To check if no password is set, {@code password} should be set to {@code null}.
+ *
+ * @return {@code true} if credentials match
+ *
+ * @throws IllegalArgumentException if {@code lockType} is invalid.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {
+ Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS,
+ Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE
+ })
+ public boolean checkLock(@LockTypes int lockType, @Nullable byte[] password) {
+ final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+ final LockscreenCredential credential = createLockscreenCredential(
+ lockType, password);
+ final VerifyCredentialResponse response = lockPatternUtils.verifyCredential(
+ credential, mContext.getUserId(), /* flags= */ 0);
+ if (response == null) {
+ return false;
+ }
+ return response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK;
+ }
+
+ private LockscreenCredential createLockscreenCredential(
+ @LockTypes int lockType, @Nullable byte[] password) {
+ if (password == null) {
+ return LockscreenCredential.createNone();
+ }
+ switch (lockType) {
+ case PASSWORD:
+ CharSequence passwordStr = new String(password, Charset.forName("UTF-8"));
+ return LockscreenCredential.createPassword(passwordStr);
+ case PIN:
+ CharSequence pinStr = new String(password);
+ return LockscreenCredential.createPin(pinStr);
+ case PATTERN:
+ List<LockPatternView.Cell> pattern =
+ LockPatternUtils.byteArrayToPattern(password);
+ return LockscreenCredential.createPattern(pattern);
+ default:
+ throw new IllegalArgumentException("Unknown lock type " + lockType);
+ }
+ }
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3de78f6..fa35025 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5360,12 +5360,8 @@
contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
// Use different highlighted colors for conversations' unread count
if (p.mHighlightExpander) {
- pillColor = getAccentTertiaryColor(p);
- // TODO(b/183710694): The accent tertiary is currently too bright in dark mode, so
- // we need to pick a contrasting color.
- textColor = ColorUtils.setAlphaComponent(
- ContrastColorUtil.resolvePrimaryColor(mContext, pillColor, mInNightMode),
- 0xFF);
+ textColor = getBackgroundColor(p);
+ pillColor = getAccentColor(p);
}
contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
@@ -6296,23 +6292,6 @@
}
/**
- * Gets the tertiary accent color for colored UI elements. If we're tinting with the theme
- * accent, this comes from the tertiary system accent palette, otherwise this would be
- * identical to {@link #getSmallIconColor(StandardTemplateParams)}.
- */
- private @ColorInt int getAccentTertiaryColor(StandardTemplateParams p) {
- if (isColorized(p)) {
- return getPrimaryTextColor(p);
- }
- int color = obtainThemeColor(com.android.internal.R.attr.colorAccentTertiary,
- COLOR_INVALID);
- if (color != COLOR_INVALID) {
- return color;
- }
- return getContrastColor(p);
- }
-
- /**
* Gets the theme's error color, or the primary text color for colorized notifications.
*/
private @ColorInt int getErrorColor(StandardTemplateParams p) {
diff --git a/core/java/android/app/RemoteServiceException.java b/core/java/android/app/RemoteServiceException.java
new file mode 100644
index 0000000..4b32463
--- /dev/null
+++ b/core/java/android/app/RemoteServiceException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.util.AndroidRuntimeException;
+
+/**
+ * Exception used by {@link ActivityThread} to crash an app process.
+ *
+ * @hide
+ */
+public class RemoteServiceException extends AndroidRuntimeException {
+ /**
+ * The type ID passed to {@link IApplicationThread#scheduleCrash}.
+ *
+ * Assign a unique ID to each subclass. See the above method for the numbers that are already
+ * taken.
+ */
+ public static final int TYPE_ID = 0;
+
+ public RemoteServiceException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/java/android/app/time/LocationTimeZoneManager.java b/core/java/android/app/time/LocationTimeZoneManager.java
index 066aada..f506f12 100644
--- a/core/java/android/app/time/LocationTimeZoneManager.java
+++ b/core/java/android/app/time/LocationTimeZoneManager.java
@@ -50,31 +50,6 @@
public static final String SHELL_COMMAND_STOP = "stop";
/**
- * A shell command that can put providers into different modes. Takes effect next time the
- * service is started.
- */
- public static final String SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE =
- "set_provider_mode_override";
-
- /**
- * The default provider mode.
- * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}.
- */
- public static final String PROVIDER_MODE_OVERRIDE_NONE = "none";
-
- /**
- * The "simulated" provider mode.
- * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}.
- */
- public static final String PROVIDER_MODE_OVERRIDE_SIMULATED = "simulated";
-
- /**
- * The "disabled" provider mode (equivalent to there being no provider configured).
- * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}.
- */
- public static final String PROVIDER_MODE_OVERRIDE_DISABLED = "disabled";
-
- /**
* A shell command that tells the service to record state information during tests. The next
* argument value is "true" or "false".
*/
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 1cbb2fb..3db1885 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -479,7 +479,7 @@
* Returns the broadcast receiver that is providing this widget.
*/
@NonNull
- public ActivityInfo getProviderInfo() {
+ public ActivityInfo getActivityInfo() {
return providerInfo;
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 5446deb..79fd807 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -28,6 +28,7 @@
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.app.PropertyInvalidatedCache;
+import android.bluetooth.BluetoothDevice.Transport;
import android.bluetooth.BluetoothProfile.ConnectionPolicy;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
@@ -3046,6 +3047,168 @@
return false;
}
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "OOB_ERROR_" }, value = {
+ OOB_ERROR_UNKNOWN,
+ OOB_ERROR_ANOTHER_ACTIVE_REQUEST,
+ OOB_ERROR_ADAPTER_DISABLED
+ })
+ public @interface OobError {}
+
+ /**
+ * An unknown error has occurred in the controller, stack, or callback pipeline.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int OOB_ERROR_UNKNOWN = 0;
+
+ /**
+ * If another application has already requested {@link OobData} then another fetch will be
+ * disallowed until the callback is removed.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int OOB_ERROR_ANOTHER_ACTIVE_REQUEST = 1;
+
+ /**
+ * The adapter is currently disabled, please enable it.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int OOB_ERROR_ADAPTER_DISABLED = 2;
+
+ /**
+ * Provides callback methods for receiving {@link OobData} from the host stack, as well as an
+ * error interface in order to allow the caller to determine next steps based on the {@link
+ * ErrorCode}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface OobDataCallback {
+ /**
+ * Handles the {@link OobData} received from the host stack.
+ *
+ * @param transport - whether the {@link OobData} is generated for LE or Classic.
+ * @param oobData - data generated in the host stack(LE) or controller (Classic)
+ *
+ * @hide
+ */
+ void onOobData(@Transport int transport, @Nullable OobData oobData);
+
+ /**
+ * Provides feedback when things don't go as expected.
+ *
+ * @param errorCode - the code descibing the type of error that occurred.
+ *
+ * @hide
+ */
+ void onError(@OobError int errorCode);
+ }
+
+ /**
+ * Wraps an AIDL interface around an {@link OobDataCallback} interface.
+ *
+ * @see {@link IBluetoothOobDataCallback} for interface definition.
+ *
+ * @hide
+ */
+ public class WrappedOobDataCallback extends IBluetoothOobDataCallback.Stub {
+ private final OobDataCallback mCallback;
+ private final Executor mExecutor;
+
+ /**
+ * @param callback - object to receive {@link OobData} must be a non null argument
+ *
+ * @throws NullPointerException if the callback is null.
+ */
+ WrappedOobDataCallback(@NonNull OobDataCallback callback,
+ @NonNull @CallbackExecutor Executor executor) {
+ Preconditions.checkNotNull(callback);
+ Preconditions.checkNotNull(executor);
+ mCallback = callback;
+ mExecutor = executor;
+ }
+ /**
+ * Wrapper function to relay to the {@link OobDataCallback#onOobData}
+ *
+ * @param transport - whether the {@link OobData} is generated for LE or Classic.
+ * @param oobData - data generated in the host stack(LE) or controller (Classic)
+ *
+ * @hide
+ */
+ public void onOobData(@Transport int transport, OobData oobData) {
+ mExecutor.execute(new Runnable() {
+ public void run() {
+ mCallback.onOobData(transport, oobData);
+ }
+ });
+ }
+ /**
+ * Wrapper function to relay to the {@link OobDataCallback#onError}
+ *
+ * @param errorCode - the code descibing the type of error that occurred.
+ *
+ * @hide
+ */
+ public void onError(@OobError int errorCode) {
+ mExecutor.execute(new Runnable() {
+ public void run() {
+ mCallback.onError(errorCode);
+ }
+ });
+ }
+ }
+
+ /**
+ * Fetches a secret data value that can be used for a secure and simple pairing experience.
+ *
+ * <p>This is the Local Out of Band data the comes from the
+ *
+ * <p>This secret is the local Out of Band data. This data is used to securely and quickly
+ * pair two devices with minimal user interaction.
+ *
+ * <p>For example, this secret can be transferred to a remote device out of band (meaning any
+ * other way besides using bluetooth). Once the remote device finds this device using the
+ * information given in the data, such as the PUBLIC ADDRESS, the remote device could then
+ * connect to this device using this secret when the pairing sequenece asks for the secret.
+ * This device will respond by automatically accepting the pairing due to the secret being so
+ * trustworthy.
+ *
+ * @param transport - provide type of transport (e.g. LE or Classic).
+ * @param callback - target object to receive the {@link OobData} value.
+ *
+ * @throws NullPointerException if callback is null.
+ * @throws IllegalArgumentException if the transport is not valid.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void generateLocalOobData(@Transport int transport,
+ @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) {
+ if (transport != BluetoothDevice.TRANSPORT_BREDR && transport
+ != BluetoothDevice.TRANSPORT_LE) {
+ throw new IllegalArgumentException("Invalid transport '" + transport + "'!");
+ }
+ Preconditions.checkNotNull(callback);
+ if (!isEnabled()) {
+ Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!");
+ callback.onError(OOB_ERROR_ADAPTER_DISABLED);
+ } else {
+ try {
+ mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback,
+ executor));
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ }
+
/**
* Enable control of the Bluetooth Adapter for a single application.
*
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index a96c14f..0c208fd 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -952,6 +952,21 @@
@SystemApi
public static final int ACCESS_REJECTED = 2;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = { "TRANSPORT_" },
+ value = {
+ /** Allow host to automatically select a transport (dual-mode only) */
+ TRANSPORT_AUTO,
+ /** Use Classic or BR/EDR transport.*/
+ TRANSPORT_BREDR,
+ /** Use Low Energy transport.*/
+ TRANSPORT_LE,
+ }
+ )
+ public @interface Transport {}
+
/**
* No preference of physical transport for GATT connections to remote dual-mode devices
*/
@@ -1084,6 +1099,10 @@
public void onBrEdrDown() {
if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
}
+
+ public void onOobData(@Transport int transport, OobData oobData) {
+ if (DBG) Log.d(TAG, "onOobData: got data");
+ }
};
/**
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 2ce7156..0116db0 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -375,6 +375,14 @@
* Calling app must check for feature presence of
* {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} before calling this API.
*
+ * For Bluetooth LE devices this is based on scanning for device with the given address.
+ * For Bluetooth classic devices this is triggered when the device connects/disconnects.
+ * WiFi devices are not supported.
+ *
+ * If a Bluetooth LE device wants to use a rotating mac address, it is recommended to use
+ * Resolvable Private Address, and ensure the device is bonded to the phone so that android OS
+ * is able to resolve the address.
+ *
* @param deviceAddress a previously-associated companion device's address
*
* @throws DeviceNotAssociatedException if the given device was not previously associated
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index c851519..b13bf09 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -21,15 +21,12 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.AppGlobals;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
import android.permission.PermissionManager;
import android.util.ArraySet;
@@ -93,6 +90,8 @@
// TODO: Codegen applies method level annotations to argument vs the generated member (@SystemApi)
// TODO: Codegen doesn't properly read/write IBinder members
// TODO: Codegen doesn't properly handle Set arguments
+// TODO: Codegen requires @SystemApi annotations on fields which breaks
+// android.signature.cts.api.AnnotationTest (need to update the test)
// @DataClass(genEqualsHashCode = true, genConstructor = false, genBuilder = true)
public final class AttributionSource implements Parcelable {
/**
@@ -153,8 +152,6 @@
*
* @hide
*/
- @SystemApi
- @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
@DataClass.ParcelWith(RenouncedPermissionsParcelling.class)
private @Nullable Set<String> mRenouncedPermissions = null;
@@ -516,7 +513,7 @@
private @Nullable String mPackageName;
private @Nullable String mAttributionTag;
private @Nullable IBinder mToken;
- private @SystemApi @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) @Nullable Set<String> mRenouncedPermissions;
+ private @Nullable Set<String> mRenouncedPermissions;
private @Nullable AttributionSource mNext;
private long mBuilderFieldsSet = 0L;
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index cadbd60..11adfa3 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -51,6 +51,25 @@
*/
@SystemService(Context.CLIPBOARD_SERVICE)
public class ClipboardManager extends android.text.ClipboardManager {
+
+ /**
+ * DeviceConfig property, within the clipboard namespace, that determines whether notifications
+ * are shown when an app accesses clipboard. This may be overridden by a user-controlled
+ * setting.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_SHOW_ACCESS_NOTIFICATIONS =
+ "show_access_notifications";
+
+ /**
+ * Default value for the DeviceConfig property that determines whether notifications are shown
+ * when an app accesses clipboard.
+ *
+ * @hide
+ */
+ public static final boolean DEVICE_CONFIG_DEFAULT_SHOW_ACCESS_NOTIFICATIONS = true;
+
private final Context mContext;
private final Handler mHandler;
private final IClipboard mService;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2c77372..183e73c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2401,14 +2401,6 @@
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
/**
- * Clear DNS Cache Action: This is broadcast when networks have changed and old
- * DNS entries should be tossed.
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
- /**
* Alarm Changed Action: This is broadcast when the AlarmClock
* application's alarm is set or unset. It is used by the
* AlarmClock application and the StatusBar service.
@@ -6569,6 +6561,10 @@
* any affinities needed to have that task in the proper state (either
* moving activities to or from it), or simply resetting that task to
* its initial state if needed.
+ *
+ * @see android.R.attr#allowTaskReparenting
+ * @see android.R.attr#clearTaskOnLaunch
+ * @see android.R.attr#finishOnTaskLaunch
*/
public static final int FLAG_ACTIVITY_RESET_TASK_IF_NEEDED = 0x00200000;
/**
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index 01b554a..1735aa2 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -5,6 +5,7 @@
per-file IntentFilter.java = patb@google.com
per-file Intent.java = toddke@google.com
per-file Intent.java = patb@google.com
+per-file Intent.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS
per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture/OWNERS
per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS
diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
index 049bfe7..5089f30 100644
--- a/core/java/android/content/PermissionChecker.java
+++ b/core/java/android/content/PermissionChecker.java
@@ -1066,11 +1066,25 @@
return AppOpsManager.MODE_ERRORED;
}
if (selfAccess) {
- return appOpsManager.startOpNoThrow(op, resolvedAttributionSource.getUid(),
- resolvedAttributionSource.getPackageName(),
- /*startIfModeDefault*/ false,
- resolvedAttributionSource.getAttributionTag(),
- message);
+ // If the datasource is not in a trusted platform component then in would not
+ // have UPDATE_APP_OPS_STATS and the call below would fail. The problem is that
+ // an app is exposing runtime permission protected data but cannot blame others
+ // in a trusted way which would not properly show in permission usage UIs.
+ // As a fallback we note a proxy op that blames the app and the datasource.
+ try {
+ return appOpsManager.startOpNoThrow(op, resolvedAttributionSource.getUid(),
+ resolvedAttributionSource.getPackageName(),
+ /*startIfModeDefault*/ false,
+ resolvedAttributionSource.getAttributionTag(),
+ message);
+ } catch (SecurityException e) {
+ Slog.w(LOG_TAG, "Datasource " + attributionSource + " protecting data with"
+ + " platform defined runtime permission "
+ + AppOpsManager.opToPermission(op) + " while not having "
+ + Manifest.permission.UPDATE_APP_OPS_STATS);
+ return appOpsManager.startProxyOpNoThrow(op, attributionSource, message,
+ skipProxyOperation);
+ }
} else {
return appOpsManager.startProxyOpNoThrow(op, resolvedAttributionSource, message,
skipProxyOperation);
@@ -1082,10 +1096,24 @@
return AppOpsManager.MODE_ERRORED;
}
if (selfAccess) {
- return appOpsManager.noteOpNoThrow(op, resolvedAttributionSource.getUid(),
- resolvedAttributionSource.getPackageName(),
- resolvedAttributionSource.getAttributionTag(),
- message);
+ // If the datasource is not in a trusted platform component then in would not
+ // have UPDATE_APP_OPS_STATS and the call below would fail. The problem is that
+ // an app is exposing runtime permission protected data but cannot blame others
+ // in a trusted way which would not properly show in permission usage UIs.
+ // As a fallback we note a proxy op that blames the app and the datasource.
+ try {
+ return appOpsManager.noteOpNoThrow(op, resolvedAttributionSource.getUid(),
+ resolvedAttributionSource.getPackageName(),
+ resolvedAttributionSource.getAttributionTag(),
+ message);
+ } catch (SecurityException e) {
+ Slog.w(LOG_TAG, "Datasource " + attributionSource + " protecting data with"
+ + " platform defined runtime permission "
+ + AppOpsManager.opToPermission(op) + " while not having "
+ + Manifest.permission.UPDATE_APP_OPS_STATS);
+ return appOpsManager.noteProxyOpNoThrow(op, attributionSource, message,
+ skipProxyOperation);
+ }
} else {
return appOpsManager.noteProxyOpNoThrow(op, resolvedAttributionSource, message,
skipProxyOperation);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6badf0e0..6ad204e 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1436,11 +1436,11 @@
private @NativeHeapZeroInitialized int nativeHeapZeroInitialized = ZEROINIT_DEFAULT;
/**
- * If {@code true} this app requests optimized external storage access.
+ * If {@code true} this app requests raw external storage access.
* The request may not be honored due to policy or other reasons.
*/
@Nullable
- private Boolean requestOptimizedExternalStorageAccess;
+ private Boolean requestRawExternalStorageAccess;
/**
* Represents the default policy. The actual policy used will depend on other properties of
@@ -1598,9 +1598,9 @@
if (nativeHeapZeroInitialized != ZEROINIT_DEFAULT) {
pw.println(prefix + "nativeHeapZeroInitialized=" + nativeHeapZeroInitialized);
}
- if (requestOptimizedExternalStorageAccess != null) {
- pw.println(prefix + "requestOptimizedExternalStorageAccess="
- + requestOptimizedExternalStorageAccess);
+ if (requestRawExternalStorageAccess != null) {
+ pw.println(prefix + "requestRawExternalStorageAccess="
+ + requestRawExternalStorageAccess);
}
}
super.dumpBack(pw, prefix);
@@ -1829,7 +1829,7 @@
gwpAsanMode = orig.gwpAsanMode;
memtagMode = orig.memtagMode;
nativeHeapZeroInitialized = orig.nativeHeapZeroInitialized;
- requestOptimizedExternalStorageAccess = orig.requestOptimizedExternalStorageAccess;
+ requestRawExternalStorageAccess = orig.requestRawExternalStorageAccess;
}
public String toString() {
@@ -1918,7 +1918,7 @@
dest.writeInt(gwpAsanMode);
dest.writeInt(memtagMode);
dest.writeInt(nativeHeapZeroInitialized);
- sForBoolean.parcel(requestOptimizedExternalStorageAccess, dest, parcelableFlags);
+ sForBoolean.parcel(requestRawExternalStorageAccess, dest, parcelableFlags);
}
public static final @android.annotation.NonNull Parcelable.Creator<ApplicationInfo> CREATOR
@@ -2004,7 +2004,7 @@
gwpAsanMode = source.readInt();
memtagMode = source.readInt();
nativeHeapZeroInitialized = source.readInt();
- requestOptimizedExternalStorageAccess = sForBoolean.unparcel(source);
+ requestRawExternalStorageAccess = sForBoolean.unparcel(source);
}
/**
@@ -2121,10 +2121,10 @@
/**
* @return
* <ul>
- * <li>{@code true} if this app requested optimized external storage access
- * <li>{@code false} if this app requests to disable optimized external storage access.
+ * <li>{@code true} if this app requested raw external storage access
+ * <li>{@code false} if this app requests to disable raw external storage access.
* <li>{@code null} if the app didn't specify
- * {@link android.R.styleable#AndroidManifestApplication_requestOptimizedExternalStorageAccess}
+ * {@link android.R.styleable#AndroidManifestApplication_requestRawExternalStorageAccess}
* in its manifest file.
* </ul>
*
@@ -2132,8 +2132,8 @@
*/
@SystemApi
@Nullable
- public Boolean hasRequestOptimizedExternalStorageAccess() {
- return requestOptimizedExternalStorageAccess;
+ public Boolean hasRequestRawExternalStorageAccess() {
+ return requestRawExternalStorageAccess;
}
/**
@@ -2421,8 +2421,8 @@
nativeHeapZeroInitialized = value;
}
/** {@hide} */
- public void setRequestOptimizedExternalStorageAccess(@Nullable Boolean value) {
- requestOptimizedExternalStorageAccess = value;
+ public void setRequestRawExternalStorageAccess(@Nullable Boolean value) {
+ requestRawExternalStorageAccess = value;
}
/** {@hide} */
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 1c65e00..8dcba7f 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -259,8 +259,8 @@
ParsingPackage setNativeHeapZeroInitialized(
@ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized);
- ParsingPackage setRequestOptimizedExternalStorageAccess(
- @Nullable Boolean requestOptimizedExternalStorageAccess);
+ ParsingPackage setRequestRawExternalStorageAccess(
+ @Nullable Boolean requestRawExternalStorageAccess);
ParsingPackage setCrossProfile(boolean crossProfile);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 97e1b54..ea7135e 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -400,7 +400,7 @@
@Nullable
@DataClass.ParcelWith(ForBoolean.class)
- private Boolean requestOptimizedExternalStorageAccess;
+ private Boolean requestRawExternalStorageAccess;
// TODO(chiuwinson): Non-null
@Nullable
@@ -1086,7 +1086,7 @@
appInfo.setGwpAsanMode(gwpAsanMode);
appInfo.setMemtagMode(memtagMode);
appInfo.setNativeHeapZeroInitialized(nativeHeapZeroInitialized);
- appInfo.setRequestOptimizedExternalStorageAccess(requestOptimizedExternalStorageAccess);
+ appInfo.setRequestRawExternalStorageAccess(requestRawExternalStorageAccess);
appInfo.setBaseCodePath(mBaseApkPath);
appInfo.setBaseResourcePath(mBaseApkPath);
appInfo.setCodePath(mPath);
@@ -1223,7 +1223,7 @@
dest.writeMap(this.mProperties);
dest.writeInt(this.memtagMode);
dest.writeInt(this.nativeHeapZeroInitialized);
- sForBoolean.parcel(this.requestOptimizedExternalStorageAccess, dest, flags);
+ sForBoolean.parcel(this.requestRawExternalStorageAccess, dest, flags);
}
public ParsingPackageImpl(Parcel in) {
@@ -1348,7 +1348,7 @@
this.mProperties = in.readHashMap(boot);
this.memtagMode = in.readInt();
this.nativeHeapZeroInitialized = in.readInt();
- this.requestOptimizedExternalStorageAccess = sForBoolean.unparcel(in);
+ this.requestRawExternalStorageAccess = sForBoolean.unparcel(in);
assignDerivedFields();
}
@@ -2131,8 +2131,8 @@
@Nullable
@Override
- public Boolean hasRequestOptimizedExternalStorageAccess() {
- return requestOptimizedExternalStorageAccess;
+ public Boolean hasRequestRawExternalStorageAccess() {
+ return requestRawExternalStorageAccess;
}
@Override
@@ -2586,8 +2586,8 @@
}
@Override
- public ParsingPackageImpl setRequestOptimizedExternalStorageAccess(@Nullable Boolean value) {
- requestOptimizedExternalStorageAccess = value;
+ public ParsingPackageImpl setRequestRawExternalStorageAccess(@Nullable Boolean value) {
+ requestRawExternalStorageAccess = value;
return this;
}
@Override
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index cfd828e..4d4cc1a 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -905,7 +905,7 @@
int getNativeHeapZeroInitialized();
@Nullable
- Boolean hasRequestOptimizedExternalStorageAccess();
+ Boolean hasRequestRawExternalStorageAccess();
// TODO(b/135203078): Hide and enforce going through PackageInfoUtils
ApplicationInfo toAppInfoWithoutState();
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 4e7bd70..a1ffc0c 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -2019,9 +2019,9 @@
v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED);
}
if (sa.hasValue(
- R.styleable.AndroidManifestApplication_requestOptimizedExternalStorageAccess)) {
- pkg.setRequestOptimizedExternalStorageAccess(sa.getBoolean(R.styleable
- .AndroidManifestApplication_requestOptimizedExternalStorageAccess,
+ R.styleable.AndroidManifestApplication_requestRawExternalStorageAccess)) {
+ pkg.setRequestRawExternalStorageAccess(sa.getBoolean(R.styleable
+ .AndroidManifestApplication_requestRawExternalStorageAccess,
false));
}
} finally {
diff --git a/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java
index fbc951e..bfbcfd8 100644
--- a/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java
+++ b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java
@@ -23,6 +23,7 @@
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -157,6 +158,61 @@
*/
public static final class Font {
+ /**
+ * Builds a {@link Font}.
+ */
+ public static final class Builder {
+ private final@NonNull String mPostScriptName;
+ private final @NonNull FontStyle mStyle;
+ private @NonNull List<FontVariationAxis> mAxes = Collections.emptyList();
+ private @IntRange(from = 0) int mIndex = 0;
+
+ /**
+ * Construct a {@link Font.Builder}
+ *
+ * @param postScriptName The PostScript name of the font file to use. PostScript name is
+ * in Name ID 6 field in 'name' table, as specified by OpenType
+ * specification.
+ * @param style The style for this font.
+ */
+ public Builder(@NonNull String postScriptName, @NonNull FontStyle style) {
+ Objects.requireNonNull(postScriptName);
+ Preconditions.checkStringNotEmpty(postScriptName);
+ Objects.requireNonNull(style);
+ mPostScriptName = postScriptName;
+ mStyle = style;
+ }
+
+ /**
+ * A list of {@link FontVariationAxis} to specify axis tags and values for variable
+ * fonts.
+ */
+ public @NonNull Builder setAxes(@NonNull List<FontVariationAxis> axes) {
+ Objects.requireNonNull(axes);
+ Preconditions.checkCollectionElementsNotNull(axes, "axes");
+ mAxes = axes;
+ return this;
+ }
+
+ /**
+ * Sets font collection index for the Font.
+ *
+ * @see {@link android.R.attr#ttcIndex}.
+ */
+ public @NonNull Builder setIndex(@IntRange(from = 0) int index) {
+ Preconditions.checkArgumentNonnegative(index);
+ mIndex = index;
+ return this;
+ }
+
+ /**
+ * Build a {@link Font} instance.
+ */
+ public @NonNull Font build() {
+ return new Font(mPostScriptName, mStyle, mIndex, mAxes);
+ }
+ }
+
@NonNull
private final String mPostScriptName;
@NonNull
@@ -164,6 +220,8 @@
@NonNull
private final List<FontVariationAxis> mAxes;
+ private final @IntRange(from = 0) int mIndex;
+
/**
* Constructs a FontStyleVariation.
*
@@ -176,18 +234,15 @@
* Name ID 6 field in 'name' table, as specified by OpenType
* specification.
* @param style The style for this font.
+ * @param index The index of the font in the collection.
* @param axes A list of {@link FontVariationAxis} to specify axis tags and values
* for variable fonts.
*/
- public Font(@NonNull String postScriptName, @NonNull FontStyle style,
- @NonNull List<FontVariationAxis> axes) {
- Objects.requireNonNull(postScriptName);
- Preconditions.checkStringNotEmpty(postScriptName);
- Objects.requireNonNull(style);
- Objects.requireNonNull(axes);
- Preconditions.checkCollectionElementsNotNull(axes, "axes");
+ private Font(@NonNull String postScriptName, @NonNull FontStyle style,
+ @IntRange(from = 0) int index, @NonNull List<FontVariationAxis> axes) {
mPostScriptName = postScriptName;
mStyle = style;
+ mIndex = index;
mAxes = axes;
}
@@ -207,6 +262,7 @@
return mStyle;
}
+
/**
* Returns the list of {@link FontVariationAxis}.
*/
@@ -217,12 +273,9 @@
/**
* Returns the index of collection
- *
- * TODO(183752879): Make font index configurable and make this SystemApi.
- * @hide
*/
public @IntRange(from = 0) int getIndex() {
- return 0;
+ return mIndex;
}
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 365dea6..3c11d8e 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -575,7 +575,6 @@
&& rate > CAPPED_SAMPLING_RATE_LEVEL
&& mIsPackageDebuggable
&& !mHasHighSamplingRateSensorsPermission) {
- Compatibility.reportChange(CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION);
throw new SecurityException("To use the sampling rate level " + rate
+ ", app needs to declare the normal permission"
+ " HIGH_SAMPLING_RATE_SENSORS.");
@@ -787,7 +786,6 @@
&& rateUs < CAPPED_SAMPLING_PERIOD_US
&& mManager.mIsPackageDebuggable
&& !mManager.mHasHighSamplingRateSensorsPermission) {
- Compatibility.reportChange(CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION);
throw new SecurityException("To use the sampling rate of " + rateUs
+ " microseconds, app needs to declare the normal permission"
+ " HIGH_SAMPLING_RATE_SENSORS.");
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 9457d8f1..11c426a 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -17,6 +17,7 @@
package android.hardware.display;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
@@ -118,6 +119,7 @@
* @return Model year of the device. Return -1 if not available. Typically,
* one of model year or manufacture year is available.
*/
+ @IntRange(from = -1)
public int getModelYear() {
return mModelYear != null ? mModelYear : -1;
}
@@ -126,6 +128,7 @@
* @return The year of manufacture, or -1 it is not available. Typically,
* one of model year or manufacture year is available.
*/
+ @IntRange(from = -1)
public int getManufactureYear() {
if (mManufactureDate == null) {
return -1;
@@ -134,9 +137,10 @@
}
/**
- * @return The week of manufacture, or -1 it is not available. Typically,
- * not present if model year is available.
+ * @return The week of manufacture which ranges from 1 to 53, or -1 it is not available.
+ * Typically, it is not present if model year is available.
*/
+ @IntRange(from = -1, to = 53)
public int getManufactureWeek() {
if (mManufactureDate == null) {
return -1;
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index cdc219a..983a43a 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -391,8 +391,9 @@
}
final int numListeners = mDisplayListeners.size();
+ DisplayInfo info = getDisplayInfo(displayId);
for (int i = 0; i < numListeners; i++) {
- mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
+ mDisplayListeners.get(i).sendDisplayEvent(displayId, event, info);
}
if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) {
// Choreographer only supports a single display, so only dispatch refresh rate
@@ -894,6 +895,8 @@
public final DisplayListener mListener;
public long mEventsMask;
+ private final DisplayInfo mDisplayInfo = new DisplayInfo();
+
DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper,
@EventsMask long eventsMask) {
super(looper, null, true /*async*/);
@@ -901,8 +904,8 @@
mEventsMask = eventsMask;
}
- public void sendDisplayEvent(int displayId, @DisplayEvent int event) {
- Message msg = obtainMessage(event, displayId, 0);
+ public void sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info) {
+ Message msg = obtainMessage(event, displayId, 0, info);
sendMessage(msg);
}
@@ -924,7 +927,11 @@
break;
case EVENT_DISPLAY_CHANGED:
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) {
- mListener.onDisplayChanged(msg.arg1);
+ DisplayInfo newInfo = (DisplayInfo) msg.obj;
+ if (newInfo != null && !newInfo.equals(mDisplayInfo)) {
+ mDisplayInfo.copyFrom(newInfo);
+ mListener.onDisplayChanged(msg.arg1);
+ }
}
break;
case EVENT_DISPLAY_REMOVED:
diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
index f13326b..d06bc1d 100644
--- a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
+++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
@@ -84,7 +84,6 @@
* of the result
*/
public void oneTouchPlay(OneTouchPlayCallback callback) {
- // TODO: Use PendingResult.
try {
mService.oneTouchPlay(getCallbackWrapper(callback));
} catch (RemoteException e) {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 632eb15..ec83c4e 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -772,6 +772,12 @@
return DebugUtils.flagsToString(ConnectivityManager.class, "BLOCKED_", blockedReasons);
}
+ /** @hide */
+ @NonNull
+ public static String allowedReasonsToString(int allowedReasons) {
+ return DebugUtils.flagsToString(NetworkPolicyManager.class, "ALLOWED_", allowedReasons);
+ }
+
/**
* Register a {@link NetworkPolicyCallback} to listen for changes to network blocked status
* of apps.
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 11445e9..d5cc01a 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -24,6 +24,7 @@
import android.nfc.TechListParcel;
import android.nfc.IAppCallback;
import android.nfc.INfcAdapterExtras;
+import android.nfc.INfcControllerAlwaysOnStateCallback;
import android.nfc.INfcTag;
import android.nfc.INfcCardEmulation;
import android.nfc.INfcFCardEmulation;
@@ -75,4 +76,6 @@
boolean setControllerAlwaysOn(boolean value);
boolean isControllerAlwaysOn();
boolean isControllerAlwaysOnSupported();
+ void registerControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
+ void unregisterControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
}
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
new file mode 100644
index 0000000..1e4fdd7
--- /dev/null
+++ b/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+/**
+ * @hide
+ */
+oneway interface INfcControllerAlwaysOnStateCallback {
+ /**
+ * Called whenever the controller always on state changes
+ *
+ * @param isEnabled true if the state is enabled, false otherwise
+ */
+ void onControllerAlwaysOnStateChanged(boolean isEnabled);
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index eed2c77..bbf802c 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,6 +16,7 @@
package android.nfc;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
@@ -47,6 +48,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Represents the local NFC adapter.
@@ -65,6 +67,8 @@
public final class NfcAdapter {
static final String TAG = "NFC";
+ private final NfcControllerAlwaysOnStateListener mControllerAlwaysOnStateListener;
+
/**
* Intent to start an activity when a tag with NDEF payload is discovered.
*
@@ -350,22 +354,6 @@
"android.nfc.extra.HANDOVER_TRANSFER_STATUS";
/** @hide */
- public static final String ACTION_ALWAYS_ON_STATE_CHANGED =
- "android.nfc.action.ALWAYS_ON_STATE_CHANGED";
-
- /**
- * Used as an int extra field in {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
- * intents to request the current power state. Possible values are:
- * {@link #STATE_OFF},
- * {@link #STATE_TURNING_ON},
- * {@link #STATE_ON},
- * {@link #STATE_TURNING_OFF},
- * @hide
- */
- public static final String EXTRA_ALWAYS_ON_STATE =
- "android.nfc.extra.ALWAYS_ON_STATE";
-
- /** @hide */
public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
/** @hide */
public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
@@ -430,6 +418,22 @@
}
/**
+ * A callback to be invoked when NFC controller always on state changes.
+ * <p>Register your {@code ControllerAlwaysOnStateCallback} implementation with {@link
+ * NfcAdapter#registerControllerAlwaysOnStateCallback} and disable it with {@link
+ * NfcAdapter#unregisterControllerAlwaysOnStateCallback}.
+ * @see #registerControllerAlwaysOnStateCallback
+ * @hide
+ */
+ @SystemApi
+ public interface ControllerAlwaysOnStateCallback {
+ /**
+ * Called on NFC controller always on state changes
+ */
+ void onStateChanged(boolean isEnabled);
+ }
+
+ /**
* A callback to be invoked when the system successfully delivers your {@link NdefMessage}
* to another device.
* @see #setOnNdefPushCompleteCallback
@@ -744,6 +748,7 @@
mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
mTagRemovedListener = null;
mLock = new Object();
+ mControllerAlwaysOnStateListener = new NfcControllerAlwaysOnStateListener(getService());
}
/**
@@ -2239,14 +2244,16 @@
/**
* Sets NFC controller always on feature.
* <p>This API is for the NFCC internal state management. It allows to discriminate
- * the controller function from the NFC function by keeping the NFC Controller on without
+ * the controller function from the NFC function by keeping the NFC controller on without
* any NFC RF enabled if necessary.
- * <p>This call is asynchronous. Listen for {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
- * broadcasts to find out when the operation is complete.
- * <p>If this returns true, then either NFCC is already on, or
- * a {@link #ACTION_ALWAYS_ON_STATE_CHANGED} broadcast will be sent to indicate
- * a state transition.
- * If this returns false, then there is some problem that prevents an attempt to turn NFCC on.
+ * <p>This call is asynchronous. Register a callback {@link #ControllerAlwaysOnStateCallback}
+ * by {@link #registerControllerAlwaysOnStateCallback} to find out when the operation is
+ * complete.
+ * <p>If this returns true, then either NFCC always on state has been set based on the value,
+ * or a {@link ControllerAlwaysOnStateCallback#onStateChanged(boolean)} will be invoked to
+ * indicate the state change.
+ * If this returns false, then there is some problem that prevents an attempt to turn NFCC
+ * always on.
* @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
* disabled), if false the NFCC will follow completely the Nfc adapter state.
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
@@ -2284,7 +2291,6 @@
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
* @hide
*/
-
@SystemApi
@RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
public boolean isControllerAlwaysOn() {
@@ -2313,7 +2319,6 @@
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
* @hide
*/
-
@SystemApi
@RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
public boolean isControllerAlwaysOnSupported() {
@@ -2337,4 +2342,39 @@
return false;
}
}
+
+ /**
+ * Register a {@link ControllerAlwaysOnStateCallback} to listen for NFC controller always on
+ * state changes
+ * <p>The provided callback will be invoked by the given {@link Executor}.
+ *
+ * @param executor an {@link Executor} to execute given callback
+ * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+ public void registerControllerAlwaysOnStateCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull ControllerAlwaysOnStateCallback callback) {
+ mControllerAlwaysOnStateListener.register(executor, callback);
+ }
+
+ /**
+ * Unregister the specified {@link ControllerAlwaysOnStateCallback}
+ * <p>The same {@link ControllerAlwaysOnStateCallback} object used when calling
+ * {@link #registerControllerAlwaysOnStateCallback(Executor, ControllerAlwaysOnStateCallback)}
+ * must be used.
+ *
+ * <p>Callbacks are automatically unregistered when application process goes away
+ *
+ * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+ public void unregisterControllerAlwaysOnStateCallback(
+ @NonNull ControllerAlwaysOnStateCallback callback) {
+ mControllerAlwaysOnStateListener.unregister(callback);
+ }
}
diff --git a/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java b/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java
new file mode 100644
index 0000000..69a9ec7
--- /dev/null
+++ b/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.NonNull;
+import android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public class NfcControllerAlwaysOnStateListener extends INfcControllerAlwaysOnStateCallback.Stub {
+ private static final String TAG = "NfcControllerAlwaysOnStateListener";
+
+ private final INfcAdapter mAdapter;
+
+ private final Map<ControllerAlwaysOnStateCallback, Executor> mCallbackMap = new HashMap<>();
+
+ private boolean mCurrentState = false;
+ private boolean mIsRegistered = false;
+
+ public NfcControllerAlwaysOnStateListener(@NonNull INfcAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Register a {@link ControllerAlwaysOnStateCallback} with this
+ * {@link NfcControllerAlwaysOnStateListener}
+ *
+ * @param executor an {@link Executor} to execute given callback
+ * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ */
+ public void register(@NonNull Executor executor,
+ @NonNull ControllerAlwaysOnStateCallback callback) {
+ synchronized (this) {
+ if (mCallbackMap.containsKey(callback)) {
+ return;
+ }
+
+ mCallbackMap.put(callback, executor);
+ if (!mIsRegistered) {
+ try {
+ mAdapter.registerControllerAlwaysOnStateCallback(this);
+ mIsRegistered = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to register ControllerAlwaysOnStateListener");
+ }
+ }
+ }
+ }
+
+ /**
+ * Unregister the specified {@link ControllerAlwaysOnStateCallback}
+ *
+ * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ */
+ public void unregister(@NonNull ControllerAlwaysOnStateCallback callback) {
+ synchronized (this) {
+ if (!mCallbackMap.containsKey(callback)) {
+ return;
+ }
+
+ mCallbackMap.remove(callback);
+
+ if (mCallbackMap.isEmpty() && mIsRegistered) {
+ try {
+ mAdapter.unregisterControllerAlwaysOnStateCallback(this);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to unregister ControllerAlwaysOnStateListener");
+ }
+ mIsRegistered = false;
+ }
+ }
+ }
+
+ private void sendCurrentState(@NonNull ControllerAlwaysOnStateCallback callback) {
+ synchronized (this) {
+ Executor executor = mCallbackMap.get(callback);
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onStateChanged(
+ mCurrentState));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void onControllerAlwaysOnStateChanged(boolean isEnabled) {
+ synchronized (this) {
+ mCurrentState = isEnabled;
+ for (ControllerAlwaysOnStateCallback cb : mCallbackMap.keySet()) {
+ sendCurrentState(cb);
+ }
+ }
+ }
+}
+
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index d7bb226..ba6fc6e 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -53,6 +53,11 @@
in PerUidReadTimeouts[] perUidReadTimeouts);
/**
+ * PM/system is done with this storage, ok to increase timeouts.
+ */
+ void onInstallationComplete(int storageId);
+
+ /**
* Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
*/
const int BIND_TEMPORARY = 0;
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 2a42b98..6e25968 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -205,16 +205,26 @@
/**
* Resets the states and unbinds storage instances for an installation session.
*/
- public void cleanUp() {
- if (mDefaultStorage == null) {
- return;
+ public void cleanUpAndMarkComplete() {
+ IncrementalStorage defaultStorage = cleanUp();
+ if (defaultStorage != null) {
+ defaultStorage.onInstallationComplete();
+ }
+ }
+
+ private IncrementalStorage cleanUp() {
+ IncrementalStorage defaultStorage = mDefaultStorage;
+ mInheritedStorage = null;
+ mDefaultStorage = null;
+ if (defaultStorage == null) {
+ return null;
}
try {
mIncrementalManager.unregisterLoadingProgressCallbacks(mStageDir.getAbsolutePath());
- mDefaultStorage.unBind(mStageDir.getAbsolutePath());
+ defaultStorage.unBind(mStageDir.getAbsolutePath());
} catch (IOException ignored) {
}
- mDefaultStorage = null;
+ return defaultStorage;
}
}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 7cf0144..c19e29f 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -398,7 +398,7 @@
}
/**
- * Iinitializes and starts the DataLoader.
+ * Initializes and starts the DataLoader.
* This makes sure all install-time parameters are applied.
* Does not affect persistent DataLoader params.
* @return True if start request was successfully queued.
@@ -419,6 +419,18 @@
}
}
+ /**
+ * Marks the completion of installation.
+ */
+ public void onInstallationComplete() {
+ try {
+ mService.onInstallationComplete(mId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+
private static final int UUID_BYTE_SIZE = 16;
/**
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 751e9aa..1a40f06 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -35,6 +35,7 @@
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
+import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -42,9 +43,7 @@
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.permission.SplitPermissionInfoParcelable;
-import android.location.LocationManager;
import android.media.AudioManager;
-import android.content.AttributionSource;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
@@ -52,8 +51,8 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.UserHandle;
-import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
@@ -104,6 +103,20 @@
public static final long CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS = 146211400;
/**
+ * The time to wait in between refreshing the exempted indicator role packages
+ */
+ private static final long EXEMPTED_INDICATOR_ROLE_UPDATE_FREQUENCY_MS = 15000;
+
+ private static long sLastIndicatorUpdateTime = -1;
+
+ private static final int[] EXEMPTED_ROLES = {R.string.config_systemAmbientAudioIntelligence,
+ R.string.config_systemUiIntelligence, R.string.config_systemAudioIntelligence,
+ R.string.config_systemNotificationIntelligence, R.string.config_systemTextIntelligence,
+ R.string.config_systemVisualIntelligence};
+
+ private static final String[] INDICATOR_EXEMPTED_PACKAGES = new String[EXEMPTED_ROLES.length];
+
+ /**
* Note: Changing this won't do anything on its own - you should also change the filtering in
* {@link #shouldTraceGrant}.
*
@@ -873,21 +886,31 @@
}
/**
- * Check if this package/op combination is exempted from indicators
- * @return
+ * Determine if a package should be shown in indicators. Only a select few roles, and the
+ * system app itself, are hidden. These values are updated at most every 15 seconds.
* @hide
*/
- public static boolean isSpecialCaseShownIndicator(@NonNull Context context,
+ public static boolean shouldShowPackageForIndicatorCached(@NonNull Context context,
@NonNull String packageName) {
-
- if (packageName.equals(SYSTEM_PKG)) {
+ if (SYSTEM_PKG.equals(packageName)) {
return false;
}
+ long now = SystemClock.elapsedRealtime();
+ if (sLastIndicatorUpdateTime == -1
+ || (now - sLastIndicatorUpdateTime) > EXEMPTED_INDICATOR_ROLE_UPDATE_FREQUENCY_MS) {
+ sLastIndicatorUpdateTime = now;
+ for (int i = 0; i < EXEMPTED_ROLES.length; i++) {
+ INDICATOR_EXEMPTED_PACKAGES[i] = context.getString(EXEMPTED_ROLES[i]);
+ }
+ }
+ for (int i = 0; i < EXEMPTED_ROLES.length; i++) {
+ String exemptedPackage = INDICATOR_EXEMPTED_PACKAGES[i];
+ if (exemptedPackage != null && exemptedPackage.equals(packageName)) {
+ return false;
+ }
+ }
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, "permissions_hub_2_enabled",
- false)
- || packageName.equals(context.getString(R.string.config_systemSpeechRecognizer))
- || context.getSystemService(LocationManager.class).isProviderPackage(packageName);
+ return true;
}
/**
* Gets the list of packages that have permissions that specified
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 2d6fa3c..53ba259 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -26,8 +26,6 @@
import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE;
import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
-import static android.app.AppOpsManager.opToPermission;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED;
import static android.media.AudioSystem.MODE_IN_COMMUNICATION;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
@@ -284,10 +282,6 @@
continue;
}
- if (!shouldShowPermissionsHub() && !isUserSensitive(packageName, user, op)) {
- continue;
- }
-
boolean isRunning = attrOpEntry.isRunning()
|| lastAccessTime >= runningThreshold;
@@ -302,7 +296,7 @@
OpUsage usage = new OpUsage(packageName, attributionTag, op, uid,
lastAccessTime, isRunning, proxyUsage);
- Integer packageAttr = usage.getPackageAttrHash();
+ Integer packageAttr = usage.getPackageIdHash();
if (!usages.containsKey(permGroupName)) {
ArrayMap<Integer, OpUsage> map = new ArrayMap<>();
map.put(packageAttr, usage);
@@ -342,19 +336,19 @@
}
ArrayMap<Integer, OpUsage> allUsages = new ArrayMap<>();
- // map of uid -> most recent non-proxy-related usage for that uid.
+ // map of packageName and uid hash -> most recent non-proxy-related usage for that uid.
ArrayMap<Integer, OpUsage> mostRecentUsages = new ArrayMap<>();
- // set of all uids involved in a proxy usage
- ArraySet<Integer> proxyUids = new ArraySet<>();
+ // set of all packages involved in a proxy usage
+ ArraySet<Integer> proxyPackages = new ArraySet<>();
// map of usage -> list of proxy app labels
ArrayMap<OpUsage, ArrayList<CharSequence>> proxyLabels = new ArrayMap<>();
// map of usage.proxy hash -> usage hash, telling us if a usage is a proxy
ArrayMap<Integer, OpUsage> proxies = new ArrayMap<>();
for (int i = 0; i < usages.size(); i++) {
OpUsage usage = usages.get(i);
- allUsages.put(usage.getPackageAttrHash(), usage);
+ allUsages.put(usage.getPackageIdHash(), usage);
if (usage.proxy != null) {
- proxies.put(usage.proxy.getPackageAttrHash(), usage);
+ proxies.put(usage.proxy.getPackageIdHash(), usage);
}
}
@@ -365,25 +359,27 @@
continue;
}
- int usageAttr = usage.getPackageAttrHash();
+ int usageAttr = usage.getPackageIdHash();
// If this usage has a proxy, but is not a proxy, it is the end of a chain.
if (!proxies.containsKey(usageAttr) && usage.proxy != null) {
proxyLabels.put(usage, new ArrayList<>());
- proxyUids.add(usage.uid);
+ proxyPackages.add(usage.getPackageIdHash());
}
// If this usage is not by the system, and is more recent than the next-most recent
- // for it's uid, save it.
- if (!usage.packageName.equals(SYSTEM_PKG) && (!mostRecentUsages.containsKey(usage.uid)
- || usage.lastAccessTime > mostRecentUsages.get(usage.uid).lastAccessTime)) {
- mostRecentUsages.put(usage.uid, usage);
+ // for it's uid and package name, save it.
+ int usageId = usage.getPackageIdHash();
+ OpUsage lastMostRecent = mostRecentUsages.get(usageId);
+ if (shouldShowPackage(usage.packageName) && (lastMostRecent == null
+ || usage.lastAccessTime > lastMostRecent.lastAccessTime)) {
+ mostRecentUsages.put(usageId, usage);
}
}
// get all the proxy labels
for (int numStart = 0; numStart < proxyLabels.size(); numStart++) {
OpUsage start = proxyLabels.keyAt(numStart);
- // Remove any non-proxy usage for the starting uid
- mostRecentUsages.remove(start.uid);
+ // Remove any non-proxy usage for the starting package
+ mostRecentUsages.remove(start.getPackageIdHash());
OpUsage currentUsage = proxyLabels.keyAt(numStart);
ArrayList<CharSequence> proxyLabelList = proxyLabels.get(currentUsage);
if (currentUsage == null || proxyLabelList == null) {
@@ -393,14 +389,13 @@
int maxUsages = allUsages.size();
while (currentUsage.proxy != null) {
- if (allUsages.containsKey(currentUsage.proxy.getPackageAttrHash())) {
- currentUsage = allUsages.get(currentUsage.proxy.getPackageAttrHash());
+ if (allUsages.containsKey(currentUsage.proxy.getPackageIdHash())) {
+ currentUsage = allUsages.get(currentUsage.proxy.getPackageIdHash());
} else {
// We are missing the proxy usage. This may be because it's a one-step trusted
// proxy. Check if we should show the proxy label, and show it, if so.
OpUsage proxy = currentUsage.proxy;
- if (PermissionManager.isSpecialCaseShownIndicator(mContext, proxy.packageName)
- || isUserSensitive(proxy.packageName, proxy.getUser(), proxy.op)) {
+ if (shouldShowPackage(proxy.packageName)) {
currentUsage = proxy;
// We've effectively added one usage, so increment the max number of usages
maxUsages++;
@@ -409,17 +404,16 @@
}
}
-
if (currentUsage == null || iterNum == maxUsages
- || currentUsage.getPackageAttrHash() == start.getPackageAttrHash()) {
+ || currentUsage.getPackageIdHash() == start.getPackageIdHash()) {
// We have an invalid state, or a cycle, so break
break;
}
- proxyUids.add(currentUsage.uid);
+ proxyPackages.add(currentUsage.getPackageIdHash());
// Don't add an app label for the main app, or the system app
if (!currentUsage.packageName.equals(start.packageName)
- && !currentUsage.packageName.equals(SYSTEM_PKG)) {
+ && shouldShowPackage(currentUsage.packageName)) {
try {
PackageManager userPkgManager =
getUserContext(currentUsage.getUser()).getPackageManager();
@@ -440,26 +434,17 @@
proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList));
}
- for (int uid : mostRecentUsages.keySet()) {
- if (!proxyUids.contains(uid)) {
- usagesAndLabels.put(mostRecentUsages.get(uid), null);
+ for (int packageHash : mostRecentUsages.keySet()) {
+ if (!proxyPackages.contains(packageHash)) {
+ usagesAndLabels.put(mostRecentUsages.get(packageHash), null);
}
}
return usagesAndLabels;
}
- private boolean isUserSensitive(String packageName, UserHandle user, String op) {
- if (op.equals(OPSTR_PHONE_CALL_CAMERA) || op.equals(OPSTR_PHONE_CALL_MICROPHONE)) {
- return true;
- }
-
- if (opToPermission(op) == null) {
- return false;
- }
-
- int permFlags = mPkgManager.getPermissionFlags(opToPermission(op), packageName, user);
- return (permFlags & FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0;
+ private boolean shouldShowPackage(String packageName) {
+ return PermissionManager.shouldShowPackageForIndicatorCached(mContext, packageName);
}
/**
@@ -490,8 +475,8 @@
return UserHandle.getUserHandleForUid(uid);
}
- public int getPackageAttrHash() {
- return Objects.hash(packageName, attributionTag, uid);
+ public int getPackageIdHash() {
+ return Objects.hash(packageName, uid);
}
@Override
diff --git a/core/java/android/provider/SimPhonebookContract.java b/core/java/android/provider/SimPhonebookContract.java
index 030b863..fb89eb0 100644
--- a/core/java/android/provider/SimPhonebookContract.java
+++ b/core/java/android/provider/SimPhonebookContract.java
@@ -17,13 +17,14 @@
package android.provider;
import static android.provider.SimPhonebookContract.ElementaryFiles.EF_ADN;
-import static android.provider.SimPhonebookContract.ElementaryFiles.EF_ADN_PATH_SEGMENT;
import static android.provider.SimPhonebookContract.ElementaryFiles.EF_FDN;
-import static android.provider.SimPhonebookContract.ElementaryFiles.EF_FDN_PATH_SEGMENT;
import static android.provider.SimPhonebookContract.ElementaryFiles.EF_SDN;
-import static android.provider.SimPhonebookContract.ElementaryFiles.EF_SDN_PATH_SEGMENT;
+import static android.provider.SimPhonebookContract.ElementaryFiles.PATH_SEGMENT_EF_ADN;
+import static android.provider.SimPhonebookContract.ElementaryFiles.PATH_SEGMENT_EF_FDN;
+import static android.provider.SimPhonebookContract.ElementaryFiles.PATH_SEGMENT_EF_SDN;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.WorkerThread;
@@ -78,11 +79,11 @@
public static String getEfUriPath(@ElementaryFiles.EfType int efType) {
switch (efType) {
case EF_ADN:
- return EF_ADN_PATH_SEGMENT;
+ return PATH_SEGMENT_EF_ADN;
case EF_FDN:
- return EF_FDN_PATH_SEGMENT;
+ return PATH_SEGMENT_EF_FDN;
case EF_SDN:
- return EF_SDN_PATH_SEGMENT;
+ return PATH_SEGMENT_EF_SDN;
default:
throw new IllegalArgumentException("Unsupported EfType " + efType);
}
@@ -109,9 +110,9 @@
* the phone number can contain at most {@link ElementaryFiles#PHONE_NUMBER_MAX_LENGTH}
* characters. The {@link SimRecords#NAME} column can contain at most
* {@link ElementaryFiles#NAME_MAX_LENGTH} bytes when it is encoded for storage on the SIM.
- * Encoding is done internally and so the name should be provided unencoded but the number of
- * bytes required to encode it will vary depending on the characters it contains. This length
- * can be determined by calling
+ * Encoding is done internally and so the name should be provided to these provider APIs as a
+ * Java String but the number of bytes required to encode it for storage will vary depending on
+ * the characters it contains. This length can be determined by calling
* {@link SimRecords#getEncodedNameLength(ContentResolver, String)}.
* </p>
* <h3>Operations </h3>
@@ -308,7 +309,8 @@
*/
@NonNull
public static Uri getItemUri(
- int subscriptionId, @ElementaryFiles.EfType int efType, int recordNumber) {
+ int subscriptionId, @ElementaryFiles.EfType int efType,
+ @IntRange(from = 1) int recordNumber) {
// Elementary file record indices are 1-based.
Preconditions.checkArgument(recordNumber > 0, "Invalid recordNumber");
@@ -332,6 +334,7 @@
* @see ElementaryFiles#NAME_MAX_LENGTH
*/
@WorkerThread
+ @IntRange(from = 0)
public static int getEncodedNameLength(
@NonNull ContentResolver resolver, @NonNull String name) {
Objects.requireNonNull(name);
@@ -442,12 +445,27 @@
* methods operating on this Uri will throw UnsupportedOperationException
*/
public static final int EF_SDN = 3;
- /** @hide */
- public static final String EF_ADN_PATH_SEGMENT = "adn";
- /** @hide */
- public static final String EF_FDN_PATH_SEGMENT = "fdn";
- /** @hide */
- public static final String EF_SDN_PATH_SEGMENT = "sdn";
+ /**
+ * The Uri path segment used to target the ADN elementary file for SimPhonebookProvider
+ * content operations.
+ *
+ * @hide
+ */
+ public static final String PATH_SEGMENT_EF_ADN = "adn";
+ /**
+ * The Uri path segment used to target the FDN elementary file for SimPhonebookProvider
+ * content operations.
+ *
+ * @hide
+ */
+ public static final String PATH_SEGMENT_EF_FDN = "fdn";
+ /**
+ * The Uri path segment used to target the SDN elementary file for SimPhonebookProvider
+ * content operations.
+ *
+ * @hide
+ */
+ public static final String PATH_SEGMENT_EF_SDN = "sdn";
/** The MIME type of CONTENT_URI providing a directory of ADN-like elementary files. */
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-elementary-file";
/** The MIME type of a CONTENT_URI subdirectory of a single ADN-like elementary file. */
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 38945f5..f3a8b5d 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -362,6 +362,18 @@
/**
* Used to determine the currently configured default SMS package.
+ * <p>
+ * As of Android 11 apps will need specific permission to query other packages. To use
+ * this method an app must include in their AndroidManifest:
+ * <queries>
+ * <intent>
+ * <action android:name="android.provider.Telephony.SMS_DELIVER"/>
+ * </intent>
+ * </queries>
+ * Which will allow them to query packages which declare intent filters that include
+ * the {@link android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION} intent.
+ * </p>
+ *
* @param context context of the requesting application
* @return package name for the default SMS package or null
*/
diff --git a/core/java/android/service/timezone/TimeZoneProviderService.java b/core/java/android/service/timezone/TimeZoneProviderService.java
index a9348c6..a2b22e8 100644
--- a/core/java/android/service/timezone/TimeZoneProviderService.java
+++ b/core/java/android/service/timezone/TimeZoneProviderService.java
@@ -50,35 +50,49 @@
*
* <p>Once stopped or failed, providers are required to stop generating callbacks.
*
- * <p>Provider discovery:
- *
- * <p>You must declare the service in your manifest file with the
- * {@link android.Manifest.permission#BIND_TIME_ZONE_PROVIDER_SERVICE} permission,
- * and include an intent filter with the necessary action indicating what type of provider it is.
- *
- * <p>Device configuration can influence how {@link TimeZoneProviderService}s are discovered.
- * In one mode, there can be multiple {@link TimeZoneProviderService}s configured with the same
- * action, and the one with the highest "serviceVersion" metadata will be used.
- *
- * <p>{@link TimeZoneProviderService}s may be deployed into processes that run once-per-user
- * or once-per-device (i.e. they service multiple users). The "serviceIsMultiuser" metadata must
- * be set accordingly.
- *
* <p>Provider types:
*
* <p>Android supports up to two <em>location-derived</em> time zone providers. These are called the
- * "primary" and "secondary" location time zone provider. The primary location time zone provider is
- * started first and will be used until it becomes uncertain or fails, at which point the secondary
- * provider will be started.
+ * "primary" and "secondary" location time zone providers. When a location-derived time zone is
+ * required, the primary location time zone provider is started first and used until it becomes
+ * uncertain or fails, at which point the secondary provider will be started. The secondary will be
+ * started and stopped as needed.
*
- * <p>Location-derived time zone providers are configured using {@link
- * #PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} and {@link
- * #SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} intent-filter actions respectively.
- * Besides declaring the android:permission attribute mentioned above, the application supplying a
- * location provider must be granted the {@link
+ * <p>Provider discovery:
+ *
+ * <p>Each provider is optional and can be disabled. When enabled, a provider's package name must
+ * be explicitly configured in the system server, see {@code
+ * config_primaryLocationTimeZoneProviderPackageName} and {@code
+ * config_secondaryLocationTimeZoneProviderPackageName} for details.
+ *
+ * <p>You must declare the service in the AndroidManifest of the app hosting the provider with the
+ * {@link android.Manifest.permission#BIND_TIME_ZONE_PROVIDER_SERVICE} permission,
+ * and include an intent filter with the necessary action indicating that it is the primary
+ * provider ({@link #PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE}) or the secondary
+ * provider ({@link #SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE}).
+ *
+ * <p>Besides declaring the android:permission attribute mentioned above, the application supplying
+ * a location provider must be granted the {@link
* android.Manifest.permission#INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE} permission to be
* accepted by the system server.
*
+ * <p>{@link TimeZoneProviderService}s may be deployed into processes that run once-per-user
+ * or once-per-device (i.e. they service multiple users). See serviceIsMultiuser metadata below for
+ * configuration details.
+ *
+ * <p>The service may specify metadata on its capabilities:
+ *
+ * <ul>
+ * <li>
+ * "serviceIsMultiuser": A boolean property, indicating if the service wishes to take
+ * responsibility for handling changes to the current user on the device. If true, the
+ * service will always be bound from the system user. If false, the service will always be
+ * bound from the current user. If the current user changes, the old binding will be
+ * released, and a new binding established under the new user. Assumed to be false if not
+ * specified.
+ * </li>
+ * </ul>
+ *
* <p>For example:
* <pre>
* <uses-permission
@@ -86,7 +100,7 @@
*
* ...
*
- * <service android:name=".FooTimeZoneProviderService"
+ * <service android:name=".ExampleTimeZoneProviderService"
* android:exported="true"
* android:permission="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE">
* <intent-filter>
@@ -94,7 +108,6 @@
* android:name="android.service.timezone.SecondaryLocationTimeZoneProviderService"
* />
* </intent-filter>
- * <meta-data android:name="serviceVersion" android:value="1" />
* <meta-data android:name="serviceIsMultiuser" android:value="true" />
* </service>
* </pre>
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 78e5eab..7e8622a 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -2427,9 +2427,8 @@
@Override
public void onError(String errorInfo) {
Log.w(TAG, "System TTS connection error: " + errorInfo);
- // The connection was not established successfully - handle as
- // disconnection: clear the state and notify the user.
- onServiceDisconnected(/* componentName= */ null);
+ // There is an error connecting to the engine - notify the listener.
+ dispatchOnInit(ERROR);
}
});
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 49065aa..a1ffe34 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -110,6 +110,7 @@
* @deprecated Use {@link TelephonyCallback.MessageWaitingIndicatorListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 0x00000004;
/**
@@ -123,6 +124,7 @@
* @deprecated Use {@link TelephonyCallback.CallForwardingIndicatorListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008;
/**
@@ -141,6 +143,7 @@
* @deprecated Use {@link TelephonyCallback.CellLocationListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
public static final int LISTEN_CELL_LOCATION = 0x00000010;
/**
@@ -194,7 +197,7 @@
* @see #onSignalStrengthsChanged
*
* @hide
- * @deprecated Use {@link TelephonyCallback.AlwaysReportedSignalStrengthListener}
+ * @deprecated Use TelephonyManager#setSignalStrengthUpdateRequest
* instead.
*/
@Deprecated
@@ -204,13 +207,18 @@
/**
* Listen for changes to observed cell info.
*
- * Listening to this event requires the {@link Manifest.permission#ACCESS_FINE_LOCATION}
+ * Listening to this event requires the {@link Manifest.permission#READ_PHONE_STATE} and
+ * {@link Manifest.permission#ACCESS_FINE_LOCATION}
* permission.
*
* @see #onCellInfoChanged
* @deprecated Use {@link TelephonyCallback.CellInfoListener} instead.
*/
@Deprecated
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
public static final int LISTEN_CELL_INFO = 0x00000400;
/**
@@ -261,7 +269,7 @@
*
* <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
*
- * @see #onServiceStateChanged(ServiceState)
+ * @see #onSrvccStateChanged
* @hide
* @deprecated Use {@link TelephonyCallback.SrvccStateListener} instead.
*/
@@ -376,6 +384,7 @@
* @deprecated Use {@link TelephonyCallback.ActiveDataSubscriptionIdListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 0x00400000;
/**
@@ -399,6 +408,7 @@
* @deprecated Use {@link TelephonyCallback.EmergencyNumberListListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public static final int LISTEN_EMERGENCY_NUMBER_LIST = 0x01000000;
/**
@@ -487,7 +497,10 @@
* @deprecated Use {@link TelephonyCallback.RegistrationFailedListener} instead.
*/
@Deprecated
- @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
public static final int LISTEN_REGISTRATION_FAILURE = 0x40000000;
/**
@@ -503,7 +516,10 @@
* @deprecated Use {@link TelephonyCallback.BarringInfoListener} instead.
*/
@Deprecated
- @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
public static final int LISTEN_BARRING_INFO = 0x80000000;
/*
@@ -650,6 +666,7 @@
* @deprecated Use {@link TelephonyCallback.MessageWaitingIndicatorListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public void onMessageWaitingIndicatorChanged(boolean mwi) {
// default implementation empty
}
@@ -666,6 +683,7 @@
* @deprecated Use {@link TelephonyCallback.CallForwardingIndicatorListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public void onCallForwardingIndicatorChanged(boolean cfi) {
// default implementation empty
}
@@ -682,6 +700,7 @@
* @deprecated Use {@link TelephonyCallback.CellLocationListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
public void onCellLocationChanged(CellLocation location) {
// default implementation empty
}
@@ -801,6 +820,10 @@
* @param cellInfo is the list of currently visible cells.
* @deprecated Use {@link TelephonyCallback.CellInfoListener} instead.
*/
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
@Deprecated
public void onCellInfoChanged(List<CellInfo> cellInfo) {
// default implementation empty
@@ -875,14 +898,14 @@
* subId. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
- * <p>Requires permission {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
* or the calling app has carrier privileges
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @param dataConnectionState {@link PreciseDataConnectionState}
* @deprecated Use {@link TelephonyCallback.PreciseDataConnectionStateListener} instead.
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@Deprecated
public void onPreciseDataConnectionStateChanged(
@NonNull PreciseDataConnectionState dataConnectionState) {
@@ -924,6 +947,7 @@
*/
@SystemApi
@Deprecated
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void onSrvccStateChanged(@SrvccState int srvccState) {
// default implementation empty
}
@@ -944,6 +968,7 @@
*/
@SystemApi
@Deprecated
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void onVoiceActivationStateChanged(@SimActivationState int state) {
// default implementation empty
}
@@ -1026,6 +1051,7 @@
* @deprecated Use {@link TelephonyCallback.EmergencyNumberListListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public void onEmergencyNumberListChanged(
@NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList) {
// default implementation empty
@@ -1043,6 +1069,7 @@
*/
@SystemApi
@Deprecated
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber) {
// default implementation empty
}
@@ -1068,6 +1095,7 @@
*/
@SystemApi
@Deprecated
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
int subscriptionId) {
// Default implementation for backwards compatibility
@@ -1086,6 +1114,7 @@
*/
@SystemApi
@Deprecated
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber) {
// default implementation empty
}
@@ -1158,6 +1187,7 @@
* @deprecated Use {@link TelephonyCallback.ActiveDataSubscriptionIdListener} instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public void onActiveDataSubscriptionIdChanged(int subId) {
// default implementation empty
}
@@ -1178,6 +1208,7 @@
*/
@SystemApi
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
public void onCallAttributesChanged(@NonNull CallAttributes callAttributes) {
// default implementation empty
}
@@ -1199,6 +1230,7 @@
*/
@SystemApi
@Deprecated
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void onRadioPowerStateChanged(@RadioPowerState int state) {
// default implementation empty
}
@@ -1253,6 +1285,10 @@
* @deprecated Use {@link TelephonyCallback.RegistrationFailedListener} instead.
*/
@Deprecated
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
public void onRegistrationFailed(@NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn,
int domain, int causeCode, int additionalCauseCode) {
// default implementation empty
@@ -1269,6 +1305,10 @@
* @deprecated Use {@link TelephonyCallback.BarringInfoListener} instead.
*/
@Deprecated
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
public void onBarringInfoChanged(@NonNull BarringInfo barringInfo) {
// default implementation empty
}
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index 1ab6e0f..1a25c8b 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -218,10 +218,9 @@
* even in some situations such as the screen of the device is off.
*
* @hide
- * @see AlwaysReportedSignalStrengthListener#onSignalStrengthsChanged
+ * @see TelephonyManager#setSignalStrengthUpdateRequest
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10;
/**
@@ -231,8 +230,10 @@
* @see CellInfoListener#onCellInfoChanged
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
- public static final int EVENT_CELL_INFO_CHANGED = 11;
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ }) public static final int EVENT_CELL_INFO_CHANGED = 11;
/**
* Event for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
@@ -369,9 +370,10 @@
/**
* Event for changes to active data subscription ID. Active data subscription is
- * the current subscription used to setup Cellular Internet data. For example,
- * it could be the current active opportunistic subscription in use, or the
- * subscription user selected as default data subscription in DSDS mode.
+ * the current subscription used to setup Cellular Internet data. The data is only active on the
+ * subscription at a time, even it is multi-SIM mode. For example, it could be the current
+ * active opportunistic subscription in use, or the subscription user selected as default data
+ * subscription in DSDS mode.
*
* <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
* app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
@@ -668,8 +670,7 @@
* @see ServiceState#STATE_OUT_OF_SERVICE
* @see ServiceState#STATE_POWER_OFF
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onServiceStateChanged(@NonNull ServiceState serviceState);
+ void onServiceStateChanged(@NonNull ServiceState serviceState);
}
/**
@@ -687,7 +688,7 @@
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onMessageWaitingIndicatorChanged(boolean mwi);
+ void onMessageWaitingIndicatorChanged(boolean mwi);
}
/**
@@ -706,7 +707,7 @@
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onCallForwardingIndicatorChanged(boolean cfi);
+ void onCallForwardingIndicatorChanged(boolean cfi);
}
/**
@@ -724,7 +725,7 @@
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
- public void onCellLocationChanged(@NonNull CellLocation location);
+ void onCellLocationChanged(@NonNull CellLocation location);
}
/**
@@ -753,7 +754,7 @@
* @param state the current call state
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onCallStateChanged(@Annotation.CallState int state);
+ void onCallStateChanged(@Annotation.CallState int state);
}
/**
@@ -777,9 +778,8 @@
* @see TelephonyManager#DATA_CONNECTED
* @see TelephonyManager#DATA_SUSPENDED
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onDataConnectionStateChanged(@TelephonyManager.DataState int state,
- @Annotation.NetworkType int networkType);
+ void onDataConnectionStateChanged(@TelephonyManager.DataState int state,
+ @Annotation.NetworkType int networkType);
}
/**
@@ -802,8 +802,7 @@
* @see TelephonyManager#DATA_ACTIVITY_INOUT
* @see TelephonyManager#DATA_ACTIVITY_DORMANT
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onDataActivity(@Annotation.DataActivityType int direction);
+ void onDataActivity(@Annotation.DataActivityType int direction);
}
/**
@@ -820,27 +819,7 @@
* subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
- }
-
- /**
- * Interface for network signal strengths callback which always reported from modem.
- */
- public interface AlwaysReportedSignalStrengthListener {
- /**
- * Callback always invoked from modem when network signal strengths changes on the
- * registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers TelephonyCallback by
- * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- */
- @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
- public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
+ void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
}
/**
@@ -860,8 +839,11 @@
*
* @param cellInfo is the list of currently visible cells.
*/
- @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
- public void onCellInfoChanged(@NonNull List<CellInfo> cellInfo);
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
+ void onCellInfoChanged(@NonNull List<CellInfo> cellInfo);
}
/**
@@ -884,7 +866,7 @@
* @param callState {@link PreciseCallState}
*/
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onPreciseCallStateChanged(@NonNull PreciseCallState callState);
+ void onPreciseCallStateChanged(@NonNull PreciseCallState callState);
}
/**
@@ -905,8 +887,8 @@
* @param preciseDisconnectCause {@link PreciseDisconnectCause}.
*/
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onCallDisconnectCauseChanged(@Annotation.DisconnectCauses int disconnectCause,
- @Annotation.PreciseDisconnectCauses int preciseDisconnectCause);
+ void onCallDisconnectCauseChanged(@Annotation.DisconnectCauses int disconnectCause,
+ @Annotation.PreciseDisconnectCauses int preciseDisconnectCause);
}
/**
@@ -926,7 +908,7 @@
* @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
*/
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo);
+ void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo);
}
/**
@@ -952,7 +934,7 @@
* @param dataConnectionState {@link PreciseDataConnectionState}
*/
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onPreciseDataConnectionStateChanged(
+ void onPreciseDataConnectionStateChanged(
@NonNull PreciseDataConnectionState dataConnectionState);
}
@@ -976,7 +958,7 @@
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void onSrvccStateChanged(@Annotation.SrvccState int srvccState);
+ void onSrvccStateChanged(@Annotation.SrvccState int srvccState);
}
/**
@@ -1000,7 +982,7 @@
* @param state is the current SIM voice activation state
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void onVoiceActivationStateChanged(@Annotation.SimActivationState int state);
+ void onVoiceActivationStateChanged(@Annotation.SimActivationState int state);
}
@@ -1021,8 +1003,7 @@
*
* @param state is the current SIM data activation state
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onDataActivationStateChanged(@Annotation.SimActivationState int state);
+ void onDataActivationStateChanged(@Annotation.SimActivationState int state);
}
/**
@@ -1043,8 +1024,7 @@
* @param enabled indicates whether the current user mobile data state is enabled or
* disabled.
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onUserMobileDataStateChanged(boolean enabled);
+ void onUserMobileDataStateChanged(boolean enabled);
}
/**
@@ -1058,7 +1038,7 @@
*
* @param telephonyDisplayInfo The display information.
*/
- public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo);
+ void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo);
}
/**
@@ -1089,8 +1069,8 @@
* empty.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onEmergencyNumberListChanged(
- @NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList);
+ void onEmergencyNumberListChanged(@NonNull Map<Integer,
+ List<EmergencyNumber>> emergencyNumberList);
}
/**
@@ -1118,8 +1098,8 @@
* {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
*/
@RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
- public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
- int subscriptionId);
+ void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+ int subscriptionId);
}
/**
@@ -1139,8 +1119,8 @@
* @param subscriptionId The subscription ID used to send the emergency sms.
*/
@RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
- public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber,
- int subscriptionId);
+ void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber,
+ int subscriptionId);
}
/**
@@ -1156,8 +1136,7 @@
*
* @param capability the new phone capability
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability);
+ void onPhoneCapabilityChanged(@NonNull PhoneCapability capability);
}
/**
@@ -1168,13 +1147,14 @@
* Callback invoked when active data subscription ID changes.
* Note, this callback triggers regardless of registered subscription.
*
- * @param subId current subscription used to setup Cellular Internet data.
+ * @param subId current subscription used to setup Cellular Internet data. The data is
+ * only active on the subscription at a time, even it is multi-SIM mode.
* For example, it could be the current active opportunistic subscription
* in use, or the subscription user selected as default data subscription in
* DSDS mode.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onActiveDataSubscriptionIdChanged(int subId);
+ void onActiveDataSubscriptionIdChanged(int subId);
}
/**
@@ -1197,7 +1177,7 @@
* @param state the modem radio power state
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void onRadioPowerStateChanged(@Annotation.RadioPowerState int state);
+ void onRadioPowerStateChanged(@Annotation.RadioPowerState int state);
}
/**
@@ -1221,7 +1201,7 @@
* @param active If the carrier network change is or shortly will be active,
* {@code true} indicate that showing alternative UI, {@code false} otherwise.
*/
- public void onCarrierNetworkChange(boolean active);
+ void onCarrierNetworkChange(boolean active);
}
/**
@@ -1263,9 +1243,8 @@
Manifest.permission.READ_PRECISE_PHONE_STATE,
Manifest.permission.ACCESS_FINE_LOCATION
})
- public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
- @NonNull String chosenPlmn, @NetworkRegistrationInfo.Domain int domain, int causeCode,
- int additionalCauseCode);
+ void onRegistrationFailed(@NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn,
+ @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode);
}
/**
@@ -1303,8 +1282,7 @@
* long type value}.
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- void onAllowedNetworkTypesChanged(
- @TelephonyManager.AllowedNetworkTypesReason int reason,
+ void onAllowedNetworkTypesChanged(@TelephonyManager.AllowedNetworkTypesReason int reason,
@TelephonyManager.NetworkTypeBitMask long allowedNetworkType);
}
@@ -1348,7 +1326,7 @@
Manifest.permission.READ_PRECISE_PHONE_STATE,
Manifest.permission.ACCESS_FINE_LOCATION
})
- public void onBarringInfoChanged(@NonNull BarringInfo barringInfo);
+ void onBarringInfoChanged(@NonNull BarringInfo barringInfo);
}
/**
@@ -1361,7 +1339,7 @@
* @param configs List of the current {@link PhysicalChannelConfig}s
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs);
+ void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs);
}
/**
@@ -1379,8 +1357,7 @@
* See {@link TelephonyManager.DataEnabledReason}.
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onDataEnabledChanged(boolean enabled,
- @TelephonyManager.DataEnabledReason int reason);
+ void onDataEnabledChanged(boolean enabled, @TelephonyManager.DataEnabledReason int reason);
}
/**
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 1ec12fe..340fa40 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -894,10 +894,6 @@
eventList.add(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED);
}
- if (telephonyCallback instanceof TelephonyCallback.AlwaysReportedSignalStrengthListener) {
- eventList.add(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
- }
-
if (telephonyCallback instanceof TelephonyCallback.CellInfoListener) {
eventList.add(TelephonyCallback.EVENT_CELL_INFO_CHANGED);
}
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index 78c4739..117d75e 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -16,15 +16,9 @@
package android.util;
-import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.Formatter;
-import java.util.Locale;
-
/**
* API for sending log output to the {@link Log#LOG_ID_SYSTEM} buffer.
*
@@ -34,12 +28,6 @@
*/
public final class Slog {
- @GuardedBy("Slog.class")
- private static StringBuilder sMessageBuilder;
-
- @GuardedBy("Slog.class")
- private static Formatter sFormatter;
-
private Slog() {
}
@@ -53,24 +41,6 @@
msg + '\n' + Log.getStackTraceString(tr));
}
- /**
- * Logs a {@link Log.VERBOSE} message.
- *
- * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
- * enabled for the given {@code tag}, but the compiler will still create an intermediate array
- * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're
- * calling this method in a critical path, make sure to explicitly do the check before calling
- * it.
- *
- * @deprecated use {@code com.android.server.utils.SLogF} instead.
- */
- @Deprecated
- public static void v(String tag, String format, @Nullable Object... args) {
- if (!Log.isLoggable(tag, Log.VERBOSE)) return;
-
- v(tag, getMessage(format, args));
- }
-
@UnsupportedAppUsage
public static int d(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg);
@@ -82,24 +52,6 @@
msg + '\n' + Log.getStackTraceString(tr));
}
- /**
- * Logs a {@link Log.DEBUG} message.
- *
- * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
- * enabled for the given {@code tag}, but the compiler will still create an intermediate array
- * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're
- * calling this method in a critical path, make sure to explicitly do the check before calling
- * it.
- *
- * @deprecated use {@code com.android.server.utils.SLogF} instead.
- */
- @Deprecated
- public static void d(String tag, String format, @Nullable Object... args) {
- if (!Log.isLoggable(tag, Log.DEBUG)) return;
-
- d(tag, getMessage(format, args));
- }
-
@UnsupportedAppUsage
public static int i(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, msg);
@@ -110,24 +62,6 @@
msg + '\n' + Log.getStackTraceString(tr));
}
- /**
- * Logs a {@link Log.INFO} message.
- *
- * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
- * enabled for the given {@code tag}, but the compiler will still create an intermediate array
- * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're
- * calling this method in a critical path, make sure to explicitly do the check before calling
- * it.
- *
- * @deprecated use {@code com.android.server.utils.SLogF} instead.
- */
- @Deprecated
- public static void i(String tag, String format, @Nullable Object... args) {
- if (!Log.isLoggable(tag, Log.INFO)) return;
-
- i(tag, getMessage(format, args));
- }
-
@UnsupportedAppUsage
public static int w(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, msg);
@@ -143,42 +77,6 @@
return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, Log.getStackTraceString(tr));
}
- /**
- * Logs a {@link Log.WARN} message.
- *
- * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
- * enabled for the given {@code tag}, but the compiler will still create an intermediate array
- * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're
- * calling this method in a critical path, make sure to explicitly do the check before calling
- * it.
- *
- * @deprecated use {@code com.android.server.utils.SLogF} instead.
- */
- @Deprecated
- public static void w(String tag, String format, @Nullable Object... args) {
- if (!Log.isLoggable(tag, Log.WARN)) return;
-
- w(tag, getMessage(format, args));
- }
-
- /**
- * Logs a {@link Log.WARN} message with an exception
- *
- * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
- * enabled for the given {@code tag}, but the compiler will still create an intermediate array
- * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're
- * calling this method in a critical path, make sure to explicitly do the check before calling
- * it.
- *
- * @deprecated use {@code com.android.server.utils.SLogF} instead.
- */
- @Deprecated
- public static void w(String tag, Exception exception, String format, @Nullable Object... args) {
- if (!Log.isLoggable(tag, Log.WARN)) return;
-
- w(tag, getMessage(format, args), exception);
- }
-
@UnsupportedAppUsage
public static int e(String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, msg);
@@ -191,42 +89,6 @@
}
/**
- * Logs a {@link Log.ERROR} message.
- *
- * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
- * enabled for the given {@code tag}, but the compiler will still create an intermediate array
- * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're
- * calling this method in a critical path, make sure to explicitly do the check before calling
- * it.
- *
- * @deprecated use {@code com.android.server.utils.SLogF} instead.
- */
- @Deprecated
- public static void e(String tag, String format, @Nullable Object... args) {
- if (!Log.isLoggable(tag, Log.ERROR)) return;
-
- e(tag, getMessage(format, args));
- }
-
- /**
- * Logs a {@link Log.ERROR} message with an exception
- *
- * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
- * enabled for the given {@code tag}, but the compiler will still create an intermediate array
- * of the objects for the {@code vargars}, which could affect garbage collection. So, if you're
- * calling this method in a critical path, make sure to explicitly do the check before calling
- * it.
- *
- * @deprecated use {@code com.android.server.utils.SLogF} instead.
- */
- @Deprecated
- public static void e(String tag, Exception exception, String format, @Nullable Object... args) {
- if (!Log.isLoggable(tag, Log.ERROR)) return;
-
- e(tag, getMessage(format, args), exception);
- }
-
- /**
* Like {@link Log#wtf(String, String)}, but will never cause the caller to crash, and
* will always be handled asynchronously. Primarily for use by coding running within
* the system process.
@@ -237,27 +99,6 @@
}
/**
- * Logs a {@code wtf} message.
- *
- * @deprecated use {@code com.android.server.utils.SLogF} instead.
- */
- @Deprecated
- public static void wtf(String tag, String format, @Nullable Object... args) {
- wtf(tag, getMessage(format, args));
- }
-
- /**
- * Logs a {@code wtf} message with an exception.
- *
- * @deprecated use {@code com.android.server.utils.SLogF} instead.
- */
- @Deprecated
- public static void wtf(String tag, Exception exception, String format,
- @Nullable Object... args) {
- wtf(tag, getMessage(format, args), exception);
- }
-
- /**
* Like {@link #wtf(String, String)}, but does not output anything to the log.
*/
public static void wtfQuiet(String tag, String msg) {
@@ -297,18 +138,4 @@
public static int println(int priority, String tag, String msg) {
return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg);
}
-
- private static String getMessage(String format, @Nullable Object... args) {
- synchronized (Slog.class) {
- if (sMessageBuilder == null) {
- // Lazy load so they're not created if not used by the process
- sMessageBuilder = new StringBuilder();
- sFormatter = new Formatter(sMessageBuilder, Locale.ENGLISH);
- }
- sFormatter.format(format, args);
- String message = sMessageBuilder.toString();
- sMessageBuilder.setLength(0);
- return message;
- }
- }
}
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index 2a9bbdf..9856553 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -60,6 +60,7 @@
*
* @return error of distance measurement in meters
*/
+ @FloatRange(from = 0.0)
public double getErrorMeters() {
return mErrorMeters;
}
@@ -162,7 +163,7 @@
* @throws IllegalArgumentException if error is negative or NaN
*/
@NonNull
- public Builder setErrorMeters(double errorMeters) {
+ public Builder setErrorMeters(@FloatRange(from = 0.0) double errorMeters) {
if (Double.isNaN(errorMeters) || errorMeters < 0.0) {
throw new IllegalArgumentException(
"errorMeters must be >= 0.0 and not NaN: " + errorMeters);
@@ -178,7 +179,8 @@
* @throws IllegalArgumentException if confidence level is not in the range of [0.0, 1.0]
*/
@NonNull
- public Builder setConfidenceLevel(double confidenceLevel) {
+ public Builder setConfidenceLevel(
+ @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
throw new IllegalArgumentException(
"confidenceLevel must be in the range [0.0, 1.0]: " + confidenceLevel);
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index 4036892..30da248 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -160,14 +160,4 @@
* closed.
*/
const int RANGING_SESSION_CLOSE_THRESHOLD_MS = 3000; // Value TBD
-
- /**
- * Ranging scheduling time unit (RSTU) for High Rate Pulse (HRP) PHY
- */
- const int HIGH_RATE_PULSE_CHIRPS_PER_RSTU = 416;
-
- /**
- * Ranging scheduling time unit (RSTU) for Low Rate Pulse (LRP) PHY
- */
- const int LOW_RATE_PULSE_CHIRPS_PER_RSTU = 1;
}
diff --git a/core/java/android/uwb/IUwbRangingCallbacks.aidl b/core/java/android/uwb/IUwbRangingCallbacks.aidl
index f71f3ff..f15debb 100644
--- a/core/java/android/uwb/IUwbRangingCallbacks.aidl
+++ b/core/java/android/uwb/IUwbRangingCallbacks.aidl
@@ -92,9 +92,13 @@
* Called when the ranging session has been stopped
*
* @param sessionHandle the session the callback is being invoked for
+ * @param reason the reason the session was stopped
+ * @param parameters protocol specific parameters
*/
- void onRangingStopped(in SessionHandle sessionHandle);
+ void onRangingStopped(in SessionHandle sessionHandle,
+ RangingChangeReason reason,
+ in PersistableBundle parameters);
/**
* Called when a ranging session fails to stop
diff --git a/core/java/android/uwb/RangingManager.java b/core/java/android/uwb/RangingManager.java
index 5c7f0f5..ff8b912 100644
--- a/core/java/android/uwb/RangingManager.java
+++ b/core/java/android/uwb/RangingManager.java
@@ -171,7 +171,8 @@
}
@Override
- public void onRangingStopped(SessionHandle sessionHandle) {
+ public void onRangingStopped(SessionHandle sessionHandle, @RangingChangeReason int reason,
+ PersistableBundle params) {
synchronized (this) {
if (!hasSession(sessionHandle)) {
Log.w(TAG, "onRangingStopped - received unexpected SessionHandle: "
@@ -180,7 +181,7 @@
}
RangingSession session = mRangingSessionTable.get(sessionHandle);
- session.onRangingStopped();
+ session.onRangingStopped(convertToReason(reason), params);
}
}
diff --git a/core/java/android/uwb/RangingSession.java b/core/java/android/uwb/RangingSession.java
index 52ec5bd..345b69d 100644
--- a/core/java/android/uwb/RangingSession.java
+++ b/core/java/android/uwb/RangingSession.java
@@ -191,8 +191,11 @@
/**
* Invoked when a request to stop the session succeeds
+ *
+ * @param reason reason for the session stop
+ * @param parameters protocol specific parameters related to the stop reason
*/
- void onStopped();
+ void onStopped(@Reason int reason, @NonNull PersistableBundle parameters);
/**
* Invoked when a request to stop the session fails
@@ -434,14 +437,15 @@
/**
* @hide
*/
- public void onRangingStopped() {
+ public void onRangingStopped(@Callback.Reason int reason,
+ @NonNull PersistableBundle params) {
if (mState == State.CLOSED) {
Log.w(TAG, "onRangingStopped invoked for a closed session");
return;
}
mState = State.IDLE;
- executeCallback(() -> mCallback.onStopped());
+ executeCallback(() -> mCallback.onStopped(reason, params));
}
/**
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 36be9f8..8e5f905 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -377,7 +377,7 @@
&& ownerUid == other.ownerUid
&& Objects.equals(ownerPackageName, other.ownerPackageName)
&& removeMode == other.removeMode
- && refreshRateOverride == other.refreshRateOverride
+ && getRefreshRate() == other.getRefreshRate()
&& brightnessMinimum == other.brightnessMinimum
&& brightnessMaximum == other.brightnessMaximum
&& brightnessDefault == other.brightnessDefault
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c001ec9..c201e3b 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1131,7 +1131,7 @@
continue;
}
final InsetsSourceControl control = consumer.getControl();
- if (control != null) {
+ if (control != null && control.getLeash() != null) {
controls.put(consumer.getType(), new InsetsSourceControl(control));
typesReady |= toPublicType(consumer.getType());
} else if (animationType == ANIMATION_TYPE_SHOW) {
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index bc50dbe..8e50fed 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -33,6 +33,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.util.Log;
import android.util.imetracing.ImeTracing;
@@ -240,10 +241,6 @@
mHasWindowFocus = false;
}
- boolean hasWindowFocus() {
- return mHasWindowFocus;
- }
-
boolean hasViewFocusWhenWindowFocusGain() {
return mHasViewFocusWhenWindowFocusGain;
}
@@ -366,7 +363,16 @@
protected void setRequestedVisible(boolean requestedVisible) {
if (mRequestedVisible != requestedVisible) {
mRequestedVisible = requestedVisible;
- mIsAnimationPending = false;
+
+ // We need an animation later if the leash of a real control (which has an insets hint)
+ // is not ready. The !mIsAnimationPending check is in case that the requested visibility
+ // is changed twice before playing the animation -- we don't need an animation in this
+ // case.
+ mIsAnimationPending = !mIsAnimationPending
+ && mSourceControl != null
+ && mSourceControl.getLeash() == null
+ && !Insets.NONE.equals(mSourceControl.getInsetsHint());
+
mController.onRequestedVisibilityChanged(this);
if (DEBUG) Log.d(TAG, "setRequestedVisible: " + requestedVisible);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 82106b0..2b96a14 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -33,7 +33,6 @@
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RenderNode;
@@ -670,10 +669,16 @@
if (mClipSurfaceToBounds && mClipBounds != null) {
mTmpRect.intersect(mClipBounds);
}
- canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
- mCornerRadius, mCornerRadius, mRoundedViewportPaint);
+ canvas.punchHole(
+ mTmpRect.left,
+ mTmpRect.top,
+ mTmpRect.right,
+ mTmpRect.bottom,
+ mCornerRadius,
+ mCornerRadius
+ );
} else {
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+ canvas.punchHole(0f, 0f, getWidth(), getHeight(), 0f, 0f);
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index ab46170..1c15bbc 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -627,7 +627,7 @@
/**
* Integer argument specifying the end index of the requested text location data. Must be
- * positive.
+ * positive and no larger than {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}.
*
* @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
*/
@@ -635,6 +635,11 @@
"android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
/**
+ * The maximum allowed length of the requested text location data.
+ */
+ public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000;
+
+ /**
* Key used to request extra data for the rendering information.
* The key requests that a {@link AccessibilityNodeInfo.ExtraRenderingInfo} be added to this
* info. This request is made with {@link #refreshWithExtraData(String, Bundle)} without
@@ -1038,6 +1043,14 @@
* recycled).
*/
public boolean refreshWithExtraData(String extraDataKey, Bundle args) {
+ // limits the text location length to make sure the rectangle array allocation avoids
+ // the binder transaction failure and OOM crash.
+ if (args.getInt(EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH, -1)
+ > EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH) {
+ args.putInt(EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH,
+ EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH);
+ }
+
args.putString(EXTRA_DATA_REQUESTED_KEY, extraDataKey);
return refresh(args, true);
}
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
index d0ab004..1cb6825 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
@@ -60,4 +60,11 @@
*/
void onPerformScaleAction(int displayId, float scale);
+ /**
+ * Called when the accessibility action is performed.
+ *
+ * @param displayId The logical display id.
+ */
+ void onAccessibilityActionPerformed(int displayId);
+
}
diff --git a/core/java/android/view/translation/TranslationResponse.java b/core/java/android/view/translation/TranslationResponse.java
index 35040f1..f9b7012 100644
--- a/core/java/android/view/translation/TranslationResponse.java
+++ b/core/java/android/view/translation/TranslationResponse.java
@@ -78,6 +78,13 @@
abstract static class BaseBuilder {
/**
+ * @deprecated Use {@link Builder#Builder(int)}.
+ * @hide
+ */
+ @Deprecated
+ public abstract Builder setTranslationStatus(@TranslationStatus int value);
+
+ /**
* Adds {@link TranslationResponseValue} to be translated. The input
* TranslationResponseValue format should match those provided by the
* {@link android.view.translation.Translator}'s destSpec.
@@ -137,7 +144,7 @@
- // Code below generated by codegen v1.0.22.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -362,6 +369,8 @@
* The translation result status code.
*/
@DataClass.Generated.Member
+ @Override
+ @Deprecated
public @NonNull Builder setTranslationStatus(@TranslationStatus int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
@@ -438,10 +447,10 @@
}
@DataClass.Generated(
- time = 1616189850232L,
- codegenVersion = "1.0.22",
+ time = 1617218030666L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponse.java",
- inputSignatures = "public static final int TRANSLATION_STATUS_SUCCESS\npublic static final int TRANSLATION_STATUS_UNKNOWN_ERROR\npublic static final int TRANSLATION_STATUS_CONTEXT_UNSUPPORTED\nprivate final @android.view.translation.TranslationResponse.TranslationStatus int mTranslationStatus\nprivate final @android.annotation.NonNull android.util.SparseArray<android.view.translation.TranslationResponseValue> mTranslationResponseValues\nprivate final @android.annotation.NonNull android.util.SparseArray<android.view.translation.ViewTranslationResponse> mViewTranslationResponses\nprivate final boolean mFinalResponse\nprivate static android.util.SparseArray<android.view.translation.TranslationResponseValue> defaultTranslationResponseValues()\nprivate static android.util.SparseArray<android.view.translation.ViewTranslationResponse> defaultViewTranslationResponses()\nprivate static boolean defaultFinalResponse()\nclass TranslationResponse extends java.lang.Object implements [android.os.Parcelable]\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int,android.view.translation.TranslationResponseValue)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int,android.view.translation.ViewTranslationResponse)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genHiddenConstDefs=true)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int,android.view.translation.TranslationResponseValue)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int,android.view.translation.ViewTranslationResponse)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "public static final int TRANSLATION_STATUS_SUCCESS\npublic static final int TRANSLATION_STATUS_UNKNOWN_ERROR\npublic static final int TRANSLATION_STATUS_CONTEXT_UNSUPPORTED\nprivate final @android.view.translation.TranslationResponse.TranslationStatus int mTranslationStatus\nprivate final @android.annotation.NonNull android.util.SparseArray<android.view.translation.TranslationResponseValue> mTranslationResponseValues\nprivate final @android.annotation.NonNull android.util.SparseArray<android.view.translation.ViewTranslationResponse> mViewTranslationResponses\nprivate final boolean mFinalResponse\nprivate static android.util.SparseArray<android.view.translation.TranslationResponseValue> defaultTranslationResponseValues()\nprivate static android.util.SparseArray<android.view.translation.ViewTranslationResponse> defaultViewTranslationResponses()\nprivate static boolean defaultFinalResponse()\nclass TranslationResponse extends java.lang.Object implements [android.os.Parcelable]\npublic abstract @java.lang.Deprecated android.view.translation.TranslationResponse.Builder setTranslationStatus(int)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int,android.view.translation.TranslationResponseValue)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int,android.view.translation.ViewTranslationResponse)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genHiddenConstDefs=true)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationResponse.Builder setTranslationStatus(int)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int,android.view.translation.TranslationResponseValue)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int,android.view.translation.ViewTranslationResponse)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 29c78b5..f49aa74 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3263,16 +3263,14 @@
/**
* Create a new RemoteViews object that will display the views contained
- * in the specified layout file.
+ * in the specified layout file and change the id of the root view to the specified one.
*
- * @param packageName Name of the package that contains the layout resource.
- * @param userId The user under which the package is running.
- * @param layoutId The id of the layout resource.
- *
- * @hide
+ * @param packageName Name of the package that contains the layout resource
+ * @param layoutId The id of the layout resource
*/
- public RemoteViews(String packageName, int userId, @LayoutRes int layoutId) {
- this(getApplicationInfo(packageName, userId), layoutId);
+ public RemoteViews(@NonNull String packageName, @LayoutRes int layoutId, @IdRes int viewId) {
+ this(packageName, layoutId);
+ this.mViewId = viewId;
}
/**
@@ -3727,7 +3725,7 @@
* The {@code stableId} will be used to identify a potential view to recycled when the remote
* view is inflated. Views can be re-used if inserted in the same order, potentially with
* some views appearing / disappearing. To be recycled the view must not change the layout
- * used to inflate it or its view id (see {@link RemoteViews#setViewId}).
+ * used to inflate it or its view id (see {@link RemoteViews#RemoteViews(String, int, int)}).
*
* Note: if a view is re-used, all the actions will be re-applied on it. However, its properties
* are not reset, so what was applied in previous round will have an effect. As a view may be
@@ -6340,25 +6338,9 @@
}
/**
- * Set the ID of the top-level view of the XML layout.
- *
- * The view's ID is changed right after inflation, before it gets added to its parent. The ID
- * of a given view can never change after the initial inflation.
- *
- * Set to {@link View#NO_ID} to reset and simply keep the id defined in the XML layout.
- *
- * @throws UnsupportedOperationException if the method is called on a RemoteViews defined in
- * term of other RemoteViews (e.g. {@link #RemoteViews(RemoteViews, RemoteViews)}).
+ * Get the ID of the top-level view of the XML layout, if set using
+ * {@link RemoteViews#RemoteViews(String, int, int)}.
*/
- public void setViewId(@IdRes int viewId) {
- if (hasMultipleLayouts()) {
- throw new UnsupportedOperationException(
- "The viewId can only be set on RemoteViews defined from a XML layout.");
- }
- mViewId = viewId;
- }
-
- /** Get the ID of the top-level view of the XML layout, as set by {@link #setViewId}. */
public @IdRes int getViewId() {
return mViewId;
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index fffeb02..5a5e745 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -116,7 +116,6 @@
KeyphraseMetadata getEnrolledKeyphraseMetadata(String keyphrase, String bcp47Locale);
/**
* @return the component name for the currently active voice interaction service
- * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
*/
ComponentName getActiveServiceComponentName();
diff --git a/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java b/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java
index 7bd7acf..1fc126e 100644
--- a/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java
+++ b/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java
@@ -24,7 +24,9 @@
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
+import android.graphics.Path;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.graphics.Xfermode;
import android.graphics.drawable.Drawable;
import android.view.animation.DecelerateInterpolator;
@@ -44,6 +46,9 @@
private int mMainColor;
private ValueAnimator mColorAnimation;
private int mMainColorTo;
+ private float mCornerRadius;
+ private Rect mBounds;
+ private ConcaveInfo mConcaveInfo;
public ScrimDrawable() {
mPaint = new Paint();
@@ -127,15 +132,67 @@
return PixelFormat.TRANSLUCENT;
}
+ /**
+ * Enable drawable shape to have rounded corners with provided radius
+ */
+ public void setRoundedCorners(float radius) {
+ mCornerRadius = radius;
+ }
+
+ /**
+ * Make bottom edge concave with provided corner radius
+ */
+ public void setBottomEdgeConcave(float radius) {
+ // only rounding top corners for clip out path
+ float[] cornerRadii = new float[]{radius, radius, radius, radius, 0, 0, 0, 0};
+ mConcaveInfo = new ConcaveInfo(radius, cornerRadii);
+ }
+
@Override
public void draw(@NonNull Canvas canvas) {
mPaint.setColor(mMainColor);
mPaint.setAlpha(mAlpha);
- canvas.drawRect(getBounds(), mPaint);
+ if (mConcaveInfo != null) {
+ drawConcave(canvas);
+ }
+ canvas.drawRoundRect(getBounds().left, getBounds().top, getBounds().right,
+ getBounds().bottom + mCornerRadius,
+ /* x radius*/ mCornerRadius, /* y radius*/ mCornerRadius, mPaint);
+ }
+
+ private void drawConcave(Canvas canvas) {
+ // checking if width of clip out path needs to change
+ if (mBounds == null
+ || getBounds().right != mBounds.right
+ || getBounds().left != mBounds.left) {
+ mConcaveInfo.mPath.reset();
+ float left = getBounds().left;
+ float right = getBounds().right;
+ float top = 0f;
+ float bottom = mConcaveInfo.mPathOverlap;
+ mConcaveInfo.mPath.addRoundRect(left, top, right, bottom,
+ mConcaveInfo.mCornerRadii, Path.Direction.CW);
+ }
+ mBounds = getBounds();
+ int translation = (int) (mBounds.bottom - mConcaveInfo.mPathOverlap);
+ canvas.translate(0, translation);
+ canvas.clipOutPath(mConcaveInfo.mPath);
+ canvas.translate(0, -translation);
}
@VisibleForTesting
public int getMainColor() {
return mMainColor;
}
+
+ private static class ConcaveInfo {
+ private final float mPathOverlap;
+ private final float[] mCornerRadii;
+ private final Path mPath = new Path();
+
+ ConcaveInfo(float pathOverlap, float[] cornerRadii) {
+ mPathOverlap = pathOverlap;
+ mCornerRadii = cornerRadii;
+ }
+ }
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 98c75b9..1000914 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -18,6 +18,7 @@
import android.annotation.AnyThread;
import android.annotation.DrawableRes;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Uri;
import android.os.IBinder;
@@ -28,6 +29,8 @@
import com.android.internal.annotations.GuardedBy;
+import java.util.Objects;
+
/**
* A utility class to take care of boilerplate code around IPCs.
*/
@@ -47,7 +50,7 @@
* @param privOps Binder interface to be set
*/
@AnyThread
- public synchronized void set(IInputMethodPrivilegedOperations privOps) {
+ public synchronized void set(@NonNull IInputMethodPrivilegedOperations privOps) {
if (mPrivOps != null) {
throw new IllegalStateException(
"IInputMethodPrivilegedOperations must be set at most once."
@@ -90,7 +93,8 @@
* @param privOps Binder interface to be set
*/
@AnyThread
- public void set(IInputMethodPrivilegedOperations privOps) {
+ public void set(@NonNull IInputMethodPrivilegedOperations privOps) {
+ Objects.requireNonNull(privOps, "privOps must not be null");
mOps.set(privOps);
}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 594a1a7..135c076 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -27,6 +27,7 @@
import static com.android.internal.jank.InteractionJankMonitor.ACTION_METRICS_LOGGED;
import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_BEGIN;
import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_CANCEL;
+import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_END;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -215,7 +216,7 @@
mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl);
}
if (mListener != null) {
- mListener.onNotifyCujEvents(mSession, ACTION_SESSION_BEGIN);
+ mListener.onCujEvents(mSession, ACTION_SESSION_BEGIN);
}
}
@@ -240,7 +241,9 @@
}
Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
mSession.setReason(reason);
- InteractionJankMonitor.getInstance().removeTimeout(mSession.getCuj());
+ if (mListener != null) {
+ mListener.onCujEvents(mSession, ACTION_SESSION_END);
+ }
}
// We don't remove observer here,
// will remove it when all the frame metrics in this duration are called back.
@@ -269,7 +272,7 @@
// Notify the listener the session has been cancelled.
// We don't notify the listeners if the session never begun.
if (mListener != null) {
- mListener.onNotifyCujEvents(mSession, ACTION_SESSION_CANCEL);
+ mListener.onCujEvents(mSession, ACTION_SESSION_CANCEL);
}
}
@@ -445,7 +448,7 @@
maxFrameTimeNanos,
missedSfFramesCounts);
if (mListener != null) {
- mListener.onNotifyCujEvents(mSession, ACTION_METRICS_LOGGED);
+ mListener.onCujEvents(mSession, ACTION_METRICS_LOGGED);
}
}
if (DEBUG) {
@@ -587,6 +590,6 @@
* @param session the CUJ session
* @param action the specific action
*/
- void onNotifyCujEvents(Session session, String action);
+ void onCujEvents(Session session, String action);
}
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 6c56d42..5ab2a82 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -19,7 +19,9 @@
import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY;
import static com.android.internal.jank.FrameTracker.ChoreographerWrapper;
+import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL;
import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NOT_BEGUN;
+import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
@@ -100,6 +102,7 @@
private static final int DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS = 64;
public static final String ACTION_SESSION_BEGIN = ACTION_PREFIX + ".ACTION_SESSION_BEGIN";
+ public static final String ACTION_SESSION_END = ACTION_PREFIX + ".ACTION_SESSION_END";
public static final String ACTION_SESSION_CANCEL = ACTION_PREFIX + ".ACTION_SESSION_CANCEL";
public static final String ACTION_METRICS_LOGGED = ACTION_PREFIX + ".ACTION_METRICS_LOGGED";
public static final String BUNDLE_KEY_CUJ_NAME = ACTION_PREFIX + ".CUJ_NAME";
@@ -275,10 +278,7 @@
public FrameTracker createFrameTracker(View v, Session session) {
final Context c = v.getContext().getApplicationContext();
synchronized (this) {
- boolean needListener = SystemProperties.getBoolean(PROP_NOTIFY_CUJ_EVENT, false);
- FrameTrackerListener eventsListener =
- !needListener ? null : (s, act) -> notifyEvents(c, act, s);
-
+ FrameTrackerListener eventsListener = (s, act) -> handleCujEvents(c, act, s);
return new FrameTracker(session, mWorker.getThreadHandler(),
new ThreadedRendererWrapper(v.getThreadedRenderer()),
new ViewRootWrapper(v.getViewRootImpl()), new SurfaceControlWrapper(),
@@ -287,6 +287,28 @@
}
}
+ private void handleCujEvents(Context context, String action, Session session) {
+ // Clear the running and timeout tasks if the end / cancel was fired within the tracker.
+ // Or we might have memory leaks.
+ if (needRemoveTasks(action, session)) {
+ removeTimeout(session.getCuj());
+ removeTracker(session.getCuj());
+ }
+
+ // Notify the receivers if necessary.
+ if (session.shouldNotify()) {
+ notifyEvents(context, action, session);
+ }
+ }
+
+ private boolean needRemoveTasks(String action, Session session) {
+ final boolean badEnd = action.equals(ACTION_SESSION_END)
+ && session.getReason() != REASON_END_NORMAL;
+ final boolean badCancel = action.equals(ACTION_SESSION_CANCEL)
+ && session.getReason() != REASON_CANCEL_NORMAL;
+ return badEnd || badCancel;
+ }
+
private void notifyEvents(Context context, String action, Session session) {
if (action.equals(ACTION_SESSION_CANCEL)
&& session.getReason() == REASON_CANCEL_NOT_BEGUN) {
@@ -299,7 +321,7 @@
context.sendBroadcast(intent);
}
- void removeTimeout(@CujType int cujType) {
+ private void removeTimeout(@CujType int cujType) {
synchronized (this) {
Runnable timeout = mTimeoutActions.get(cujType);
if (timeout != null) {
@@ -371,7 +393,7 @@
// Skip this call since we haven't started a trace yet.
if (tracker == null) return false;
tracker.end(FrameTracker.REASON_END_NORMAL);
- mRunningTrackers.remove(cujType);
+ removeTracker(cujType);
return true;
}
}
@@ -390,7 +412,7 @@
// Skip this call since we haven't started a trace yet.
if (tracker == null) return false;
tracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
- mRunningTrackers.remove(cujType);
+ removeTracker(cujType);
return true;
}
}
@@ -401,6 +423,12 @@
}
}
+ private void removeTracker(@CujType int cuj) {
+ synchronized (this) {
+ mRunningTrackers.remove(cuj);
+ }
+ }
+
private void updateProperties(DeviceConfig.Properties properties) {
synchronized (this) {
mSamplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY,
@@ -516,9 +544,11 @@
private long mTimeStamp;
@FrameTracker.Reasons
private int mReason = FrameTracker.REASON_END_UNKNOWN;
+ private boolean mShouldNotify;
public Session(@CujType int cujType) {
mCujType = cujType;
+ mShouldNotify = SystemProperties.getBoolean(PROP_NOTIFY_CUJ_EVENT, false);
}
@CujType
@@ -558,5 +588,10 @@
public int getReason() {
return mReason;
}
+
+ /** Determine if should notify the receivers of cuj events */
+ public boolean shouldNotify() {
+ return mShouldNotify;
+ }
}
}
diff --git a/core/java/com/android/internal/os/BINDER_OWNERS b/core/java/com/android/internal/os/BINDER_OWNERS
new file mode 100644
index 0000000..9f68a32
--- /dev/null
+++ b/core/java/com/android/internal/os/BINDER_OWNERS
@@ -0,0 +1,2 @@
+dplotnikov@google.com
+gaillard@google.com
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 3f01ebb..ea3b3a7 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -1,6 +1,7 @@
per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
per-file *Zygote* = file:/ZYGOTE_OWNERS
per-file *Cpu* = file:CPU_OWNERS
+per-file *Binder* = file:BINDER_OWNERS
# BatteryStats
per-file BatterySipper.java = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 654b461..d16d9c6 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -95,4 +95,5 @@
boolean hasSecureLockScreen();
boolean tryUnlockWithCachedUnifiedChallenge(int userId);
void removeCachedUnifiedChallenge(int userId);
+ void updateEncryptionPassword(int type, in byte[] password);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a161f18..a0e50be 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -34,7 +34,6 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.UserInfo;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -59,18 +58,13 @@
import com.google.android.collect.Lists;
-import libcore.util.HexEncoding;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-import java.util.StringJoiner;
/**
* Utilities for the lock pattern and its settings.
@@ -186,7 +180,7 @@
public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle";
public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp";
public static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
- private static final String HISTORY_DELIMITER = ",";
+ public static final String PASSWORD_HISTORY_DELIMITER = ",";
@UnsupportedAppUsage
private final Context mContext;
@@ -559,9 +553,11 @@
if(passwordHistoryLength == 0) {
return false;
}
- String legacyHash = legacyPasswordToHash(passwordToCheck, userId);
- String passwordHash = passwordToHistoryHash(passwordToCheck, hashFactor, userId);
- String[] history = passwordHistory.split(HISTORY_DELIMITER);
+ byte[] salt = getSalt(userId).getBytes();
+ String legacyHash = LockscreenCredential.legacyPasswordToHash(passwordToCheck, salt);
+ String passwordHash = LockscreenCredential.passwordToHistoryHash(
+ passwordToCheck, salt, hashFactor);
+ String[] history = passwordHistory.split(PASSWORD_HISTORY_DELIMITER);
// Password History may be too long...
for (int i = 0; i < Math.min(passwordHistoryLength, history.length); i++) {
if (history[i].equals(legacyHash) || history[i].equals(passwordHash)) {
@@ -701,20 +697,9 @@
} catch (RemoteException e) {
throw new RuntimeException("Unable to save lock password", e);
}
-
- onPostPasswordChanged(newCredential, userHandle);
return true;
}
- private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) {
- updateEncryptionPasswordIfNeeded(newCredential, userHandle);
- if (newCredential.isPattern()) {
- reportPatternWasChosen(userHandle);
- }
- updatePasswordHistory(newCredential, userHandle);
- reportEnabledTrustAgentsChanged(userHandle);
- }
-
private void updateCryptoUserInfo(int userId) {
if (userId != UserHandle.USER_SYSTEM) {
return;
@@ -781,100 +766,6 @@
return getDeviceOwnerInfo() != null;
}
- /** Update the encryption password if it is enabled **/
- private void updateEncryptionPassword(final int type, final byte[] password) {
- if (!hasSecureLockScreen() && password != null && password.length != 0) {
- throw new UnsupportedOperationException(
- "This operation requires the lock screen feature.");
- }
- if (!isDeviceEncryptionEnabled()) {
- return;
- }
- final IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- Log.e(TAG, "Could not find the mount service to update the encryption password");
- return;
- }
-
- // TODO(b/120484642): This is a location where we still use a String for vold
- String passwordString = password != null ? new String(password) : null;
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... dummy) {
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- try {
- storageManager.changeEncryptionPassword(type, passwordString);
- } catch (RemoteException e) {
- Log.e(TAG, "Error changing encryption password", e);
- }
- return null;
- }
- }.execute();
- }
-
- /**
- * Update device encryption password if calling user is USER_SYSTEM and device supports
- * encryption.
- */
- private void updateEncryptionPasswordIfNeeded(LockscreenCredential credential, int userHandle) {
- // Update the device encryption password.
- if (userHandle != UserHandle.USER_SYSTEM || !isDeviceEncryptionEnabled()) {
- return;
- }
- if (!shouldEncryptWithCredentials(true)) {
- updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
- return;
- }
- if (credential.isNone()) {
- // Set the encryption password to default.
- setCredentialRequiredToDecrypt(false);
- }
- updateEncryptionPassword(credential.getStorageCryptType(), credential.getCredential());
- }
-
- /**
- * Store the hash of the *current* password in the password history list, if device policy
- * enforces password history requirement.
- */
- private void updatePasswordHistory(LockscreenCredential password, int userHandle) {
- if (password.isNone()) {
- return;
- }
- if (password.isPattern()) {
- // Do not keep track of historical patterns
- return;
- }
- // Add the password to the password history. We assume all
- // password hashes have the same length for simplicity of implementation.
- String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
- if (passwordHistory == null) {
- passwordHistory = "";
- }
- int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
- if (passwordHistoryLength == 0) {
- passwordHistory = "";
- } else {
- final byte[] hashFactor = getPasswordHistoryHashFactor(password, userHandle);
- String hash = passwordToHistoryHash(password.getCredential(), hashFactor, userHandle);
- if (hash == null) {
- Log.e(TAG, "Compute new style password hash failed, fallback to legacy style");
- hash = legacyPasswordToHash(password.getCredential(), userHandle);
- }
- if (TextUtils.isEmpty(passwordHistory)) {
- passwordHistory = hash;
- } else {
- String[] history = passwordHistory.split(HISTORY_DELIMITER);
- StringJoiner joiner = new StringJoiner(HISTORY_DELIMITER);
- joiner.add(hash);
- for (int i = 0; i < passwordHistoryLength - 1 && i < history.length; i++) {
- joiner.add(history[i]);
- }
- passwordHistory = joiner.toString();
- }
- }
- setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
- }
-
/**
* Determine if the device supports encryption, even if it's set to default. This
* differs from isDeviceEncrypted() in that it returns true even if the device is
@@ -898,7 +789,11 @@
* Clears the encryption password.
*/
public void clearEncryptionPassword() {
- updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+ try {
+ getLockSettings().updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't clear encryption password");
+ }
}
/**
@@ -1045,56 +940,9 @@
* @param password the gesture pattern.
*
* @return the hash of the pattern in a byte array.
- * TODO: move to LockscreenCredential class
*/
public String legacyPasswordToHash(byte[] password, int userId) {
- if (password == null || password.length == 0) {
- return null;
- }
-
- try {
- // Previously the password was passed as a String with the following code:
- // byte[] saltedPassword = (password + getSalt(userId)).getBytes();
- // The code below creates the identical digest preimage using byte arrays:
- byte[] salt = getSalt(userId).getBytes();
- byte[] saltedPassword = Arrays.copyOf(password, password.length + salt.length);
- System.arraycopy(salt, 0, saltedPassword, password.length, salt.length);
- byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
- byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
-
- byte[] combined = new byte[sha1.length + md5.length];
- System.arraycopy(sha1, 0, combined, 0, sha1.length);
- System.arraycopy(md5, 0, combined, sha1.length, md5.length);
-
- final char[] hexEncoded = HexEncoding.encode(combined);
- Arrays.fill(saltedPassword, (byte) 0);
- return new String(hexEncoded);
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError("Missing digest algorithm: ", e);
- }
- }
-
- /**
- * Hash the password for password history check purpose.
- * TODO: move to LockscreenCredential class
- */
- private String passwordToHistoryHash(byte[] passwordToHash, byte[] hashFactor, int userId) {
- if (passwordToHash == null || passwordToHash.length == 0 || hashFactor == null) {
- return null;
- }
- try {
- MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
- sha256.update(hashFactor);
- byte[] salt = getSalt(userId).getBytes();
- byte[] saltedPassword = Arrays.copyOf(passwordToHash, passwordToHash.length
- + salt.length);
- System.arraycopy(salt, 0, saltedPassword, passwordToHash.length, salt.length);
- sha256.update(saltedPassword);
- Arrays.fill(saltedPassword, (byte) 0);
- return new String(HexEncoding.encode(sha256.digest()));
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError("Missing digest algorithm: ", e);
- }
+ return LockscreenCredential.legacyPasswordToHash(password, getSalt(userId).getBytes());
}
/**
@@ -1396,14 +1244,6 @@
}
}
- private boolean isDoNotAskCredentialsOnBootSet() {
- return getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
- }
-
- private boolean shouldEncryptWithCredentials(boolean defaultValue) {
- return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
- }
-
private void throwIfCalledOnMainThread() {
if (Looper.getMainLooper().isCurrentThread()) {
throw new IllegalStateException("should not be called from the main thread.");
@@ -1590,12 +1430,7 @@
credential.checkLength();
LockSettingsInternal localService = getLockSettingsInternal();
- if (!localService.setLockCredentialWithToken(credential, tokenHandle, token, userHandle)) {
- return false;
- }
-
- onPostPasswordChanged(credential, userHandle);
- return true;
+ return localService.setLockCredentialWithToken(credential, tokenHandle, token, userHandle);
}
/**
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index a488449..361ba95 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -31,6 +31,10 @@
import com.android.internal.util.Preconditions;
+import libcore.util.HexEncoding;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -276,6 +280,82 @@
return getType() == storedCredentialType;
}
+ /**
+ * Hash the password for password history check purpose.
+ */
+ public String passwordToHistoryHash(byte[] salt, byte[] hashFactor) {
+ return passwordToHistoryHash(mCredential, salt, hashFactor);
+ }
+
+ /**
+ * Hash the password for password history check purpose.
+ */
+ public static String passwordToHistoryHash(
+ byte[] passwordToHash, byte[] salt, byte[] hashFactor) {
+ if (passwordToHash == null || passwordToHash.length == 0
+ || hashFactor == null || salt == null) {
+ return null;
+ }
+ try {
+ MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
+ sha256.update(hashFactor);
+ byte[] saltedPassword = Arrays.copyOf(passwordToHash, passwordToHash.length
+ + salt.length);
+ System.arraycopy(salt, 0, saltedPassword, passwordToHash.length, salt.length);
+ sha256.update(saltedPassword);
+ Arrays.fill(saltedPassword, (byte) 0);
+ return new String(HexEncoding.encode(sha256.digest()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError("Missing digest algorithm: ", e);
+ }
+ }
+
+ /**
+ * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
+ * Not the most secure, but it is at least a second level of protection. First level is that
+ * the file is in a location only readable by the system process.
+ *
+ * @return the hash of the pattern in a byte array.
+ */
+ public String legacyPasswordToHash(byte[] salt) {
+ return legacyPasswordToHash(mCredential, salt);
+ }
+
+ /**
+ * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
+ * Not the most secure, but it is at least a second level of protection. First level is that
+ * the file is in a location only readable by the system process.
+ *
+ * @param password the gesture pattern.
+ *
+ * @return the hash of the pattern in a byte array.
+ */
+ public static String legacyPasswordToHash(byte[] password, byte[] salt) {
+ if (password == null || password.length == 0 || salt == null) {
+ return null;
+ }
+
+ try {
+ // Previously the password was passed as a String with the following code:
+ // byte[] saltedPassword = (password + salt).getBytes();
+ // The code below creates the identical digest preimage using byte arrays:
+ byte[] saltedPassword = Arrays.copyOf(password, password.length + salt.length);
+ System.arraycopy(salt, 0, saltedPassword, password.length, salt.length);
+ byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
+ byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
+
+ byte[] combined = new byte[sha1.length + md5.length];
+ System.arraycopy(sha1, 0, combined, 0, sha1.length);
+ System.arraycopy(md5, 0, combined, sha1.length, md5.length);
+
+ final char[] hexEncoded = HexEncoding.encode(combined);
+ Arrays.fill(saltedPassword, (byte) 0);
+ return new String(hexEncoded);
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError("Missing digest algorithm: ", e);
+ }
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 5630a1e..7fde92c 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -45,6 +45,7 @@
#define ENCODING_MPEGH_BL_L4 24
#define ENCODING_MPEGH_LC_L3 25
#define ENCODING_MPEGH_LC_L4 26
+#define ENCODING_DTS_UHD 27
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -110,6 +111,8 @@
return AUDIO_FORMAT_MPEGH_LC_L3;
case ENCODING_MPEGH_LC_L4:
return AUDIO_FORMAT_MPEGH_LC_L4;
+ case ENCODING_DTS_UHD:
+ return AUDIO_FORMAT_DTS_UHD;
default:
return AUDIO_FORMAT_INVALID;
}
@@ -179,6 +182,8 @@
return ENCODING_MPEGH_LC_L3;
case AUDIO_FORMAT_MPEGH_LC_L4:
return ENCODING_MPEGH_LC_L4;
+ case AUDIO_FORMAT_DTS_UHD:
+ return ENCODING_DTS_UHD;
case AUDIO_FORMAT_DEFAULT:
return ENCODING_DEFAULT;
default:
diff --git a/core/proto/android/app/activitymanager.proto b/core/proto/android/app/activitymanager.proto
index ead7e16..a21d1d4 100644
--- a/core/proto/android/app/activitymanager.proto
+++ b/core/proto/android/app/activitymanager.proto
@@ -33,4 +33,6 @@
UID_OBSERVER_FLAG_ACTIVE = 4;
// report uid cached state has changed, original value is 1 << 4
UID_OBSERVER_FLAG_CACHED = 5;
+ // report uid capability has changed, original value is 1 << 5
+ UID_OBSERVER_FLAG_CAPABILITY = 6;
}
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 74a37ca..17dc4589 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -778,6 +778,7 @@
CHANGE_ACTIVE = 2;
CHANGE_CACHED = 3;
CHANGE_UNCACHED = 4;
+ CHANGE_CAPABILITY = 5;
}
repeated Change last_reported_changes = 8;
optional int32 num_procs = 9;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 83e6c4b..58abfeb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -326,7 +326,6 @@
<protected-broadcast android:name="android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
- <protected-broadcast android:name="android.nfc.action.ALWAYS_ON_STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" />
<protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
<protected-broadcast android:name="android.nfc.action.REQUIRE_UNLOCK_FOR_NFC" />
@@ -346,7 +345,7 @@
<protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
<protected-broadcast android:name="com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER" />
- <protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
+ <protected-broadcast android:name="android.net.action.CLEAR_DNS_CACHE" />
<protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
<protected-broadcast android:name="android.os.UpdateLock.UPDATE_LOCK_CHANGED" />
@@ -1391,7 +1390,7 @@
<!-- Required to be able to discover and connect to nearby Bluetooth devices.
<p>Protection level: dangerous -->
<permission-group android:name="android.permission-group.NEARBY_DEVICES"
- android:icon="@drawable/ic_qs_bluetooth"
+ android:icon="@drawable/perm_group_nearby_devices"
android:label="@string/permgrouplab_nearby_devices"
android:description="@string/permgroupdesc_nearby_devices"
android:priority="750" />
@@ -4241,6 +4240,15 @@
<permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
android:protectionLevel="signature|installer" />
+ <!-- @SystemApi Allows an application to bypass role qualification. This allows switching role
+ holders to otherwise non eligible holders. Only the shell is allowed to do this, the
+ qualification for the shell role itself cannot be bypassed, and each role needs to
+ explicitly allow bypassing qualification in its definition. The bypass state will not be
+ persisted across reboot.
+ @hide -->
+ <permission android:name="android.permission.BYPASS_ROLE_QUALIFICATION"
+ android:protectionLevel="internal|role" />
+
<!-- @SystemApi Allows an application to observe role holder changes.
@hide -->
<permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"
@@ -4258,6 +4266,7 @@
android:protectionLevel="normal" />
<!-- Allows an application to create new companion device associations.
+ @SystemApi
@hide -->
<permission android:name="android.permission.ASSOCIATE_COMPANION_DEVICES"
android:protectionLevel="internal|role" />
diff --git a/core/res/res/drawable/perm_group_nearby_devices.xml b/core/res/res/drawable/perm_group_nearby_devices.xml
new file mode 100644
index 0000000..84cc432
--- /dev/null
+++ b/core/res/res/drawable/perm_group_nearby_devices.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="#000000"
+ android:pathData="M12,16.427L7.574,12 12,7.574 16.426,12zM10.58,2.59l-8,8c-0.78,0.78 -0.78,2.05 0,2.83l8,8c0.78,0.78 2.05,0.78 2.83,0l8,-8c0.78,-0.78 0.78,-2.05 0,-2.83l-8,-8c-0.78,-0.79 -2.04,-0.79 -2.83,0zM13.39,17.81L12,19.2l-1.39,-1.39 -4.42,-4.42L4.8,12l1.39,-1.39 4.42,-4.42L12,4.8l1.39,1.39 4.42,4.42L19.2,12l-1.39,1.39 -4.42,4.42z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 986bb82..c51b2d8 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1867,16 +1867,21 @@
-->
<attr name="preserveLegacyExternalStorage" format="boolean" />
- <!-- If {@code true} this app would like optimized external storage access.
+ <!-- If {@code true} this app would like raw external storage access.
<p> This flag can only be used by apps holding
<ul>
<li>{@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission or
<li>{@link android.app.role}#SYSTEM_GALLERY role.
</ul>
- When the flag is set, bulk file path operations will be optimized.
+ <p> When the flag is set, all file path access on external storage will bypass database
+ operations that update MediaStore collection. Raw external storage access as a side effect
+ can improve performance of bulk file path operations but can cause unexpected behavior in
+ apps due to inconsistencies in MediaStore collection and lower file system.
+ When the flag is set, app should scan the file after file path operations to ensure
+ consistency of MediaStore collection.
- The default value is {@code true} if
+ <p> The default value is {@code true} if
<ul>
<li>app has {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission and
targets targetSDK<=30.
@@ -1884,7 +1889,7 @@
</ul>
{@code false} otherwise.
-->
- <attr name="requestOptimizedExternalStorageAccess" format="boolean" />
+ <attr name="requestRawExternalStorageAccess" format="boolean" />
<!-- If {@code true} this app declares that it should be visible to all other apps on
device, regardless of what they declare via the {@code queries} tags in their
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fc2bdf3..142d923 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1637,32 +1637,22 @@
config_timeZoneRulesUpdateTrackingEnabled are true.] -->
<integer name="config_timeZoneRulesCheckRetryCount">5</integer>
- <!-- Whether the geolocation time zone detection feature is enabled. -->
+ <!-- Whether the geolocation time zone detection feature is enabled. Setting this to false means
+ the feature cannot be used. Setting this to true means it may be used if other
+ configuration allows (see provider configuration below, also compile time overlays). -->
<bool name="config_enableGeolocationTimeZoneDetection" translatable="false">true</bool>
- <!-- Whether the primary LocationTimeZoneProvider is enabled device.
+ <!-- Whether the primary LocationTimeZoneProvider is enabled.
Ignored if config_enableGeolocationTimeZoneDetection is false -->
<bool name="config_enablePrimaryLocationTimeZoneProvider" translatable="false">false</bool>
- <!-- Used when enablePrimaryLocationTimeZoneProvider is true. Controls whether to enable primary
- location time zone provider overlay which allows the primary location time zone provider to
- be replaced by an app at run-time. When disabled, only the
- config_primaryLocationTimeZoneProviderPackageName package will be searched for the primary
- location time zone provider, otherwise any system package is eligible. Anyone who wants to
- disable the runtime overlay mechanism can set it to false. -->
- <bool name="config_enablePrimaryLocationTimeZoneOverlay" translatable="false">false</bool>
- <!-- Package name providing the primary location time zone provider. Used only when
- config_enablePrimaryLocationTimeZoneOverlay is false. -->
+ <!-- The package name providing the primary location time zone provider.
+ Only used when config_enableGeolocationTimeZoneDetection and
+ enablePrimaryLocationTimeZoneProvider are true. -->
<string name="config_primaryLocationTimeZoneProviderPackageName" translatable="false">@null</string>
- <!-- Whether the secondary LocationTimeZoneProvider is enabled device.
+ <!-- Whether the secondary LocationTimeZoneProvider is enabled.
Ignored if config_enableGeolocationTimeZoneDetection is false -->
<bool name="config_enableSecondaryLocationTimeZoneProvider" translatable="false">true</bool>
- <!-- Used when enableSecondaryLocationTimeZoneProvider is true. Controls whether to enable
- secondary location time zone provider overlay which allows the primary location time zone
- provider to config_secondaryLocationTimeZoneProviderPackageName package will be searched
- for the secondary location time zone provider, otherwise any system package is eligible.
- Anyone who wants to disable the runtime overlay mechanism can set it to false. -->
- <bool name="config_enableSecondaryLocationTimeZoneOverlay" translatable="false">false</bool>
<!-- Package name providing the secondary location time zone provider. Used only when
config_enableSecondaryLocationTimeZoneOverlay is false.
@@ -1942,11 +1932,13 @@
<!-- The name of the package that will hold the speech recognizer role by default. -->
<string name="config_systemSpeechRecognizer" translatable="false"></string>
<!-- The name of the package that will hold the system Wi-Fi coex manager role. -->
- <string name="config_systemWifiCoexManager" translateable="false"></string>
+ <string name="config_systemWifiCoexManager" translatable="false"></string>
<!-- The name of the package that will hold the wellbeing role. -->
<string name="config_systemWellbeing" translatable="false"></string>
<!-- The name of the package that will hold the television notification handler role -->
<string name="config_systemTelevisionNotificationHandler" translatable="false"></string>
+ <!-- The name of the package that will hold the system activity recognizer role. -->
+ <string name="config_systemActivityRecognizer" translatable="false"></string>
<!-- The name of the package that will be allowed to change its components' label/icon. -->
<string name="config_overrideComponentUiPackage" translatable="false"></string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b402c95..3a5621b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3092,7 +3092,7 @@
<public name="attributionTags"/>
<public name="suppressesSpellChecker" />
<public name="usesPermissionFlags" />
- <public name="requestOptimizedExternalStorageAccess" />
+ <public name="requestRawExternalStorageAccess" />
<!-- @hide @SystemApi -->
<public name="playHomeTransitionSound" />
<public name="lStar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 61e766e..90e9c09 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -823,9 +823,9 @@
<string name="permgroupdesc_camera">take pictures and record video</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
- <string name="permgrouplab_nearby_devices">Nearby Bluetooth Devices</string>
+ <string name="permgrouplab_nearby_devices">Nearby devices</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
- <string name="permgroupdesc_nearby_devices">discover and connect to nearby Bluetooth devices</string>
+ <string name="permgroupdesc_nearby_devices">discover and connect to nearby devices</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_calllog">Call logs</string>
@@ -1486,9 +1486,9 @@
<string name="permdesc_bluetooth_connect" product="default">Allows the app to connect to paired Bluetooth devices</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50]-->
- <string name="permlab_uwb_ranging">range to devices using ultra-wideband</string>
+ <string name="permlab_uwb_ranging">determine relative position between nearby Ultra-Wideband devices</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]-->
- <string name="permdesc_uwb_ranging" product="default">Allows the app to range to devices using ultra-wideband</string>
+ <string name="permdesc_uwb_ranging">Allow the app to determine relative position between nearby Ultra-Wideband devices</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_preferredPaymentInfo">Preferred NFC Payment Service Information</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eb1fe1d..408620a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2180,10 +2180,8 @@
<java-symbol type="bool" name="config_enableGnssTimeUpdateService" />
<java-symbol type="bool" name="config_enableGeolocationTimeZoneDetection" />
<java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneProvider" />
- <java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" />
<java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
<java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneProvider" />
- <java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneOverlay" />
<java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" />
<java-symbol type="layout" name="resolver_list" />
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index dd60dd4..1a63660 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -44,8 +44,6 @@
import com.android.bandwidthtest.NetworkState.StateTransitionDirection;
import com.android.internal.util.AsyncChannel;
-import junit.framework.Assert;
-
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.List;
@@ -76,7 +74,11 @@
private WifiManager mWifiManager;
private Context mContext;
// Verify connectivity state
- private static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
+ // ConnectivityManager.TYPE_* is deprecated and no longer extended, so use the max public
+ // network type - TYPE_VPN should be enough.
+ // TODO: Replace registering CONNECTIVITY_ACTION with registering NetworkCallback and check
+ // network by NetworkCapabilities.TRANSPORT_* and NetworkCapabilities.hasTransport() instead.
+ private static final int NUM_NETWORK_TYPES = ConnectivityManager.TYPE_VPN + 1;
private NetworkState[] mConnectivityState = new NetworkState[NUM_NETWORK_TYPES];
public ConnectionUtil(Context context) {
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index f47fa39..4dbdc60 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -531,7 +531,7 @@
}
@Override
- public void scheduleCrash(String s) throws RemoteException {
+ public void scheduleCrash(String s, int i) throws RemoteException {
}
@Override
diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS
index fa1aa5e..74cdd21 100644
--- a/core/tests/coretests/src/android/view/OWNERS
+++ b/core/tests/coretests/src/android/view/OWNERS
@@ -1,3 +1,6 @@
+# Accessibility
+per-file WindowInfoTest.java = file:/services/accessibility/OWNERS
+
# Input
per-file *MotionEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
per-file *KeyEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
@@ -9,6 +12,7 @@
per-file *Insets* = file:/services/core/java/com/android/server/wm/OWNERS
per-file *View* = file:/services/core/java/com/android/server/wm/OWNERS
per-file *Visibility* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Window* = file:/services/core/java/com/android/server/wm/OWNERS
# Scroll Capture
per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java b/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
index 05bab1c..9d77d16 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
@@ -17,6 +17,8 @@
package com.android.internal.widget;
+import static com.google.common.truth.Truth.assertThat;
+
import android.test.AndroidTestCase;
import java.util.Arrays;
@@ -175,6 +177,81 @@
assertEquals(credential, credential.duplicate());
}
+ public void testPasswordToHistoryHash() {
+ String password = "1234";
+ LockscreenCredential credential = LockscreenCredential.createPassword(password);
+ String hashFactor = "6637D20C0798382D9F1304861C81DE222BC6CB7183623C67DA99B115A7AF702D";
+ String salt = "6d5331dd120077a0";
+ String expectedHash = "BCFB17409F2CD0A00D8627F76D080FB547B0B6A30CB7A375A34720D2312EDAC7";
+
+ assertThat(
+ credential.passwordToHistoryHash(salt.getBytes(), hashFactor.getBytes()))
+ .isEqualTo(expectedHash);
+ assertThat(
+ LockscreenCredential.passwordToHistoryHash(
+ password.getBytes(), salt.getBytes(), hashFactor.getBytes()))
+ .isEqualTo(expectedHash);
+ }
+
+ public void testPasswordToHistoryHashInvalidInput() {
+ String password = "1234";
+ LockscreenCredential credential = LockscreenCredential.createPassword(password);
+ String hashFactor = "6637D20C0798382D9F1304861C81DE222BC6CB7183623C67DA99B115A7AF702D";
+ String salt = "6d5331dd120077a0";
+
+ assertThat(
+ credential.passwordToHistoryHash(/* salt= */ null, hashFactor.getBytes()))
+ .isNull();
+ assertThat(
+ LockscreenCredential.passwordToHistoryHash(
+ password.getBytes(), /* salt= */ null, hashFactor.getBytes()))
+ .isNull();
+
+ assertThat(
+ credential.passwordToHistoryHash(salt.getBytes(), /* hashFactor= */ null))
+ .isNull();
+ assertThat(
+ LockscreenCredential.passwordToHistoryHash(
+ password.getBytes(), salt.getBytes(), /* hashFactor= */ null))
+ .isNull();
+
+ assertThat(
+ LockscreenCredential.passwordToHistoryHash(
+ /* password= */ null, salt.getBytes(), hashFactor.getBytes()))
+ .isNull();
+ }
+
+ public void testLegacyPasswordToHash() {
+ String password = "1234";
+ LockscreenCredential credential = LockscreenCredential.createPassword(password);
+ String salt = "6d5331dd120077a0";
+ String expectedHash =
+ "2DD04348ADBF8F4CABD7F722DC2E2887FAD4B6020A0C3E02C831E09946F0554FDC13B155";
+
+ assertThat(
+ credential.legacyPasswordToHash(salt.getBytes()))
+ .isEqualTo(expectedHash);
+ assertThat(
+ LockscreenCredential.legacyPasswordToHash(
+ password.getBytes(), salt.getBytes()))
+ .isEqualTo(expectedHash);
+ }
+
+ public void testLegacyPasswordToHashInvalidInput() {
+ String password = "1234";
+ LockscreenCredential credential = LockscreenCredential.createPassword(password);
+ String salt = "6d5331dd120077a0";
+
+ assertThat(credential.legacyPasswordToHash(/* salt= */ null)).isNull();
+ assertThat(LockscreenCredential.legacyPasswordToHash(
+ password.getBytes(), /* salt= */ null)).isNull();
+
+ assertThat(
+ LockscreenCredential.legacyPasswordToHash(
+ /* password= */ null, salt.getBytes()))
+ .isNull();
+ }
+
private LockscreenCredential createPattern(String patternString) {
return LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern(
patternString.getBytes()));
diff --git a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
index 8271bed..5de6d42 100644
--- a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
+++ b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
@@ -128,8 +128,8 @@
rangingManager.onRangingReconfigureFailed(handle, REASON, PARAMS);
verify(callback, times(1)).onReconfigureFailed(eq(REASON), eq(PARAMS));
- rangingManager.onRangingStopped(handle);
- verify(callback, times(1)).onStopped();
+ rangingManager.onRangingStopped(handle, REASON, PARAMS);
+ verify(callback, times(1)).onStopped(eq(REASON), eq(PARAMS));
rangingManager.onRangingStopFailed(handle, REASON, PARAMS);
verify(callback, times(1)).onStopFailed(eq(REASON), eq(PARAMS));
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 0987f77..489da16 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -429,6 +429,7 @@
<permission name="android.permission.LOG_COMPAT_CHANGE" />
<permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
<permission name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG" />
+ <permission name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD" />
<!-- Permissions required to test ambient display. -->
<permission name="android.permission.READ_DREAM_STATE" />
<permission name="android.permission.WRITE_DREAM_STATE" />
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 54f9fa8..a612265 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -673,6 +673,13 @@
/**
* @hide
*/
+ public void punchHole(float left, float top, float right, float bottom, float rx, float ry) {
+ nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry);
+ }
+
+ /**
+ * @hide
+ */
public void setHwBitmapsInSwModeEnabled(boolean enabled) {
mAllowHwBitmapsInSwMode = enabled;
}
@@ -815,4 +822,7 @@
private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
float hOffset, float vOffset, int flags, long nativePaint);
+
+ private static native void nPunchHole(long renderer, float left, float top, float right,
+ float bottom, float rx, float ry);
}
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index a8922e8..a998ba8 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -610,6 +610,14 @@
indices, indexOffset, indexCount, paint.getNativeInstance());
}
+ /**
+ * @hide
+ */
+ @Override
+ public void punchHole(float left, float top, float right, float bottom, float rx, float ry) {
+ nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry);
+ }
+
@FastNative
private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left,
float top, long nativePaintOrZero, int canvasDensity, int screenDensity,
@@ -735,4 +743,8 @@
@FastNative
private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
float hOffset, float vOffset, int flags, long nativePaint);
+
+ @FastNative
+ private static native void nPunchHole(long renderer, float left, float top, float right,
+ float bottom, float rx, float ry);
}
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 1f9022b..a6aa4f2 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -353,7 +353,7 @@
boolean userPresenceRequired,
byte[] attestationChallenge,
boolean devicePropertiesAttestationIncluded,
- int[] attestationIds,
+ @NonNull int[] attestationIds,
boolean uniqueIdIncluded,
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
@@ -779,9 +779,8 @@
* @return integer array representing the requested device IDs to attest.
*/
@SystemApi
- @Nullable
- public int[] getAttestationIds() {
- return Utils.cloneIfNotNull(mAttestationIds);
+ public @NonNull int[] getAttestationIds() {
+ return mAttestationIds.clone();
}
/**
@@ -911,7 +910,7 @@
private boolean mUserPresenceRequired = false;
private byte[] mAttestationChallenge = null;
private boolean mDevicePropertiesAttestationIncluded = false;
- private int[] mAttestationIds = null;
+ private int[] mAttestationIds = new int[0];
private boolean mUniqueIdIncluded = false;
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index c26d9f583..dc7f3dd 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -655,7 +655,7 @@
}
int[] idTypes = mSpec.getAttestationIds();
- if (idTypes == null) {
+ if (idTypes.length == 0) {
return;
}
final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index f6b63eb..e152633 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1011,6 +1011,9 @@
/** Moves the PiP menu to the destination bounds. */
public void finishResizeForMenu(Rect destinationBounds) {
+ if (!isInPip()) {
+ return;
+ }
mPipMenuController.movePipMenu(null, null, destinationBounds);
mPipMenuController.updateMenuBounds(destinationBounds);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 4cf8ab4..17cde73 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -16,13 +16,9 @@
package com.android.wm.shell.pip.phone;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
import android.annotation.Nullable;
-import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.RemoteAction;
import android.content.Context;
import android.content.pm.ParceledListSlice;
@@ -43,6 +39,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipMediaController.ActionListener;
import com.android.wm.shell.pip.PipMenuController;
@@ -59,7 +56,7 @@
*/
public class PhonePipMenuController implements PipMenuController {
- private static final String TAG = "PipMenuActController";
+ private static final String TAG = "PhonePipMenuController";
private static final boolean DEBUG = false;
public static final int MENU_STATE_NONE = 0;
@@ -99,6 +96,7 @@
private final RectF mTmpSourceRectF = new RectF();
private final RectF mTmpDestinationRectF = new RectF();
private final Context mContext;
+ private final PipBoundsState mPipBoundsState;
private final PipMediaController mMediaController;
private final ShellExecutor mMainExecutor;
private final Handler mMainHandler;
@@ -134,10 +132,11 @@
}
};
- public PhonePipMenuController(Context context, PipMediaController mediaController,
- SystemWindows systemWindows, ShellExecutor mainExecutor,
- Handler mainHandler) {
+ public PhonePipMenuController(Context context, PipBoundsState pipBoundsState,
+ PipMediaController mediaController, SystemWindows systemWindows,
+ ShellExecutor mainExecutor, Handler mainHandler) {
mContext = context;
+ mPipBoundsState = pipBoundsState;
mMediaController = mediaController;
mSystemWindows = systemWindows;
mMainExecutor = mainExecutor;
@@ -466,20 +465,11 @@
* Updates the PiP menu with the best set of actions provided.
*/
private void updateMenuActions() {
- if (isMenuVisible()) {
- // Fetch the pinned stack bounds
- Rect stackBounds = null;
- try {
- RootTaskInfo pinnedTaskInfo = ActivityTaskManager.getService().getRootTaskInfo(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
- if (pinnedTaskInfo != null) {
- stackBounds = pinnedTaskInfo.bounds;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error showing PIP menu", e);
+ if (mPipMenuView != null) {
+ final ParceledListSlice<RemoteAction> menuActions = resolveMenuActions();
+ if (menuActions != null) {
+ mPipMenuView.setActions(mPipBoundsState.getBounds(), menuActions.getList());
}
-
- mPipMenuView.setActions(stackBounds, resolveMenuActions().getList());
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 1bfae53..7e594a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -374,7 +374,9 @@
void setActions(Rect stackBounds, List<RemoteAction> actions) {
mActions.clear();
mActions.addAll(actions);
- updateActionViews(stackBounds);
+ if (mMenuState == MENU_STATE_FULL) {
+ updateActionViews(stackBounds);
+ }
}
private void updateActionViews(Rect stackBounds) {
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 607ef72..c75b21f 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -464,10 +464,12 @@
"canvas/CanvasOpBuffer.cpp",
"canvas/CanvasOpRasterizer.cpp",
"effects/StretchEffect.cpp",
+ "pipeline/skia/HolePunch.cpp",
"pipeline/skia/SkiaDisplayList.cpp",
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/RenderNodeDrawable.cpp",
"pipeline/skia/ReorderBarrierDrawables.cpp",
+ "pipeline/skia/TransformCanvas.cpp",
"renderthread/Frame.cpp",
"renderthread/RenderTask.cpp",
"renderthread/TimeLord.cpp",
@@ -647,6 +649,7 @@
"tests/unit/CommonPoolTests.cpp",
"tests/unit/DamageAccumulatorTests.cpp",
"tests/unit/DeferredLayerUpdaterTests.cpp",
+ "tests/unit/EglManagerTests.cpp",
"tests/unit/FatVectorTests.cpp",
"tests/unit/GraphicsStatsServiceTests.cpp",
"tests/unit/LayerUpdateQueueTests.cpp",
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 3aa5b4b..894b479 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -17,8 +17,10 @@
#pragma once
#include "pipeline/skia/SkiaDisplayList.h"
+#include "canvas/CanvasOpBuffer.h"
#include <memory>
+#include <variant>
namespace android {
namespace uirenderer {
@@ -28,29 +30,25 @@
};
typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
-/**
- * Data structure that holds the list of commands used in display list stream
- */
-//using DisplayList = skiapipeline::SkiaDisplayList;
-class DisplayList {
+class SkiaDisplayListWrapper {
public:
// Constructs an empty (invalid) DisplayList
- explicit DisplayList() {}
+ explicit SkiaDisplayListWrapper() {}
// Constructs a DisplayList from a SkiaDisplayList
- explicit DisplayList(std::unique_ptr<skiapipeline::SkiaDisplayList> impl)
+ explicit SkiaDisplayListWrapper(std::unique_ptr<skiapipeline::SkiaDisplayList> impl)
: mImpl(std::move(impl)) {}
// Move support
- DisplayList(DisplayList&& other) : mImpl(std::move(other.mImpl)) {}
- DisplayList& operator=(DisplayList&& other) {
+ SkiaDisplayListWrapper(SkiaDisplayListWrapper&& other) : mImpl(std::move(other.mImpl)) {}
+ SkiaDisplayListWrapper& operator=(SkiaDisplayListWrapper&& other) {
mImpl = std::move(other.mImpl);
return *this;
}
// No copy support
- DisplayList(const DisplayList& other) = delete;
- DisplayList& operator=(const DisplayList&) = delete;
+ SkiaDisplayListWrapper(const SkiaDisplayListWrapper& other) = delete;
+ SkiaDisplayListWrapper& operator=(const SkiaDisplayListWrapper&) = delete;
void updateChildren(std::function<void(RenderNode*)> updateFn) {
mImpl->updateChildren(std::move(updateFn));
@@ -74,6 +72,10 @@
return mImpl && !(mImpl->isEmpty());
}
+ [[nodiscard]] bool hasHolePunches() const {
+ return mImpl && mImpl->hasHolePunches();
+ }
+
[[nodiscard]] bool containsProjectionReceiver() const {
return mImpl && mImpl->containsProjectionReceiver();
}
@@ -137,7 +139,7 @@
void applyColorTransform(ColorTransform transform) {
if (mImpl) {
- mImpl->mDisplayList.applyColorTransform(transform);
+ mImpl->applyColorTransform(transform);
}
}
@@ -145,5 +147,172 @@
std::unique_ptr<skiapipeline::SkiaDisplayList> mImpl;
};
+
+/**
+ * Data structure that holds the list of commands used in display list stream
+ */
+//using DisplayList = skiapipeline::SkiaDisplayList;
+class MultiDisplayList {
+private:
+ using SkiaDisplayList = skiapipeline::SkiaDisplayList;
+
+ struct EmptyList {
+ bool hasText() const { return false; }
+ void updateChildren(std::function<void(RenderNode*)> updateFn) {}
+ bool isEmpty() const { return true; }
+ bool containsProjectionReceiver() const { return false; }
+ bool hasVectorDrawables() const { return false; }
+ size_t getUsedSize() const { return 0; }
+ size_t getAllocatedSize() const { return 0; }
+ void output(std::ostream& output, uint32_t level) const { }
+ bool hasFunctor() const { return false; }
+ bool prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
+ return false;
+ }
+ void syncContents(const WebViewSyncData& data) { }
+ void applyColorTransform(ColorTransform transform) { }
+ };
+
+ std::variant<EmptyList, std::unique_ptr<SkiaDisplayList>, CanvasOpBuffer> mImpls;
+
+ template <typename T>
+ static constexpr T& get(T& t) { return t; }
+ template <typename T>
+ static constexpr const T& get(const T& t) { return t; }
+
+ template <typename T>
+ static constexpr T& get(std::unique_ptr<T>& t) { return *t; }
+ template <typename T>
+ static constexpr const T& get(const std::unique_ptr<T>& t) { return *t; }
+
+ template <typename T>
+ auto apply(T&& t) {
+ return std::visit([&t](auto& it) -> auto {
+ return t(get(it));
+ }, mImpls);
+ }
+
+ template <typename T>
+ auto apply(T&& t) const {
+ return std::visit([&t](const auto& it) -> auto {
+ return t(get(it));
+ }, mImpls);
+ }
+
+public:
+ // Constructs an empty (invalid) DisplayList
+ explicit MultiDisplayList() {}
+
+ // Constructs a DisplayList from a SkiaDisplayList
+ explicit MultiDisplayList(std::unique_ptr<SkiaDisplayList> impl)
+ : mImpls(std::move(impl)) {}
+
+ explicit MultiDisplayList(CanvasOpBuffer&& opBuffer) : mImpls(std::move(opBuffer)) {}
+
+ // Move support
+ MultiDisplayList(MultiDisplayList&& other) : mImpls(std::move(other.mImpls)) {}
+ MultiDisplayList& operator=(MultiDisplayList&& other) {
+ mImpls = std::move(other.mImpls);
+ return *this;
+ }
+
+ // No copy support
+ MultiDisplayList(const MultiDisplayList& other) = delete;
+ MultiDisplayList& operator=(const MultiDisplayList&) = delete;
+
+ void updateChildren(std::function<void(RenderNode*)> updateFn) {
+ apply([&](auto& it) { it.updateChildren(std::move(updateFn)); });
+ }
+
+ [[nodiscard]] explicit operator bool() const {
+ return isValid();
+ }
+
+ // If true this DisplayList contains a backing content, even if that content is empty
+ // If false, there this DisplayList is in an "empty" state
+ [[nodiscard]] bool isValid() const {
+ return mImpls.index() != 0;
+ }
+
+ [[nodiscard]] bool isEmpty() const {
+ return apply([](const auto& it) -> auto { return it.isEmpty(); });
+ }
+
+ [[nodiscard]] bool hasContent() const {
+ return !isEmpty();
+ }
+
+ [[nodiscard]] bool containsProjectionReceiver() const {
+ return apply([](const auto& it) -> auto { return it.containsProjectionReceiver(); });
+ }
+
+ [[nodiscard]] SkiaDisplayList* asSkiaDl() {
+ return std::get<1>(mImpls).get();
+ }
+
+ [[nodiscard]] const SkiaDisplayList* asSkiaDl() const {
+ return std::get<1>(mImpls).get();
+ }
+
+ [[nodiscard]] bool hasVectorDrawables() const {
+ return apply([](const auto& it) -> auto { return it.hasVectorDrawables(); });
+ }
+
+ void clear(RenderNode* owningNode = nullptr) {
+ if (owningNode && mImpls.index() == 1) {
+ auto& skiaDl = std::get<1>(mImpls);
+ if (skiaDl->reuseDisplayList(owningNode)) {
+ skiaDl.release();
+ }
+ }
+ mImpls = EmptyList{};
+ }
+
+ [[nodiscard]] size_t getUsedSize() const {
+ return apply([](const auto& it) -> auto { return it.getUsedSize(); });
+ }
+
+ [[nodiscard]] size_t getAllocatedSize() const {
+ return apply([](const auto& it) -> auto { return it.getAllocatedSize(); });
+ }
+
+ void output(std::ostream& output, uint32_t level) const {
+ apply([&](const auto& it) { it.output(output, level); });
+ }
+
+ [[nodiscard]] bool hasFunctor() const {
+ return apply([](const auto& it) -> auto { return it.hasFunctor(); });
+ }
+
+ bool prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
+ return apply([&](auto& it) -> auto {
+ return it.prepareListAndChildren(observer, info, functorsNeedLayer, std::move(childFn));
+ });
+ }
+
+ void syncContents(const WebViewSyncData& data) {
+ apply([&](auto& it) { it.syncContents(data); });
+ }
+
+ [[nodiscard]] bool hasText() const {
+ return apply([](const auto& it) -> auto { return it.hasText(); });
+ }
+
+ void applyColorTransform(ColorTransform transform) {
+ apply([=](auto& it) { it.applyColorTransform(transform); });
+ }
+
+ [[nodiscard]] CanvasOpBuffer& asOpBuffer() {
+ return std::get<CanvasOpBuffer>(mImpls);
+ }
+};
+
+// For now stick to the original single-type container to avoid any regressions
+using DisplayList = SkiaDisplayListWrapper;
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index f5b2675..e9eae3d 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -255,15 +255,19 @@
if (mDisplayList) {
info.out.hasFunctors |= mDisplayList.hasFunctor();
+ mHasHolePunches = mDisplayList.hasHolePunches();
bool isDirty = mDisplayList.prepareListAndChildren(
observer, info, childFunctorsNeedLayer,
- [](RenderNode* child, TreeObserver& observer, TreeInfo& info,
- bool functorsNeedLayer) {
+ [this](RenderNode* child, TreeObserver& observer, TreeInfo& info,
+ bool functorsNeedLayer) {
child->prepareTreeImpl(observer, info, functorsNeedLayer);
+ mHasHolePunches |= child->hasHolePunches();
});
if (isDirty) {
damageSelf(info);
}
+ } else {
+ mHasHolePunches = false;
}
pushLayerUpdate(info);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 39ea53b..988141f 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -35,6 +35,7 @@
#include "DisplayList.h"
#include "Matrix.h"
#include "RenderProperties.h"
+#include "pipeline/skia/HolePunch.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaLayer.h"
@@ -284,6 +285,8 @@
UsageHint mUsageHint = UsageHint::Unknown;
+ bool mHasHolePunches;
+
// METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
public:
/**
@@ -294,6 +297,8 @@
return std::move(mAvailableDisplayList);
}
+ bool hasHolePunches() { return mHasHolePunches; }
+
/**
* Attach unused displayList to this node for potential future reuse.
*/
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 28d2b4c..4c4a152 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -23,6 +23,7 @@
#include "hwui/MinikinUtils.h"
#include "hwui/PaintFilter.h"
#include "pipeline/skia/AnimatedDrawables.h"
+#include "pipeline/skia/HolePunch.h"
#include <SkAndroidFrameworkUtils.h>
#include <SkAnimatedImage.h>
@@ -244,6 +245,13 @@
return (rec && rec->saveCount == currentSaveCount) ? rec : nullptr;
}
+void SkiaCanvas::punchHole(const SkRRect& rect) {
+ SkPaint paint = SkPaint();
+ paint.setColor(0);
+ paint.setBlendMode(SkBlendMode::kClear);
+ mCanvas->drawRRect(rect, paint);
+}
+
// ----------------------------------------------------------------------------
// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 9ab2b10..e0a0be5 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -60,6 +60,8 @@
LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ");
}
+ virtual void punchHole(const SkRRect& rect) override;
+
virtual void setBitmap(const SkBitmap& bitmap) override;
virtual bool isOpaque() override;
diff --git a/libs/hwui/canvas/CanvasFrontend.h b/libs/hwui/canvas/CanvasFrontend.h
index d749d2f..f9a6101 100644
--- a/libs/hwui/canvas/CanvasFrontend.h
+++ b/libs/hwui/canvas/CanvasFrontend.h
@@ -147,8 +147,7 @@
public:
template<class... Args>
CanvasFrontend(int width, int height, Args&&... args) : CanvasStateHelper(width, height),
- mReceiver(std::forward<Args>(args)...) { }
- ~CanvasFrontend() = default;
+ mReceiver(std::in_place, std::forward<Args>(args)...) { }
void save(SaveFlags::Flags flags = SaveFlags::MatrixClip) {
if (internalSave(flagsToSaveEntry(flags))) {
@@ -186,7 +185,10 @@
submit(std::move(op));
}
- const CanvasOpReceiver& receiver() const { return *mReceiver; }
+ const CanvasOpReceiver& receiver() const {
+ LOG_ALWAYS_FATAL_IF(!mReceiver.has_value());
+ return *mReceiver;
+ }
CanvasOpReceiver finish() {
auto ret = std::move(mReceiver.value());
@@ -205,6 +207,7 @@
template <CanvasOpType T>
void submit(CanvasOp<T>&& op) {
+ LOG_ALWAYS_FATAL_IF(!mReceiver.has_value());
mReceiver->push_container(CanvasOpContainer(std::move(op), transform()));
}
};
diff --git a/libs/hwui/canvas/CanvasOpBuffer.cpp b/libs/hwui/canvas/CanvasOpBuffer.cpp
index 7054e47e..6089c572 100644
--- a/libs/hwui/canvas/CanvasOpBuffer.cpp
+++ b/libs/hwui/canvas/CanvasOpBuffer.cpp
@@ -22,4 +22,32 @@
template class OpBuffer<CanvasOpType, CanvasOpContainer>;
+void CanvasOpBuffer::updateChildren(std::function<void(RenderNode*)> updateFn) {
+ // TODO: Do we need a fast-path for finding children?
+ if (mHas.children) {
+ for (auto& iter : filter<CanvasOpType::DrawRenderNode>()) {
+ updateFn(iter->renderNode.get());
+ }
+ }
+}
+
+void CanvasOpBuffer::output(std::ostream& output, uint32_t level) const {
+ LOG_ALWAYS_FATAL("TODO");
+}
+
+bool CanvasOpBuffer::prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
+ LOG_ALWAYS_FATAL("TODO");
+ return false;
+}
+
+void CanvasOpBuffer::syncContents(const WebViewSyncData& data) {
+ LOG_ALWAYS_FATAL("TODO");
+}
+
+void CanvasOpBuffer::applyColorTransform(ColorTransform transform) {
+ LOG_ALWAYS_FATAL("TODO");
+}
+
} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasOpBuffer.h b/libs/hwui/canvas/CanvasOpBuffer.h
index 07e079a..af797ca 100644
--- a/libs/hwui/canvas/CanvasOpBuffer.h
+++ b/libs/hwui/canvas/CanvasOpBuffer.h
@@ -19,10 +19,17 @@
#include <SkMatrix.h>
#include "CanvasOpTypes.h"
+#include "CanvasTransform.h"
#include "OpBuffer.h"
+#include "TreeInfo.h"
+#include "private/hwui/WebViewFunctor.h"
+
+#include <functional>
namespace android::uirenderer {
+class RenderNode;
+
template <CanvasOpType T>
struct CanvasOp;
@@ -53,12 +60,74 @@
};
extern template class OpBuffer<CanvasOpType, CanvasOpContainer>;
-class CanvasOpBuffer final : public OpBuffer<CanvasOpType, CanvasOpContainer> {
+class CanvasOpBuffer final : private OpBuffer<CanvasOpType, CanvasOpContainer> {
+private:
+ using SUPER = OpBuffer<CanvasOpType, CanvasOpContainer>;
+
public:
+ // Expose select superclass methods publicly
+ using SUPER::for_each;
+ using SUPER::size;
+ using SUPER::resize;
+
template <CanvasOpType T>
void push(CanvasOp<T>&& op) {
push_container(CanvasOpContainer<T>(std::move(op)));
}
+
+ template <CanvasOpType T>
+ void push_container(CanvasOpContainer<T>&& op) {
+ if constexpr (IsDrawOp(T)) {
+ mHas.content = true;
+ }
+ if constexpr (T == CanvasOpType::DrawRenderNode) {
+ mHas.children = true;
+ // use staging property, since recording on UI thread
+ if (op->renderNode->stagingProperties().isProjectionReceiver()) {
+ mHas.projectionReceiver = true;
+ }
+ }
+ SUPER::push_container(std::move(op));
+ }
+
+ void clear() {
+ mHas = Contains{};
+ SUPER::clear();
+ }
+
+ void updateChildren(std::function<void(RenderNode*)> updateFn);
+ bool prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn);
+ void syncContents(const WebViewSyncData& data);
+ void applyColorTransform(ColorTransform transform);
+
+ [[nodiscard]] bool isEmpty() const { return !mHas.content; }
+ [[nodiscard]] bool hasText() const { return mHas.text; }
+ [[nodiscard]] bool hasVectorDrawables() const { return mHas.vectorDrawable; }
+ [[nodiscard]] bool containsProjectionReceiver() const { return mHas.projectionReceiver; }
+ [[nodiscard]] bool hasFunctor() const { return mHas.functor; }
+
+ [[nodiscard]] size_t getUsedSize() const {
+ return size();
+ }
+
+ [[nodiscard]] size_t getAllocatedSize() const {
+ return capacity();
+ }
+
+ void output(std::ostream& output, uint32_t level) const;
+
+private:
+ struct Contains {
+ bool content : 1 = false;
+ bool children : 1 = false;
+ bool projectionReceiver : 1 = false;
+ bool text : 1 = false;
+ bool vectorDrawable : 1 = false;
+ bool functor : 1 = false;
+ };
+ Contains mHas;
};
} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasOpRasterizer.cpp b/libs/hwui/canvas/CanvasOpRasterizer.cpp
index 0093c38..9297604 100644
--- a/libs/hwui/canvas/CanvasOpRasterizer.cpp
+++ b/libs/hwui/canvas/CanvasOpRasterizer.cpp
@@ -33,21 +33,15 @@
SkMatrix& currentGlobalTransform = globalMatrixStack.emplace_back(SkMatrix::I());
source.for_each([&]<CanvasOpType T>(const CanvasOpContainer<T> * op) {
- if constexpr (
- T == CanvasOpType::BeginZ ||
- T == CanvasOpType::EndZ ||
- T == CanvasOpType::DrawLayer
- ) {
- // Do beginZ or endZ
- LOG_ALWAYS_FATAL("TODO");
- return;
- } else {
+ if constexpr (CanvasOpTraits::can_draw<CanvasOp<T>>) {
// Generic OP
// First apply the current transformation
destination->setMatrix(SkMatrix::Concat(currentGlobalTransform, op->transform()));
// Now draw it
(*op)->draw(destination);
+ return;
}
+ LOG_ALWAYS_FATAL("TODO, unable to rasterize %d", static_cast<int>(T));
});
}
diff --git a/libs/hwui/canvas/CanvasOpTypes.h b/libs/hwui/canvas/CanvasOpTypes.h
index cde50bd..b55ef9d 100644
--- a/libs/hwui/canvas/CanvasOpTypes.h
+++ b/libs/hwui/canvas/CanvasOpTypes.h
@@ -35,7 +35,8 @@
ClipPath,
// Drawing ops
- DrawColor,
+ DRAW_OP_BEGIN,
+ DrawColor = DRAW_OP_BEGIN,
DrawRect,
DrawRegion,
DrawRoundRect,
@@ -59,10 +60,16 @@
DrawImageLattice,
DrawPicture,
DrawLayer,
+ DrawRenderNode,
+ DRAW_OP_END = DrawRenderNode,
// TODO: Rest
COUNT // must be last
};
+static constexpr bool IsDrawOp(CanvasOpType t) {
+ return CanvasOpType::DRAW_OP_BEGIN <= t && t <= CanvasOpType::DRAW_OP_END;
+}
+
} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index 86b1ac7..855cd0d 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -24,13 +24,15 @@
#include <SkImage.h>
#include <SkPicture.h>
#include <SkRuntimeEffect.h>
-#include <hwui/Bitmap.h>
-#include <log/log.h>
-#include "CanvasProperty.h"
-#include "Points.h"
+#include <log/log.h>
+
+#include "hwui/Bitmap.h"
+#include "CanvasProperty.h"
#include "CanvasOpTypes.h"
#include "Layer.h"
+#include "Points.h"
+#include "RenderNode.h"
#include <experimental/type_traits>
#include <utility>
@@ -450,6 +452,11 @@
sp<Layer> layer;
};
+template<>
+struct CanvasOp<CanvasOpType::DrawRenderNode> {
+ sp<RenderNode> renderNode;
+};
+
// cleanup our macros
#undef ASSERT_DRAWABLE
diff --git a/libs/hwui/canvas/OpBuffer.h b/libs/hwui/canvas/OpBuffer.h
index 1237d69..8b5cdbb 100644
--- a/libs/hwui/canvas/OpBuffer.h
+++ b/libs/hwui/canvas/OpBuffer.h
@@ -64,7 +64,7 @@
static constexpr auto STARTING_SIZE = PadAlign(sizeof(BufferHeader));
using ItemHeader = OpBufferItemHeader<ItemTypes>;
- OpBuffer() = default;
+ explicit OpBuffer() = default;
// Prevent copying by default
OpBuffer(const OpBuffer&) = delete;
@@ -135,7 +135,7 @@
template <typename F>
void for_each(F&& f) const {
- for_each(std::forward<F>(f), ItemTypesSequence{});
+ do_for_each(std::forward<F>(f), ItemTypesSequence{});
}
void clear();
@@ -225,7 +225,7 @@
}
template <typename F, std::size_t... I>
- void for_each(F&& f, std::index_sequence<I...>) const {
+ void do_for_each(F&& f, std::index_sequence<I...>) const {
// Validate we're not empty
if (isEmpty()) return;
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index d7162b9..de14beb 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -171,13 +171,13 @@
static const float ZERO = 0.f;
static const float CONTENT_DISTANCE_STRETCHED = 1.f;
-sk_sp<SkImageFilter> StretchEffect::getImageFilter(const sk_sp<SkImage>& snapshotImage) const {
+sk_sp<SkShader> StretchEffect::getShader(const sk_sp<SkImage>& snapshotImage) const {
if (isEmpty()) {
return nullptr;
}
- if (mStretchFilter != nullptr) {
- return mStretchFilter;
+ if (mStretchShader != nullptr) {
+ return mStretchShader;
}
float viewportWidth = stretchArea.width();
@@ -212,10 +212,9 @@
mBuilder->uniform("viewportWidth").set(&viewportWidth, 1);
mBuilder->uniform("viewportHeight").set(&viewportHeight, 1);
- mStretchFilter = SkImageFilters::Shader(mBuilder->makeShader(nullptr, false),
- SkRect{0, 0, viewportWidth, viewportHeight});
+ mStretchShader = mBuilder->makeShader(nullptr, false);
- return mStretchFilter;
+ return mStretchShader;
}
sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() {
diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h
index 8221b41..546d53b 100644
--- a/libs/hwui/effects/StretchEffect.h
+++ b/libs/hwui/effects/StretchEffect.h
@@ -53,7 +53,7 @@
StretchEffect& operator=(const StretchEffect& other) {
this->stretchArea = other.stretchArea;
this->mStretchDirection = other.mStretchDirection;
- this->mStretchFilter = nullptr;
+ this->mStretchShader = other.mStretchShader;
this->maxStretchAmountX = other.maxStretchAmountX;
this->maxStretchAmountY = other.maxStretchAmountY;
return *this;
@@ -76,14 +76,14 @@
maxStretchAmountY = std::max(maxStretchAmountY, other.maxStretchAmountY);
}
- sk_sp<SkImageFilter> getImageFilter(const sk_sp<SkImage>& snapshotImage) const;
+ sk_sp<SkShader> getShader(const sk_sp<SkImage>& snapshotImage) const;
SkRect stretchArea {0, 0, 0, 0};
float maxStretchAmountX = 0;
float maxStretchAmountY = 0;
void setStretchDirection(const SkVector& direction) {
- mStretchFilter = nullptr;
+ mStretchShader = nullptr;
mStretchDirection = direction;
}
@@ -93,7 +93,7 @@
static sk_sp<SkRuntimeEffect> getStretchEffect();
mutable SkVector mStretchDirection{0, 0};
mutable std::unique_ptr<SkRuntimeShaderBuilder> mBuilder;
- mutable sk_sp<SkImageFilter> mStretchFilter;
+ mutable sk_sp<SkShader> mStretchShader;
};
} // namespace android::uirenderer
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index d1bdb71..c1feb76 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -155,6 +155,8 @@
LOG_ALWAYS_FATAL("Not supported");
}
+ virtual void punchHole(const SkRRect& rect) = 0;
+
// ----------------------------------------------------------------------------
// Canvas state operations
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index 89fb8bb..a611f7c 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -35,6 +35,7 @@
#include "SkGraphics.h"
#include "SkRegion.h"
#include "SkVertices.h"
+#include "SkRRect.h"
namespace minikin {
class MeasuredText;
@@ -667,6 +668,11 @@
Canvas::setCompatibilityVersion(apiLevel);
}
+static void punchHole(JNIEnv* env, jobject, jlong canvasPtr, jfloat left, jfloat top, jfloat right,
+ jfloat bottom, jfloat rx, jfloat ry) {
+ auto canvas = reinterpret_cast<Canvas*>(canvasPtr);
+ canvas->punchHole(SkRRect::MakeRectXY(SkRect::MakeLTRB(left, top, right, bottom), rx, ry));
+}
}; // namespace CanvasJNI
@@ -740,6 +746,7 @@
{"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
{"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
{"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
+ {"nPunchHole", "(JFFFFFF)V", (void*) CanvasJNI::punchHole}
};
int register_android_graphics_Canvas(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/HolePunch.cpp b/libs/hwui/pipeline/skia/HolePunch.cpp
new file mode 100644
index 0000000..2b2bca6
--- /dev/null
+++ b/libs/hwui/pipeline/skia/HolePunch.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+#include "HolePunch.h"
+#include <string>
+
+using namespace android::uirenderer::skiapipeline;
+
+const std::string HOLE_PUNCH_ANNOTATION = "surface_hole_punch";
diff --git a/libs/hwui/pipeline/skia/HolePunch.h b/libs/hwui/pipeline/skia/HolePunch.h
new file mode 100644
index 0000000..92c6f77
--- /dev/null
+++ b/libs/hwui/pipeline/skia/HolePunch.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+#include <string>
+#include "SkRRect.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+const static std::string HOLE_PUNCH_ANNOTATION;
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
\ No newline at end of file
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index cb0ff8d..77d99a6 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -18,6 +18,7 @@
#include <SkPaintFilterCanvas.h>
#include "RenderNode.h"
#include "SkiaDisplayList.h"
+#include "TransformCanvas.h"
#include "utils/TraceUtils.h"
#include <include/effects/SkImageFilters.h>
@@ -179,20 +180,7 @@
paint->setColorFilter(sk_ref_sp(properties.getColorFilter()));
sk_sp<SkImageFilter> imageFilter = sk_ref_sp(properties.getImageFilter());
- sk_sp<SkImageFilter> stretchFilter =
- properties.getStretchEffect().getImageFilter(snapshotImage);
- sk_sp<SkImageFilter> filter;
- if (imageFilter && stretchFilter) {
- filter = SkImageFilters::Compose(
- std::move(stretchFilter),
- std::move(imageFilter)
- );
- } else if (stretchFilter) {
- filter = std::move(stretchFilter);
- } else {
- filter = std::move(imageFilter);
- }
- paint->setImageFilter(std::move(filter));
+ paint->setImageFilter(std::move(imageFilter));
return true;
}
return false;
@@ -256,8 +244,21 @@
canvas->drawAnnotation(bounds, String8::format(
"SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);
}
- canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,
- SkCanvas::kStrict_SrcRectConstraint);
+
+ if (renderNode->hasHolePunches()) {
+ TransformCanvas transformCanvas(canvas);
+ displayList->draw(&transformCanvas);
+ }
+
+ const StretchEffect& stretch = properties.layerProperties().getStretchEffect();
+ if (stretch.isEmpty()) {
+ canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,
+ SkCanvas::kStrict_SrcRectConstraint);
+ } else {
+ sk_sp<SkShader> stretchShader = stretch.getShader(snapshotImage);
+ paint.setShader(stretchShader);
+ canvas->drawRect(bounds, paint);
+ }
if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 483264f..90e9bc6 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -16,6 +16,8 @@
#pragma once
+#include <deque>
+
#include "RecordingCanvas.h"
#include "RenderNodeDrawable.h"
#include "TreeInfo.h"
@@ -23,8 +25,6 @@
#include "utils/LinearAllocator.h"
#include "utils/Pair.h"
-#include <deque>
-
namespace android {
namespace uirenderer {
@@ -46,8 +46,10 @@
class SkiaDisplayList {
public:
- size_t getUsedSize() { return allocator.usedSize() + mDisplayList.usedSize(); }
- size_t getAllocatedSize() { return allocator.allocatedSize() + mDisplayList.allocatedSize(); }
+ size_t getUsedSize() const { return allocator.usedSize() + mDisplayList.usedSize(); }
+ size_t getAllocatedSize() const {
+ return allocator.allocatedSize() + mDisplayList.allocatedSize();
+ }
~SkiaDisplayList() {
/* Given that we are using a LinearStdAllocator to store some of the
@@ -109,6 +111,10 @@
*/
void syncContents(const WebViewSyncData& data);
+ void applyColorTransform(ColorTransform transform) {
+ mDisplayList.applyColorTransform(transform);
+ }
+
/**
* ONLY to be called by RenderNode::prepareTree in order to prepare this
* list while the UI thread is blocked. Here we can upload mutable bitmaps
@@ -154,17 +160,25 @@
std::deque<RenderNodeDrawable> mChildNodes;
std::deque<FunctorDrawable*> mChildFunctors;
std::vector<SkImage*> mMutableImages;
+
private:
std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables;
+ bool mHasHolePunches;
public:
- void appendVD(VectorDrawableRoot* r) {
- appendVD(r, SkMatrix::I());
- }
+ void appendVD(VectorDrawableRoot* r) { appendVD(r, SkMatrix::I()); }
void appendVD(VectorDrawableRoot* r, const SkMatrix& mat) {
mVectorDrawables.push_back(Pair<VectorDrawableRoot*, SkMatrix>(r, mat));
}
+ void setHasHolePunches(bool hasHolePunches) {
+ mHasHolePunches = hasHolePunches;
+ }
+
+ bool hasHolePunches() {
+ return mHasHolePunches;
+ }
+
std::vector<AnimatedImageDrawable*> mAnimatedImages;
DisplayListData mDisplayList;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 61f9960..82814de 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -53,6 +53,27 @@
mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height));
SkiaCanvas::reset(&mRecorder);
+ mDisplayList->setHasHolePunches(false);
+}
+
+void SkiaRecordingCanvas::punchHole(const SkRRect& rect) {
+ // Add the marker annotation to allow HWUI to determine where the current
+ // clip/transformation should be applied
+ SkVector vector = rect.getSimpleRadii();
+ const int dataSize = 2;
+ float data[dataSize];
+ data[0] = vector.x();
+ data[1] = vector.y();
+ mRecorder.drawAnnotation(rect.rect(), HOLE_PUNCH_ANNOTATION.c_str(),
+ SkData::MakeWithCopy(data, dataSize));
+
+ // Clear the current rect within the layer itself
+ SkPaint paint = SkPaint();
+ paint.setColor(0);
+ paint.setBlendMode(SkBlendMode::kClear);
+ mRecorder.drawRRect(rect, paint);
+
+ mDisplayList->setHasHolePunches(true);
}
std::unique_ptr<SkiaDisplayList> SkiaRecordingCanvas::finishRecording() {
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index ff03e0c..06f2a27 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -15,6 +15,7 @@
*/
#pragma once
+#include "HolePunch.h"
#include "RecordingCanvas.h"
#include "ReorderBarrierDrawables.h"
#include "SkiaCanvas.h"
@@ -43,6 +44,8 @@
initDisplayList(renderNode, width, height);
}
+ virtual void punchHole(const SkRRect& rect) override;
+
virtual void finishRecording(uirenderer::RenderNode* destination) override;
std::unique_ptr<SkiaDisplayList> finishRecording();
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.cpp b/libs/hwui/pipeline/skia/TransformCanvas.cpp
new file mode 100644
index 0000000..6bfbb0d
--- /dev/null
+++ b/libs/hwui/pipeline/skia/TransformCanvas.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+#include "TransformCanvas.h"
+#include "HolePunch.h"
+#include "SkData.h"
+#include "SkDrawable.h"
+
+using namespace android::uirenderer::skiapipeline;
+
+void TransformCanvas::onDrawAnnotation(const SkRect& rect, const char* key, SkData* value) {
+ if (HOLE_PUNCH_ANNOTATION == key) {
+ auto* rectParams = static_cast<const float*>(value->data());
+ float radiusX = rectParams[0];
+ float radiusY = rectParams[1];
+ SkRRect roundRect = SkRRect::MakeRectXY(rect, radiusX, radiusY);
+
+ SkPaint paint;
+ paint.setColor(0);
+ paint.setBlendMode(SkBlendMode::kClear);
+ mWrappedCanvas->drawRRect(roundRect, paint);
+ }
+}
+
+void TransformCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
+ drawable->draw(this, matrix);
+}
+
+bool TransformCanvas::onFilter(SkPaint& paint) const {
+ return false;
+}
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.h b/libs/hwui/pipeline/skia/TransformCanvas.h
new file mode 100644
index 0000000..47f77f1
--- /dev/null
+++ b/libs/hwui/pipeline/skia/TransformCanvas.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+#pragma once
+
+#include <include/core/SkCanvas.h>
+#include "SkPaintFilterCanvas.h"
+
+class TransformCanvas : public SkPaintFilterCanvas {
+public:
+ TransformCanvas(SkCanvas* target) : SkPaintFilterCanvas(target), mWrappedCanvas(target) {}
+
+protected:
+ bool onFilter(SkPaint& paint) const override;
+
+protected:
+ void onDrawAnnotation(const SkRect& rect, const char* key, SkData* value) override;
+ void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override;
+
+private:
+ // We don't own the canvas so just maintain a raw pointer to it
+ SkCanvas* mWrappedCanvas;
+};
diff --git a/libs/hwui/tests/unit/CanvasFrontendTests.cpp b/libs/hwui/tests/unit/CanvasFrontendTests.cpp
index 05b1179..4ddcf6f 100644
--- a/libs/hwui/tests/unit/CanvasFrontendTests.cpp
+++ b/libs/hwui/tests/unit/CanvasFrontendTests.cpp
@@ -124,12 +124,12 @@
TEST(CanvasFrontend, drawOpTransform) {
CanvasFrontend<CanvasOpBuffer> opCanvas(100, 100);
- const auto& receiver = opCanvas.receiver();
+ const auto &receiver = opCanvas.receiver();
auto makeDrawRect = [] {
return CanvasOp<CanvasOpType::DrawRect>{
- .rect = SkRect::MakeWH(50, 50),
- .paint = SkPaint(SkColors::kBlack),
+ .rect = SkRect::MakeWH(50, 50),
+ .paint = SkPaint(SkColors::kBlack),
};
};
@@ -167,14 +167,14 @@
{
// First result should be identity
- const auto& result = transforms[0];
+ const auto &result = transforms[0];
EXPECT_EQ(SkMatrix::kIdentity_Mask, result.getType());
EXPECT_EQ(SkMatrix::I(), result);
}
{
// Should be translate 10, 10
- const auto& result = transforms[1];
+ const auto &result = transforms[1];
EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType());
SkMatrix m;
m.setTranslate(10, 10);
@@ -183,7 +183,7 @@
{
// Should be translate 10, 10 + scale 2, 4
- const auto& result = transforms[2];
+ const auto &result = transforms[2];
EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask, result.getType());
SkMatrix m;
m.setTranslate(10, 10);
@@ -193,7 +193,7 @@
{
// Should be translate 10, 10 + translate 20, 15
- const auto& result = transforms[3];
+ const auto &result = transforms[3];
EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType());
SkMatrix m;
m.setTranslate(30, 25);
@@ -202,9 +202,9 @@
{
// Should be translate 10, 10 + translate 20, 15 + rotate 90
- const auto& result = transforms[4];
+ const auto &result = transforms[4];
EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask,
- result.getType());
+ result.getType());
SkMatrix m;
m.setTranslate(30, 25);
m.preRotate(90.f);
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index 54970df..a718d46 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -149,7 +149,7 @@
CanvasOpBuffer buffer;
EXPECT_EQ(buffer.size(), 0);
size_t numPts = 3;
- auto pts = sk_ref_sp(
+ auto pts = sk_sp<Points>(
new Points({
{32, 16},
{48, 48},
@@ -192,7 +192,7 @@
CanvasOpBuffer buffer;
EXPECT_EQ(buffer.size(), 0);
size_t numPts = 3;
- auto pts = sk_ref_sp(
+ auto pts = sk_sp<Points>(
new Points({
{32, 16},
{48, 48},
diff --git a/libs/hwui/tests/unit/EglManagerTests.cpp b/libs/hwui/tests/unit/EglManagerTests.cpp
new file mode 100644
index 0000000..f7f2406
--- /dev/null
+++ b/libs/hwui/tests/unit/EglManagerTests.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "renderthread/EglManager.h"
+#include "tests/common/TestContext.h"
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
+using namespace android::uirenderer::test;
+
+TEST(EglManager, doesSurfaceLeak) {
+ EglManager eglManager;
+ eglManager.initialize();
+
+ ASSERT_TRUE(eglManager.hasEglContext());
+
+ auto colorSpace = SkColorSpace::MakeSRGB();
+ for (int i = 0; i < 100; i++) {
+ TestContext context;
+ auto result =
+ eglManager.createSurface(context.surface().get(), ColorMode::Default, colorSpace);
+ EXPECT_TRUE(result);
+ EGLSurface surface = result.unwrap();
+ eglManager.destroySurface(surface);
+ }
+
+ eglManager.destroy();
+}
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 6dd57b1..8c999c4 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -404,6 +404,7 @@
EXPECT_TRUE(pipeline->isSurfaceReady());
renderThread.destroyRenderingContext();
EXPECT_FALSE(pipeline->isSurfaceReady());
+ LOG_ALWAYS_FATAL_IF(pipeline->isSurfaceReady());
}
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, pictureCallback) {
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index eedb996..24f553f 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -324,6 +324,8 @@
public static final int ENCODING_MPEGH_LC_L3 = 25;
/** Audio data format: MPEG-H low complexity profile, level 4 */
public static final int ENCODING_MPEGH_LC_L4 = 26;
+ /** Audio data format: DTS UHD compressed */
+ public static final int ENCODING_DTS_UHD = 27;
/** @hide */
public static String toLogFriendlyEncoding(int enc) {
@@ -380,6 +382,8 @@
return "ENCODING_MPEGH_LC_L3";
case ENCODING_MPEGH_LC_L4:
return "ENCODING_MPEGH_LC_L4";
+ case ENCODING_DTS_UHD:
+ return "ENCODING_DTS_UHD";
default :
return "invalid encoding " + enc;
}
@@ -615,6 +619,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
return true;
default:
return false;
@@ -650,6 +655,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
return true;
default:
return false;
@@ -688,6 +694,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
return false;
case ENCODING_INVALID:
default:
@@ -726,6 +733,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
return false;
case ENCODING_INVALID:
default:
@@ -1012,6 +1020,7 @@
case ENCODING_MPEGH_BL_L4:
case ENCODING_MPEGH_LC_L3:
case ENCODING_MPEGH_LC_L4:
+ case ENCODING_DTS_UHD:
mEncoding = encoding;
break;
case ENCODING_INVALID:
@@ -1238,7 +1247,8 @@
ENCODING_MPEGH_BL_L3,
ENCODING_MPEGH_BL_L4,
ENCODING_MPEGH_LC_L3,
- ENCODING_MPEGH_LC_L4 }
+ ENCODING_MPEGH_LC_L4,
+ ENCODING_DTS_UHD }
)
@Retention(RetentionPolicy.SOURCE)
public @interface Encoding {}
@@ -1258,6 +1268,7 @@
ENCODING_MPEGH_BL_L4,
ENCODING_MPEGH_LC_L3,
ENCODING_MPEGH_LC_L4,
+ ENCODING_DTS_UHD
};
/** @hide */
@@ -1274,7 +1285,8 @@
ENCODING_MPEGH_BL_L3,
ENCODING_MPEGH_BL_L4,
ENCODING_MPEGH_LC_L3,
- ENCODING_MPEGH_LC_L4 }
+ ENCODING_MPEGH_LC_L4,
+ ENCODING_DTS_UHD }
)
@Retention(RetentionPolicy.SOURCE)
public @interface SurroundSoundEncoding {}
@@ -1316,6 +1328,8 @@
return "MPEG-H 3D Audio low complexity profile level 3";
case ENCODING_MPEGH_LC_L4:
return "MPEG-H 3D Audio low complexity profile level 4";
+ case ENCODING_DTS_UHD:
+ return "DTS UHD";
default:
return "Unknown surround sound format";
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 7220379..5f60fb6 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -428,6 +428,8 @@
return "AUDIO_FORMAT_MAT_2_0"; // (MAT | MAT_SUB_2_0)
case /* AUDIO_FORMAT_MAT_2_1 */ 0x24000003:
return "AUDIO_FORMAT_MAT_2_1"; // (MAT | MAT_SUB_2_1)
+ case /* AUDIO_FORMAT_DTS_UHD */ 0x2E000000:
+ return "AUDIO_FORMAT_DTS_UHD";
default:
return "AUDIO_FORMAT_(" + audioFormat + ")";
}
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index e0f6379..7433cf9 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -432,14 +432,27 @@
const ARect& destination, int32_t transform) {
CHECK_NOT_NULL(aSurfaceTransaction);
CHECK_NOT_NULL(aSurfaceControl);
- CHECK_VALID_RECT(source);
CHECK_VALID_RECT(destination);
+ Rect sourceRect = static_cast<const Rect&>(source);
+ // Adjust the source so its top and left are not negative
+ sourceRect.left = std::max(sourceRect.left, 0);
+ sourceRect.top = std::max(sourceRect.top, 0);
+ LOG_ALWAYS_FATAL_IF(sourceRect.isEmpty(), "invalid arg passed as source argument");
+
sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
- transaction->setCrop(surfaceControl, static_cast<const Rect&>(source));
- transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));
+ transaction->setCrop(surfaceControl, sourceRect);
+
+ float dsdx = (destination.right - destination.left) /
+ static_cast<float>(sourceRect.right - sourceRect.left);
+ float dsdy = (destination.bottom - destination.top) /
+ static_cast<float>(sourceRect.bottom - sourceRect.top);
+
+ transaction->setPosition(surfaceControl, destination.left - (sourceRect.left * dsdx),
+ destination.top - (sourceRect.top * dsdy));
+ transaction->setMatrix(surfaceControl, dsdx, 0, 0, dsdy);
transaction->setTransform(surfaceControl, transform);
bool transformToInverseDisplay = (NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY & transform) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -458,16 +471,18 @@
transaction->setCrop(surfaceControl, static_cast<const Rect&>(source));
}
-void ASurfaceTransaction_setPosition(ASurfaceTransaction* aSurfaceTransaction,
- ASurfaceControl* aSurfaceControl, const ARect& destination) {
- CHECK_NOT_NULL(aSurfaceTransaction);
+void ASurfaceTransaction_setPosition(ASurfaceTransaction* /* aSurfaceTransaction */,
+ ASurfaceControl* /* aSurfaceControl */,
+ const ARect& /* destination */) {
+ // TODO: Fix this function
+ /* CHECK_NOT_NULL(aSurfaceTransaction);
CHECK_NOT_NULL(aSurfaceControl);
CHECK_VALID_RECT(destination);
sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
- transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));
+ transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));*/
}
void ASurfaceTransaction_setTransform(ASurfaceTransaction* aSurfaceTransaction,
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index 9c77c85..ac5cb70 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -68,7 +68,6 @@
method public boolean bindProcessToNetwork(@Nullable android.net.Network);
method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
- method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public android.net.Network getActiveNetworkForUid(int);
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index 513b630..8dfdd614 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -26,6 +26,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
method public void systemReady();
+ field public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION";
field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
field public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index b77d821..3a9731f 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -450,6 +450,15 @@
"android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
/**
+ * Clear DNS Cache Action: This is broadcast when networks have changed and old
+ * DNS entries should be cleared.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
+
+ /**
* Invalid tethering type.
* @see #startTethering(int, boolean, OnStartTetheringCallback)
* @hide
@@ -1193,7 +1202,8 @@
*
* @return a {@link Network} object for the current default network for the
* given UID or {@code null} if no default network is currently active
- * TODO: b/183465229 Cleanup getActiveNetworkForUid once b/165835257 is fixed
+ *
+ * @hide
*/
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
@Nullable
@@ -3475,6 +3485,8 @@
* not include location sensitive info.
* </p>
*/
+ // Note: Some existing fields which are location sensitive may still be included without
+ // this flag if the app targets SDK < S (to maintain backwards compatibility).
public static final int FLAG_INCLUDE_LOCATION_INFO = 1 << 0;
/** @hide */
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 9c4c0e2..c4277c3 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -600,8 +600,9 @@
// TODO: Consider adding unwanted capabilities to the public API and mention this
// in the documentation.
checkValidCapability(capability);
- mNetworkCapabilities |= 1 << capability;
- mUnwantedNetworkCapabilities &= ~(1 << capability); // remove from unwanted capability list
+ mNetworkCapabilities |= 1L << capability;
+ // remove from unwanted capability list
+ mUnwantedNetworkCapabilities &= ~(1L << capability);
return this;
}
@@ -620,8 +621,8 @@
*/
public void addUnwantedCapability(@NetCapability int capability) {
checkValidCapability(capability);
- mUnwantedNetworkCapabilities |= 1 << capability;
- mNetworkCapabilities &= ~(1 << capability); // remove from requested capabilities
+ mUnwantedNetworkCapabilities |= 1L << capability;
+ mNetworkCapabilities &= ~(1L << capability); // remove from requested capabilities
}
/**
@@ -634,7 +635,7 @@
*/
public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
checkValidCapability(capability);
- final long mask = ~(1 << capability);
+ final long mask = ~(1L << capability);
mNetworkCapabilities &= mask;
return this;
}
@@ -649,7 +650,7 @@
*/
public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) {
checkValidCapability(capability);
- mUnwantedNetworkCapabilities &= ~(1 << capability);
+ mUnwantedNetworkCapabilities &= ~(1L << capability);
return this;
}
@@ -717,14 +718,14 @@
*/
public boolean hasCapability(@NetCapability int capability) {
return isValidCapability(capability)
- && ((mNetworkCapabilities & (1 << capability)) != 0);
+ && ((mNetworkCapabilities & (1L << capability)) != 0);
}
/** @hide */
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return isValidCapability(capability)
- && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
+ && ((mUnwantedNetworkCapabilities & (1L << capability)) != 0);
}
/**
@@ -1126,7 +1127,9 @@
* app needs to hold {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. If the
* app targets SDK version greater than or equal to {@link Build.VERSION_CODES#S}, then they
* also need to use {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} to get the info in their
- * callback. The app will be blamed for location access if this field is included.
+ * callback. If the apps targets SDK version equal to {{@link Build.VERSION_CODES#R}, this field
+ * will always be included. The app will be blamed for location access if this field is
+ * included.
* </p>
*/
public int getOwnerUid() {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 4578597..95f180a 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -16,6 +16,8 @@
*/
package com.android.packageinstaller;
+import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY;
+import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import android.Manifest;
@@ -50,6 +52,8 @@
import com.android.internal.app.AlertActivity;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
/**
* This activity is launched when a new application is installed via side loading
@@ -92,6 +96,12 @@
private String mCallingAttributionTag;
ApplicationInfo mSourceInfo;
+ /**
+ * A collection of unknown sources listeners that are actively listening for app ops mode
+ * changes
+ */
+ private List<UnknownSourcesListener> mActiveUnknownSourcesListeners = new ArrayList<>(1);
+
// ApplicationInfo object primarily used for already existing applications
private ApplicationInfo mAppInfo = null;
@@ -381,6 +391,14 @@
outState.putBoolean(ALLOW_UNKNOWN_SOURCES_KEY, mAllowUnknownSources);
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ while (!mActiveUnknownSourcesListeners.isEmpty()) {
+ unregister(mActiveUnknownSourcesListeners.get(0));
+ }
+ }
+
private void bindUi() {
mAlert.setIcon(mAppSnippet.icon);
mAlert.setTitle(mAppSnippet.label);
@@ -707,24 +725,61 @@
}
}
+ private class UnknownSourcesListener implements AppOpsManager.OnOpChangedListener {
+
+ @Override
+ public void onOpChanged(String op, String packageName) {
+ if (!mOriginatingPackage.equals(packageName)) {
+ return;
+ }
+ unregister(this);
+ mActiveUnknownSourcesListeners.remove(this);
+ if (isDestroyed()) {
+ return;
+ }
+ getMainThreadHandler().postDelayed(() -> {
+ if (!isDestroyed()) {
+ startActivity(getIntent().addFlags(FLAG_ACTIVITY_REORDER_TO_FRONT));
+ }
+ }, 500);
+
+ }
+
+ }
+
+ private void register(UnknownSourcesListener listener) {
+ mAppOpsManager.startWatchingMode(
+ AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES, mOriginatingPackage,
+ listener);
+ mActiveUnknownSourcesListeners.add(listener);
+ }
+
+ private void unregister(UnknownSourcesListener listener) {
+ mAppOpsManager.stopWatchingMode(listener);
+ mActiveUnknownSourcesListeners.remove(listener);
+ }
+
/**
* An error dialog shown when external sources are not allowed
*/
public static class ExternalSourcesBlockedDialog extends AppErrorDialog {
static AppErrorDialog newInstance(@NonNull String originationPkg) {
- ExternalSourcesBlockedDialog dialog = new ExternalSourcesBlockedDialog();
+ ExternalSourcesBlockedDialog dialog =
+ new ExternalSourcesBlockedDialog();
dialog.setArgument(originationPkg);
return dialog;
}
@Override
protected Dialog createDialog(@NonNull CharSequence argument) {
+
+ final PackageInstallerActivity activity = (PackageInstallerActivity)getActivity();
try {
- PackageManager pm = getActivity().getPackageManager();
+ PackageManager pm = activity.getPackageManager();
ApplicationInfo sourceInfo = pm.getApplicationInfo(argument.toString(), 0);
- return new AlertDialog.Builder(getActivity())
+ return new AlertDialog.Builder(activity)
.setTitle(pm.getApplicationLabel(sourceInfo))
.setIcon(pm.getApplicationIcon(sourceInfo))
.setMessage(R.string.untrusted_external_source_warning)
@@ -735,8 +790,10 @@
Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
final Uri packageUri = Uri.parse("package:" + argument);
settingsIntent.setData(packageUri);
+ settingsIntent.setFlags(FLAG_ACTIVITY_NO_HISTORY);
try {
- getActivity().startActivityForResult(settingsIntent,
+ activity.register(activity.new UnknownSourcesListener());
+ activity.startActivityForResult(settingsIntent,
REQUEST_TRUST_EXTERNAL_SOURCE);
} catch (ActivityNotFoundException exc) {
Log.e(TAG, "Settings activity not found for action: "
@@ -744,11 +801,11 @@
}
})
.setNegativeButton(R.string.cancel,
- (dialog, which) -> getActivity().finish())
+ (dialog, which) -> activity.finish())
.create();
} catch (NameNotFoundException e) {
Log.e(TAG, "Did not find app info for " + argument);
- getActivity().finish();
+ activity.finish();
return null;
}
}
diff --git a/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
index b0a9b95..397b0f9 100644
--- a/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
+++ b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
@@ -165,9 +165,8 @@
}
private List<EmergencyNumber> getPromotedEmergencyNumbers(int categories) {
- // TODO(b/171542607): Use platform API when its bug is fixed.
- Map<Integer, List<EmergencyNumber>> allLists = filterEmergencyNumbersByCategories(
- mTelephonyManager.getEmergencyNumberList(), categories);
+ Map<Integer, List<EmergencyNumber>> allLists = mTelephonyManager.getEmergencyNumberList(
+ categories);
if (allLists == null || allLists.isEmpty()) {
Log.w(TAG, "Unable to retrieve emergency number lists!");
return new ArrayList<>();
@@ -212,28 +211,4 @@
}
return promotedEmergencyNumberLists.get(SubscriptionManager.getDefaultSubscriptionId());
}
-
- /**
- * Filter emergency numbers with categories.
- */
- private Map<Integer, List<EmergencyNumber>> filterEmergencyNumbersByCategories(
- Map<Integer, List<EmergencyNumber>> emergencyNumberList, int categories) {
- Map<Integer, List<EmergencyNumber>> filteredMap = new ArrayMap<>();
- if (emergencyNumberList == null) {
- return filteredMap;
- }
- for (Integer subscriptionId : emergencyNumberList.keySet()) {
- List<EmergencyNumber> allNumbersForSub = emergencyNumberList.get(
- subscriptionId);
- List<EmergencyNumber> numbersForCategoriesPerSub = new ArrayList<>();
- for (EmergencyNumber number : allNumbersForSub) {
- if (number.isInEmergencyServiceCategories(categories)) {
- numbersForCategoriesPerSub.add(number);
- }
- }
- filteredMap.put(
- subscriptionId, numbersForCategoriesPerSub);
- }
- return filteredMap;
- }
}
diff --git a/packages/SettingsLib/SettingsTransition/res/interpolator/fast_out_extra_slow_in.xml b/packages/SettingsLib/SettingsTransition/res/interpolator/fast_out_extra_slow_in.xml
new file mode 100644
index 0000000..a2bbd2b
--- /dev/null
+++ b/packages/SettingsLib/SettingsTransition/res/interpolator/fast_out_extra_slow_in.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1"/>
diff --git a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
index f99fda0..6560a18 100644
--- a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
+++ b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
@@ -23,6 +23,8 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import androidx.core.os.BuildCompat;
+
import com.google.android.material.transition.platform.MaterialSharedAxis;
import com.google.android.material.transition.platform.SlideDistanceProvider;
@@ -47,8 +49,7 @@
transition.setDuration(DURATION);
final Interpolator interpolator =
- AnimationUtils.loadInterpolator(context,
- android.R.interpolator.fast_out_extra_slow_in);
+ AnimationUtils.loadInterpolator(context, R.interpolator.fast_out_extra_slow_in);
transition.setInterpolator(interpolator);
// TODO(b/177480673): Update fade through threshold once (cl/362065364) is released
@@ -64,6 +65,9 @@
* triggered when the page is launched/entering.
*/
public static void applyForwardTransition(Activity activity) {
+ if (!BuildCompat.isAtLeastS()) {
+ return;
+ }
if (activity == null) {
Log.w(TAG, "applyForwardTransition: Invalid activity!");
return;
@@ -87,6 +91,9 @@
* previously-started Activity.
*/
public static void applyBackwardTransition(Activity activity) {
+ if (!BuildCompat.isAtLeastS()) {
+ return;
+ }
if (activity == null) {
Log.w(TAG, "applyBackwardTransition: Invalid activity!");
return;
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
index 0a70f72..673f243 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
@@ -41,6 +41,7 @@
private static final long ONE_DAY_MILLIS = TimeUnit.DAYS.toMillis(1);
private static final long TWO_DAYS_MILLIS = TimeUnit.DAYS.toMillis(2);
private static final long ONE_HOUR_MILLIS = TimeUnit.HOURS.toMillis(1);
+ private static final long ONE_MIN_MILLIS = TimeUnit.MINUTES.toMillis(1);
/**
* This method produces the text used in various places throughout the system to describe the
@@ -63,7 +64,7 @@
// show a less than 15 min remaining warning if appropriate
CharSequence timeString = StringUtil.formatElapsedTime(context,
FIFTEEN_MINUTES_MILLIS,
- false /* withSeconds */);
+ false /* withSeconds */, false /* collapseTimeUnit */);
return getUnderFifteenString(context, timeString, percentageString);
} else if (drainTimeMs >= TWO_DAYS_MILLIS) {
// just say more than two day if over 48 hours
@@ -151,7 +152,7 @@
final long roundedTimeMs = roundTimeToNearestThreshold(drainTimeMs, ONE_HOUR_MILLIS);
CharSequence timeString = StringUtil.formatElapsedTime(context,
roundedTimeMs,
- false /* withSeconds */);
+ false /* withSeconds */, true /* collapseTimeUnit */);
if (TextUtils.isEmpty(percentageString)) {
int id = basedOnUsage
@@ -170,7 +171,7 @@
int resId) {
final long roundedTimeMs = roundTimeToNearestThreshold(drainTimeMs, ONE_HOUR_MILLIS);
CharSequence timeString = StringUtil.formatElapsedTime(context, roundedTimeMs,
- false /* withSeconds */);
+ false /* withSeconds */, false /* collapseTimeUnit */);
return context.getString(resId, timeString);
}
@@ -193,17 +194,18 @@
private static String getRegularTimeRemainingString(Context context, long drainTimeMs,
String percentageString, boolean basedOnUsage) {
- CharSequence timeString = getDateTimeStringFromMs(context, drainTimeMs);
+ CharSequence timeString = StringUtil.formatElapsedTime(context,
+ drainTimeMs, false /* withSeconds */, true /* collapseTimeUnit */);
if (TextUtils.isEmpty(percentageString)) {
int id = basedOnUsage
- ? R.string.power_discharge_by_only_enhanced
- : R.string.power_discharge_by_only;
+ ? R.string.power_remaining_duration_only_enhanced
+ : R.string.power_remaining_duration_only;
return context.getString(id, timeString);
} else {
int id = basedOnUsage
- ? R.string.power_discharge_by_enhanced
- : R.string.power_discharge_by;
+ ? R.string.power_discharging_duration_enhanced
+ : R.string.power_discharging_duration;
return context.getString(id, timeString, percentageString);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
index 83ef4f9..b65637f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
@@ -40,6 +40,8 @@
public static final int SECONDS_PER_HOUR = 60 * 60;
public static final int SECONDS_PER_DAY = 24 * 60 * 60;
+ private static final int LIMITED_TIME_UNIT_COUNT = 2;
+
/**
* Returns elapsed time for the given millis, in the following format:
* 2 days, 5 hr, 40 min, 29 sec
@@ -47,10 +49,12 @@
* @param context the application context
* @param millis the elapsed time in milli seconds
* @param withSeconds include seconds?
+ * @param collapseTimeUnit limit the output to top 2 time unit
+ * e.g 2 days, 5 hr, 40 min, 29 sec will convert to 2 days, 5 hr
* @return the formatted elapsed time
*/
public static CharSequence formatElapsedTime(Context context, double millis,
- boolean withSeconds) {
+ boolean withSeconds, boolean collapseTimeUnit) {
SpannableStringBuilder sb = new SpannableStringBuilder();
int seconds = (int) Math.floor(millis / 1000);
if (!withSeconds) {
@@ -89,6 +93,12 @@
// Everything addable was zero, so nothing was added. We add a zero.
measureList.add(new Measure(0, withSeconds ? MeasureUnit.SECOND : MeasureUnit.MINUTE));
}
+
+ if (collapseTimeUnit && measureList.size() > LIMITED_TIME_UNIT_COUNT) {
+ // Limit the output to top 2 time unit.
+ measureList.subList(LIMITED_TIME_UNIT_COUNT, measureList.size()).clear();
+ }
+
final Measure[] measureArray = measureList.toArray(new Measure[measureList.size()]);
final Locale locale = context.getResources().getConfiguration().locale;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
index 695b5b6..40339de 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
@@ -23,6 +23,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
@@ -126,7 +127,7 @@
List<EmergencyNumber> numbersForSubId = new ArrayList<>();
numbersForSubId.add(emergencyNumber);
numbers.put(subId, numbersForSubId);
- when(mTelephonyManager.getEmergencyNumberList()).thenReturn(numbers);
+ when(mTelephonyManager.getEmergencyNumberList(anyInt())).thenReturn(numbers);
when(emergencyNumber.getNumber()).thenReturn(TELEPHONY_EMERGENCY_NUMBER);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
index 4b779ac..3029736 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
@@ -35,10 +35,12 @@
@RunWith(RobolectricTestRunner.class)
public class PowerUtilTest {
private static final String TEST_BATTERY_LEVEL_10 = "10%";
+ private static final long TEN_SEC_MILLIS = Duration.ofSeconds(10).toMillis();
private static final long SEVENTEEN_MIN_MILLIS = Duration.ofMinutes(17).toMillis();
private static final long FIVE_MINUTES_MILLIS = Duration.ofMinutes(5).toMillis();
private static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis();
private static final long THREE_DAYS_MILLIS = Duration.ofDays(3).toMillis();
+ private static final long TEN_HOURS_MILLIS = Duration.ofHours(10).toMillis();
private static final long THIRTY_HOURS_MILLIS = Duration.ofHours(30).toMillis();
private static final String NORMAL_CASE_EXPECTED_PREFIX = "Should last until about";
private static final String ENHANCED_SUFFIX = " based on your usage";
@@ -152,11 +154,40 @@
THIRTY_HOURS_MILLIS,
TEST_BATTERY_LEVEL_10 /* percentageString */,
false /* basedOnUsage */);
+ String info3 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ THIRTY_HOURS_MILLIS + TEN_MINUTES_MILLIS,
+ null /* percentageString */,
+ false /* basedOnUsage */);
// We only add special mention for the long string
assertThat(info).isEqualTo("About 1 day, 6 hr left based on your usage");
// shortened string should not have extra text
assertThat(info2).isEqualTo("About 1 day, 6 hr left (10%)");
+ // present 2 time unit at most
+ assertThat(info3).isEqualTo("About 1 day, 6 hr left");
+ }
+
+ @Test
+ public void testGetBatteryRemainingStringFormatted_lessThanOneDay_usesCorrectString() {
+ String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ TEN_HOURS_MILLIS,
+ null /* percentageString */,
+ true /* basedOnUsage */);
+ String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ TEN_HOURS_MILLIS,
+ TEST_BATTERY_LEVEL_10 /* percentageString */,
+ false /* basedOnUsage */);
+ String info3 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ TEN_HOURS_MILLIS + TEN_MINUTES_MILLIS + TEN_SEC_MILLIS,
+ null /* percentageString */,
+ false /* basedOnUsage */);
+
+ // We only add special mention for the long string
+ assertThat(info).isEqualTo("About 10 hr left based on your usage");
+ // shortened string should not have extra text
+ assertThat(info2).isEqualTo("About 10 hr left (10%)");
+ // present 2 time unit at most
+ assertThat(info3).isEqualTo("About 10 hr, 10 min left");
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
index b503972..6a1d326 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
@@ -46,7 +46,7 @@
final double testMillis = 5 * DateUtils.MINUTE_IN_MILLIS + 30 * DateUtils.SECOND_IN_MILLIS;
final String expectedTime = "5 min, 30 sec";
- assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true).toString())
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true, false).toString())
.isEqualTo(expectedTime);
}
@@ -55,7 +55,7 @@
final double testMillis = 5 * DateUtils.MINUTE_IN_MILLIS + 30 * DateUtils.SECOND_IN_MILLIS;
final String expectedTime = "6 min";
- assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false, false).toString())
.isEqualTo(expectedTime);
}
@@ -65,7 +65,17 @@
+ 4 * DateUtils.HOUR_IN_MILLIS + 15 * DateUtils.MINUTE_IN_MILLIS;
final String expectedTime = "2 days, 4 hr, 15 min";
- assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false, false).toString())
+ .isEqualTo(expectedTime);
+ }
+
+ @Test
+ public void testFormatElapsedTime_TimeMoreThanOneDayAndCollapseTimeUnit_ShowCorrectly() {
+ final double testMillis = 2 * DateUtils.DAY_IN_MILLIS
+ + 4 * DateUtils.HOUR_IN_MILLIS + 15 * DateUtils.MINUTE_IN_MILLIS;
+ final String expectedTime = "2 days, 4 hr";
+
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false, true).toString())
.isEqualTo(expectedTime);
}
@@ -74,7 +84,7 @@
final double testMillis = 2 * DateUtils.DAY_IN_MILLIS + 15 * DateUtils.MINUTE_IN_MILLIS;
final String expectedTime = "2 days, 15 min";
- assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false, false).toString())
.isEqualTo(expectedTime);
}
@@ -83,7 +93,7 @@
final double testMillis = 0;
final String expectedTime = "0 sec";
- assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true).toString())
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true, false).toString())
.isEqualTo(expectedTime);
}
@@ -92,7 +102,7 @@
final double testMillis = 0;
final String expectedTime = "0 min";
- assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false, false).toString())
.isEqualTo(expectedTime);
}
@@ -101,7 +111,7 @@
final double testMillis = 15 * DateUtils.MINUTE_IN_MILLIS;
final CharSequence charSequence =
- StringUtil.formatElapsedTime(mContext, testMillis, false);
+ StringUtil.formatElapsedTime(mContext, testMillis, false, false);
assertThat(charSequence).isInstanceOf(SpannableStringBuilder.class);
final SpannableStringBuilder expectedString = (SpannableStringBuilder) charSequence;
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 5a3298d..16937b7 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -176,6 +176,7 @@
<uses-permission android:name="android.permission.SET_TIME_ZONE" />
<uses-permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS" />
<uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
+ <uses-permission android:name="android.permission.BYPASS_ROLE_QUALIFICATION" />
<uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.STATUS_BAR" />
@@ -265,10 +266,11 @@
<!-- permissions required for CTS test - PhoneStateListenerTest -->
<uses-permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" />
- <!-- Permissions required for ganting and logging -->
+ <!-- Permissions required for granting and logging -->
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
<uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
+ <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
<!-- Permission required for CTS test - BatterySaverTest -->
<uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 85ecb1c..88d7710 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -275,6 +275,8 @@
<!-- Permission to make accessibility service access Bubbles -->
<uses-permission android:name="android.permission.ADD_TRUSTED_DISPLAY" />
+ <uses-permission android:name="android.permission.MANAGE_SMARTSPACE" />
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 6c7a5b8..0d18b8d 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -24,6 +24,30 @@
"exclude-annotation": "android.platform.test.annotations.Postsubmit"
}
]
+ },
+ {
+ // Permission indicators
+ "name": "CtsPermission4TestCases",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ // Permission indicators
+ "name": "CtsVoiceRecognitionTestCases",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
],
diff --git a/packages/SystemUI/docs/falsing.md b/packages/SystemUI/docs/falsing.md
index 09215ac..0a60270 100644
--- a/packages/SystemUI/docs/falsing.md
+++ b/packages/SystemUI/docs/falsing.md
@@ -70,17 +70,17 @@
### Single Tap
-`FalsingManager#isFalseTap(boolean robustCheck, double falsePenalty)`. This
-method tells the `FalsingManager` that you want to validate a single tap. It
+`FalsingManager#isSimpleTape()`. This method
+performs a only very basic checking, checking that observed `MotionEvent`s are
+all within some small x & y region ("touch slop"). Useful for only the most simple of scenarios,
+you probably want `FalsingManager#isFalseTap` method for most cases.
+
+`FalsingManager#isFalseTap(@Penalty int penalty)`. This
+method tells the `FalsingManager` that you want to thoroughly validate a single tap. It
returns true if it thinks the tap should be rejected (i.e. the tap looks more
like a swipe) and false otherwise.
-`robustCheck` determines what heuristics are used. If set to false, the method
-performs a only very basic checking, checking that observed `MotionEvent`s are
-all within some small x & y region ("touch slop").
-
-When `robustCheck` is set to true, several more advanced rules are additionally
-applied:
+It runs through the following heuristics to validate a tap:
1. If the device recognizes a face (i.e. face-auth) the tap is **accepted**.
2. If the tap is the _second_ tap in recent history and looks like a valid Double Tap
@@ -90,19 +90,18 @@
4. Otherwise the tap is **accepted**.
All the above rules are applied only after first confirming the gesture does
-in fact look like a basic tap.
+in fact look like a simple tap.
-`falsePenalty` is a measure of how much the `HistoryTracker`'s belief should be
+`penalty` is a measure of how much the `HistoryTracker`'s belief should be
penalized in the event that the tap is rejected. This value is only used if
-`robustCheck` is set to true.
+the gesture fails to validate as a simple tap.
-A value of `0` means no change in belief. A value of `1` means a _very_ strong
-confidence in a false tap. In general, as a single tap on the screen is not
-verifiable, a small value should be supplied - on the order of `0.1`. Pass `0`
-if you don't want to penalize belief at all. Pass a higher value
-the earlier in the UX flow your interaction occurs. Once an owner is farther
-along in a UX flow (multiple taps or swipes), its safer to assume that a single
-accidental tap should cause less of a penalty.
+The `@FalsingManager.Penalty` values are fairly straightforward, but note that you
+should generally be choosing `LOW_PENALTY`. It is inherently difficult to know if a
+tap is truly false or not, so a single mis-tap should apply only a small penalty.
+If the owner is further along in a UX flow, and is still mis-tapping, it may make more
+sense to increase the penalty as mis-taps should be less likely to occur after
+several successful gestures.
### Double Tap
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index d6204db..b3aba22 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -27,6 +27,7 @@
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"bcsmartspace/src/**/*.java",
],
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index f8a9a045..35423a9 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -16,7 +16,9 @@
package com.android.systemui.plugins;
+import android.app.smartspace.SmartspaceTarget;
import android.os.Parcelable;
+import android.view.ViewGroup;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -36,9 +38,25 @@
/** Unregister a listener. */
void unregisterListener(SmartspaceTargetListener listener);
+ /**
+ * Create a view to be shown within the parent. Do not add the view, as the parent
+ * will be responsible for correctly setting the LayoutParams
+ */
+ default SmartspaceView getView(ViewGroup parent) {
+ return null;
+ }
+
+ /** Updates Smartspace data and propagates it to any listeners. */
+ void onTargetsAvailable(List<SmartspaceTarget> targets);
+
/** Provides Smartspace data to registered listeners. */
interface SmartspaceTargetListener {
/** Each Parcelable is a SmartspaceTarget that represents a card. */
void onSmartspaceTargetsUpdated(List<? extends Parcelable> targets);
}
+
+ /** View to which this plugin can be registered, in order to get updates. */
+ interface SmartspaceView {
+ void registerDataProvider(BcSmartspaceDataPlugin plugin);
+ }
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 25a3fa2..055fe37 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -19,6 +19,7 @@
import android.content.Intent;
import android.view.View;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
import com.android.systemui.plugins.annotations.ProvidesInterface;
/**
@@ -44,7 +45,15 @@
* specifies an associated view that should be used for the activity launch animation.
*/
void startPendingIntentDismissingKeyguard(PendingIntent intent,
- Runnable intentSentUiThreadCallback, View associatedView);
+ Runnable intentSentUiThreadCallback, @Nullable View associatedView);
+
+ /**
+ * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but also
+ * specifies an animation controller that should be used for the activity launch animation.
+ */
+ void startPendingIntentDismissingKeyguard(PendingIntent intent,
+ Runnable intentSentUiThreadCallback,
+ @Nullable ActivityLaunchAnimator.Controller animationController);
/**
* The intent flag can be specified in startActivity().
@@ -54,7 +63,17 @@
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
void startActivity(Intent intent, boolean dismissShade, Callback callback);
void postStartActivityDismissingKeyguard(Intent intent, int delay);
+ void postStartActivityDismissingKeyguard(Intent intent, int delay,
+ @Nullable ActivityLaunchAnimator.Controller animationController);
void postStartActivityDismissingKeyguard(PendingIntent intent);
+
+ /**
+ * Similar to {@link #postStartActivityDismissingKeyguard(PendingIntent)}, but also specifies an
+ * animation controller that should be used for the activity launch animation.
+ */
+ void postStartActivityDismissingKeyguard(PendingIntent intent,
+ @Nullable ActivityLaunchAnimator.Controller animationController);
+
void postQSRunnableDismissingKeyguard(Runnable runnable);
void dismissKeyguardThenExecute(OnDismissAction action, @Nullable Runnable cancel,
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 1fde6c9..4142e51 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -16,6 +16,7 @@
package com.android.systemui.plugins;
+import android.annotation.IntDef;
import android.net.Uri;
import android.view.MotionEvent;
@@ -24,6 +25,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Interface that decides whether a touch on the phone was accidental. i.e. Pocket Dialing.
@@ -34,6 +37,20 @@
public interface FalsingManager {
int VERSION = 6;
+ int NO_PENALTY = 0;
+ int LOW_PENALTY = 1;
+ int MODERATE_PENALTY = 2;
+ int HIGH_PENALTY = 3;
+
+ @IntDef({
+ NO_PENALTY,
+ LOW_PENALTY,
+ MODERATE_PENALTY,
+ HIGH_PENALTY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Penalty {}
+
void onSuccessfulUnlock();
boolean isUnlockingDisabled();
@@ -41,23 +58,31 @@
/** Returns true if the gesture should be rejected. */
boolean isFalseTouch(int interactionType);
+
/**
- * Returns true if the FalsingManager thinks the last gesure was not a valid tap.
+ * Does basic checking to see if gesture looks like a tap.
*
- * The first parameter, robustCheck, distinctly changes behavior. When set to false,
- * this method simply looks at the last gesture and returns whether it is a tap or not, (as
- * opposed to a swipe or other non-tap gesture). When set to true, a more thorough analysis
- * is performed that can include historical interactions and other contextual cues to see
+ * Only does the most basic of checks. No penalty is applied if this method returns false.
+ *
+ * For more robust analysis, use {@link #isFalseTap(int)}.
+ */
+ boolean isSimpleTap();
+
+ /**
+ * Returns true if the FalsingManager thinks the last gesture was not a valid tap.
+ *
+ * This method runs a more thorough analysis than the similar {@link #isSimpleTap()},
+ * that can include historical interactions and other contextual cues to see
* if the tap looks accidental.
*
- * Set robustCheck to true if you want to validate a tap for launching an action, like opening
- * a notification. Set to false if you simply want to know if the last gesture looked like a
- * tap.
+ * Use this method to validate a tap for launching an action, like opening
+ * a notification.
*
- * The second parameter, falsePenalty, indicates how much this should affect future gesture
- * classifications if this tap looks like a false.
+ * The only parameter, penalty, indicates how much this should affect future gesture
+ * classifications if this tap looks like a false. As single taps are hard to confirm as false
+ * or otherwise, a low penalty value is encouraged unless context indicates otherwise.
*/
- boolean isFalseTap(boolean robustCheck, double falsePenalty);
+ boolean isFalseTap(@Penalty int penalty);
/**
* Returns true if the last two gestures do not look like a double tap.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/animation/ActivityLaunchAnimator.kt
new file mode 100644
index 0000000..5af8dab
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/animation/ActivityLaunchAnimator.kt
@@ -0,0 +1,479 @@
+package com.android.systemui.plugins.animation
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.app.ActivityManager
+import android.app.PendingIntent
+import android.graphics.Matrix
+import android.graphics.Rect
+import android.os.RemoteException
+import android.util.MathUtils
+import android.view.IRemoteAnimationFinishedCallback
+import android.view.IRemoteAnimationRunner
+import android.view.RemoteAnimationAdapter
+import android.view.RemoteAnimationTarget
+import android.view.SyncRtSurfaceTransactionApplier
+import android.view.View
+import android.view.WindowManager
+import android.view.animation.LinearInterpolator
+import android.view.animation.PathInterpolator
+import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.policy.ScreenDecorationsUtils
+import kotlin.math.roundToInt
+
+/**
+ * A class that allows activities to be started in a seamless way from a view that is transforming
+ * nicely into the starting window.
+ */
+class ActivityLaunchAnimator {
+ companion object {
+ const val ANIMATION_DURATION = 400L
+ const val ANIMATION_DURATION_FADE_OUT_CONTENT = 67L
+ const val ANIMATION_DURATION_FADE_IN_WINDOW = 200L
+ private const val ANIMATION_DURATION_NAV_FADE_IN = 266L
+ private const val ANIMATION_DURATION_NAV_FADE_OUT = 133L
+ private const val ANIMATION_DELAY_NAV_FADE_IN =
+ ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN
+ private const val LAUNCH_TIMEOUT = 1000L
+
+ // TODO(b/184121838): Use android.R.interpolator.fast_out_extra_slow_in instead.
+ // TODO(b/184121838): Move com.android.systemui.Interpolators in an animation library we can
+ // reuse here.
+ private val ANIMATION_INTERPOLATOR = PathInterpolator(0.4f, 0f, 0.2f, 1f)
+ private val LINEAR_INTERPOLATOR = LinearInterpolator()
+ private val ALPHA_IN_INTERPOLATOR = PathInterpolator(0.4f, 0f, 1f, 1f)
+ private val ALPHA_OUT_INTERPOLATOR = PathInterpolator(0f, 0f, 0.8f, 1f)
+ private val NAV_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0f, 1f)
+ private val NAV_FADE_OUT_INTERPOLATOR = PathInterpolator(0.2f, 0f, 1f, 1f)
+
+ /**
+ * Given the [linearProgress] of a launch animation, return the linear progress of the
+ * sub-animation starting [delay] ms after the launch animation and that lasts [duration].
+ */
+ @JvmStatic
+ fun getProgress(linearProgress: Float, delay: Long, duration: Long): Float {
+ return MathUtils.constrain(
+ (linearProgress * ANIMATION_DURATION - delay) / duration,
+ 0.0f,
+ 1.0f
+ )
+ }
+ }
+
+ /**
+ * Start an intent and animate the opening window. The intent will be started by running
+ * [intentStarter], which should use the provided [RemoteAnimationAdapter] and return the launch
+ * result. [controller] is responsible from animating the view from which the intent was started
+ * in [Controller.onLaunchAnimationProgress]. No animation will start if there is no window
+ * opening.
+ *
+ * If [controller] is null, then the intent will be started and no animation will run.
+ *
+ * This method will throw any exception thrown by [intentStarter].
+ */
+ inline fun startIntentWithAnimation(
+ controller: Controller?,
+ intentStarter: (RemoteAnimationAdapter?) -> Int
+ ) {
+ if (controller == null) {
+ intentStarter(null)
+ return
+ }
+
+ val runner = Runner(controller)
+ val animationAdapter = RemoteAnimationAdapter(
+ runner,
+ ANIMATION_DURATION,
+ ANIMATION_DURATION - 150 /* statusBarTransitionDelay */
+ )
+ val launchResult = intentStarter(animationAdapter)
+ val willAnimate = launchResult == ActivityManager.START_TASK_TO_FRONT ||
+ launchResult == ActivityManager.START_SUCCESS
+ runner.context.mainExecutor.execute { controller.onIntentStarted(willAnimate) }
+
+ // If we expect an animation, post a timeout to cancel it in case the remote animation is
+ // never started.
+ if (willAnimate) {
+ runner.postTimeout()
+ }
+ }
+
+ /**
+ * Same as [startIntentWithAnimation] but allows [intentStarter] to throw a
+ * [PendingIntent.CanceledException] which must then be handled by the caller. This is useful
+ * for Java caller starting a [PendingIntent].
+ */
+ @Throws(PendingIntent.CanceledException::class)
+ fun startPendingIntentWithAnimation(
+ controller: Controller?,
+ intentStarter: PendingIntentStarter
+ ) {
+ startIntentWithAnimation(controller) { intentStarter.startPendingIntent(it) }
+ }
+
+ interface PendingIntentStarter {
+ /**
+ * Start a pending intent using the provided [animationAdapter] and return the launch
+ * result.
+ */
+ @Throws(PendingIntent.CanceledException::class)
+ fun startPendingIntent(animationAdapter: RemoteAnimationAdapter?): Int
+ }
+
+ /**
+ * A controller that takes care of applying the animation to an expanding view.
+ *
+ * Note that all callbacks (onXXX methods) are all called on the main thread.
+ */
+ interface Controller {
+ companion object {
+ /**
+ * Return a [Controller] that will animate and expand [view] into the opening window.
+ *
+ * Important: The view must be attached to the window when calling this function and
+ * during the animation.
+ */
+ @JvmStatic
+ fun fromView(view: View): Controller = GhostedViewLaunchAnimatorController(view)
+ }
+
+ /**
+ * Return the root [View] that contains the view that started the intent and will be
+ * animating together with the window.
+ *
+ * This view will be used to:
+ * - Get the associated [Context].
+ * - Compute whether we are expanding fully above the current window.
+ * - Apply surface transactions in sync with RenderThread.
+ */
+ fun getRootView(): View
+
+ /**
+ * Return the [State] of the view that will be animated. We will animate from this state to
+ * the final window state.
+ *
+ * Note: This state will be mutated and passed to [onLaunchAnimationProgress] during the
+ * animation.
+ */
+ fun createAnimatorState(): State
+
+ /**
+ * The intent was started. If [willAnimate] is false, nothing else will happen and the
+ * animation will not be started.
+ */
+ fun onIntentStarted(willAnimate: Boolean) {}
+
+ /**
+ * The animation started. This is typically used to initialize any additional resource
+ * needed for the animation. [isExpandingFullyAbove] will be true if the window is expanding
+ * fully above the [root view][getRootView].
+ */
+ fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {}
+
+ /** The animation made progress and the expandable view [state] should be updated. */
+ fun onLaunchAnimationProgress(state: State, progress: Float, linearProgress: Float) {}
+
+ /**
+ * The animation ended. This will be called *if and only if* [onLaunchAnimationStart] was
+ * called previously. This is typically used to clean up the resources initialized when the
+ * animation was started.
+ */
+ fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {}
+
+ /**
+ * The animation was cancelled remotely. Note that [onLaunchAnimationEnd] will still be
+ * called after this if the animation was already started, i.e. if [onLaunchAnimationStart]
+ * was called before the cancellation.
+ */
+ fun onLaunchAnimationCancelled() {}
+
+ /**
+ * The remote animation was not started within the expected time. It timed out and will
+ * never [start][onLaunchAnimationStart].
+ */
+ fun onLaunchAnimationTimedOut() {}
+
+ /**
+ * The animation was aborted because the opening window was not found. It will never
+ * [start][onLaunchAnimationStart].
+ */
+ fun onLaunchAnimationAborted() {}
+ }
+
+ /** The state of an expandable view during an [ActivityLaunchAnimator] animation. */
+ open class State(
+ /** The position of the view in screen space coordinates. */
+ var top: Int,
+ var bottom: Int,
+ var left: Int,
+ var right: Int,
+
+ var topCornerRadius: Float = 0f,
+ var bottomCornerRadius: Float = 0f,
+
+ var contentAlpha: Float = 1f,
+ var backgroundAlpha: Float = 1f
+ ) {
+ private val startTop = top
+ private val startLeft = left
+ private val startRight = right
+
+ val width: Int
+ get() = right - left
+
+ val height: Int
+ get() = bottom - top
+
+ open val topChange: Int
+ get() = top - startTop
+
+ val leftChange: Int
+ get() = left - startLeft
+
+ val rightChange: Int
+ get() = right - startRight
+ }
+
+ @VisibleForTesting
+ class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
+ private val rootView = controller.getRootView()
+ @PublishedApi internal val context = rootView.context
+ private val transactionApplier = SyncRtSurfaceTransactionApplier(rootView)
+ private var animator: ValueAnimator? = null
+
+ private var windowCrop = Rect()
+ private var timedOut = false
+ private var cancelled = false
+
+ // A timeout to cancel the remote animation if it is not started within X milliseconds after
+ // the intent was started.
+ //
+ // Note that this is important to keep this a Runnable (and not a Kotlin lambda), otherwise
+ // it will be automatically converted when posted and we wouldn't be able to remove it after
+ // posting it.
+ private var onTimeout = Runnable { onAnimationTimedOut() }
+
+ @PublishedApi
+ internal fun postTimeout() {
+ rootView.postDelayed(onTimeout, LAUNCH_TIMEOUT)
+ }
+
+ private fun removeTimeout() {
+ rootView.removeCallbacks(onTimeout)
+ }
+
+ override fun onAnimationStart(
+ @WindowManager.TransitionOldType transit: Int,
+ remoteAnimationTargets: Array<out RemoteAnimationTarget>,
+ remoteAnimationWallpaperTargets: Array<out RemoteAnimationTarget>,
+ remoteAnimationNonAppTargets: Array<out RemoteAnimationTarget>,
+ iRemoteAnimationFinishedCallback: IRemoteAnimationFinishedCallback
+ ) {
+ removeTimeout()
+
+ // The animation was started too late and we already notified the controller that it
+ // timed out.
+ if (timedOut) {
+ invokeCallback(iRemoteAnimationFinishedCallback)
+ return
+ }
+
+ // This should not happen, but let's make sure we don't start the animation if it was
+ // cancelled before and we already notified the controller.
+ if (cancelled) {
+ return
+ }
+
+ context.mainExecutor.execute {
+ startAnimation(remoteAnimationTargets, iRemoteAnimationFinishedCallback)
+ }
+ }
+
+ private fun startAnimation(
+ remoteAnimationTargets: Array<out RemoteAnimationTarget>,
+ iCallback: IRemoteAnimationFinishedCallback
+ ) {
+ val window = remoteAnimationTargets.firstOrNull {
+ it.mode == RemoteAnimationTarget.MODE_OPENING
+ }
+
+ if (window == null) {
+ removeTimeout()
+ invokeCallback(iCallback)
+ controller.onLaunchAnimationAborted()
+ return
+ }
+
+ val navigationBar = remoteAnimationTargets.firstOrNull {
+ it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
+ }
+
+ // Start state.
+ val state = controller.createAnimatorState()
+
+ val startTop = state.top
+ val startBottom = state.bottom
+ val startLeft = state.left
+ val startRight = state.right
+
+ val startTopCornerRadius = state.topCornerRadius
+ val startBottomCornerRadius = state.bottomCornerRadius
+
+ // End state.
+ val windowBounds = window.screenSpaceBounds
+ val endTop = windowBounds.top
+ val endBottom = windowBounds.bottom
+ val endLeft = windowBounds.left
+ val endRight = windowBounds.right
+
+ // TODO(b/184121838): Ensure that we are launching on the same screen.
+ val rootViewLocation = rootView.locationOnScreen
+ val isExpandingFullyAbove = endTop <= rootViewLocation[1] &&
+ endBottom >= rootViewLocation[1] + rootView.height &&
+ endLeft <= rootViewLocation[0] &&
+ endRight >= rootViewLocation[0] + rootView.width
+
+ // TODO(b/184121838): We should somehow get the top and bottom radius of the window.
+ val endRadius = if (isExpandingFullyAbove) {
+ // Most of the time, expanding fully above the root view means expanding in full
+ // screen.
+ ScreenDecorationsUtils.getWindowCornerRadius(context.resources)
+ } else {
+ // This usually means we are in split screen mode, so 2 out of 4 corners will have
+ // a radius of 0.
+ 0f
+ }
+
+ // Update state.
+ val animator = ValueAnimator.ofFloat(0f, 1f)
+ this.animator = animator
+ animator.duration = ANIMATION_DURATION
+ animator.interpolator = LINEAR_INTERPOLATOR
+
+ animator.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
+ controller.onLaunchAnimationStart(isExpandingFullyAbove)
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ invokeCallback(iCallback)
+ controller.onLaunchAnimationEnd(isExpandingFullyAbove)
+ }
+ })
+
+ animator.addUpdateListener { animation ->
+ if (cancelled) {
+ return@addUpdateListener
+ }
+
+ val linearProgress = animation.animatedFraction
+ val progress = ANIMATION_INTERPOLATOR.getInterpolation(linearProgress)
+
+ state.top = lerp(startTop, endTop, progress).roundToInt()
+ state.bottom = lerp(startBottom, endBottom, progress).roundToInt()
+ state.left = lerp(startLeft, endLeft, progress).roundToInt()
+ state.right = lerp(startRight, endRight, progress).roundToInt()
+
+ state.topCornerRadius = MathUtils.lerp(startTopCornerRadius, endRadius, progress)
+ state.bottomCornerRadius =
+ MathUtils.lerp(startBottomCornerRadius, endRadius, progress)
+
+ val contentAlphaProgress = getProgress(linearProgress, 0,
+ ANIMATION_DURATION_FADE_OUT_CONTENT)
+ state.contentAlpha =
+ 1 - ALPHA_OUT_INTERPOLATOR.getInterpolation(contentAlphaProgress)
+
+ val backgroundAlphaProgress = getProgress(linearProgress,
+ ANIMATION_DURATION_FADE_OUT_CONTENT, ANIMATION_DURATION_FADE_IN_WINDOW)
+ state.backgroundAlpha =
+ 1 - ALPHA_IN_INTERPOLATOR.getInterpolation(backgroundAlphaProgress)
+
+ applyStateToWindow(window, state)
+ navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }
+ controller.onLaunchAnimationProgress(state, progress, linearProgress)
+ }
+
+ animator.start()
+ }
+
+ private fun applyStateToWindow(window: RemoteAnimationTarget, state: State) {
+ val m = Matrix()
+ m.postTranslate(0f, (state.top - window.sourceContainerBounds.top).toFloat())
+ windowCrop.set(state.left, 0, state.right, state.height)
+
+ val cornerRadius = minOf(state.topCornerRadius, state.bottomCornerRadius)
+ val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(window.leash)
+ .withAlpha(1f)
+ .withMatrix(m)
+ .withWindowCrop(windowCrop)
+ .withLayer(window.prefixOrderIndex)
+ .withCornerRadius(cornerRadius)
+ .withVisibility(true)
+ .build()
+
+ transactionApplier.scheduleApply(params)
+ }
+
+ private fun applyStateToNavigationBar(
+ navigationBar: RemoteAnimationTarget,
+ state: State,
+ linearProgress: Float
+ ) {
+ val fadeInProgress = getProgress(linearProgress, ANIMATION_DELAY_NAV_FADE_IN,
+ ANIMATION_DURATION_NAV_FADE_OUT)
+
+ val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash)
+ if (fadeInProgress > 0) {
+ val m = Matrix()
+ m.postTranslate(0f, (state.top - navigationBar.sourceContainerBounds.top).toFloat())
+ windowCrop.set(state.left, 0, state.right, state.height)
+ params
+ .withAlpha(NAV_FADE_IN_INTERPOLATOR.getInterpolation(fadeInProgress))
+ .withMatrix(m)
+ .withWindowCrop(windowCrop)
+ .withVisibility(true)
+ } else {
+ val fadeOutProgress = getProgress(linearProgress, 0,
+ ANIMATION_DURATION_NAV_FADE_OUT)
+ params.withAlpha(1f - NAV_FADE_OUT_INTERPOLATOR.getInterpolation(fadeOutProgress))
+ }
+
+ transactionApplier.scheduleApply(params.build())
+ }
+
+ private fun onAnimationTimedOut() {
+ if (cancelled) {
+ return
+ }
+
+ timedOut = true
+ controller.onLaunchAnimationTimedOut()
+ }
+
+ override fun onAnimationCancelled() {
+ if (timedOut) {
+ return
+ }
+
+ cancelled = true
+ removeTimeout()
+ context.mainExecutor.execute {
+ animator?.cancel()
+ controller.onLaunchAnimationCancelled()
+ }
+ }
+
+ private fun invokeCallback(iCallback: IRemoteAnimationFinishedCallback) {
+ try {
+ iCallback.onAnimationFinished()
+ } catch (e: RemoteException) {
+ e.printStackTrace()
+ }
+ }
+
+ private fun lerp(start: Int, stop: Int, amount: Float): Float {
+ return MathUtils.lerp(start.toFloat(), stop.toFloat(), amount)
+ }
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/animation/GhostedViewLaunchAnimatorController.kt
new file mode 100644
index 0000000..a5494ad
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/animation/GhostedViewLaunchAnimatorController.kt
@@ -0,0 +1,329 @@
+package com.android.systemui.plugins.animation
+
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.PixelFormat
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.LayerDrawable
+import android.view.GhostView
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+
+/**
+ * A base implementation of [ActivityLaunchAnimator.Controller] which creates a [ghost][GhostView]
+ * of [ghostedView] as well as an expandable background view, which are drawn and animated instead
+ * of the ghosted view.
+ *
+ * Important: [ghostedView] must be attached to the window when calling this function and during the
+ * animation.
+ *
+ * Note: Avoid instantiating this directly and call [ActivityLaunchAnimator.Controller.fromView]
+ * whenever possible instead.
+ */
+open class GhostedViewLaunchAnimatorController(
+ /** The view that will be ghosted and from which the background will be extracted. */
+ private val ghostedView: View
+) : ActivityLaunchAnimator.Controller {
+ /** The root view to which we will add the ghost view and expanding background. */
+ private val rootView = ghostedView.rootView as ViewGroup
+ private val rootViewOverlay = rootView.overlay
+
+ /** The ghost view that is drawn and animated instead of the ghosted view. */
+ private var ghostView: View? = null
+
+ /**
+ * The expanding background view that will be added to [rootView] (below [ghostView]) and
+ * animate.
+ */
+ private var backgroundView: FrameLayout? = null
+
+ /**
+ * The drawable wrapping the [ghostedView] background and used as background for
+ * [backgroundView].
+ */
+ private var backgroundDrawable: WrappedDrawable? = null
+ private var startBackgroundAlpha: Int = 0xFF
+
+ /**
+ * Return the background of the [ghostedView]. This background will be used to draw the
+ * background of the background view that is expanding up to the final animation position. This
+ * is called at the start of the animation.
+ *
+ * Note that during the animation, the alpha value value of this background will be set to 0,
+ * then set back to its initial value at the end of the animation.
+ */
+ protected open fun getBackground(): Drawable? = ghostedView.background
+
+ /**
+ * Set the corner radius of [background]. The background is the one that was returned by
+ * [getBackground].
+ */
+ protected open fun setBackgroundCornerRadius(
+ background: Drawable,
+ topCornerRadius: Float,
+ bottomCornerRadius: Float
+ ) {
+ // By default, we rely on WrappedDrawable to set/restore the background radii before/after
+ // each draw.
+ backgroundDrawable?.setBackgroundRadius(topCornerRadius, bottomCornerRadius)
+ }
+
+ /** Return the current top corner radius of the background. */
+ protected open fun getCurrentTopCornerRadius(): Float {
+ val drawable = getBackground() ?: return 0f
+ val gradient = findGradientDrawable(drawable) ?: return 0f
+
+ // TODO(b/184121838): Support more than symmetric top & bottom radius.
+ return gradient.cornerRadii?.get(CORNER_RADIUS_TOP_INDEX) ?: gradient.cornerRadius
+ }
+
+ /** Return the current bottom corner radius of the background. */
+ protected open fun getCurrentBottomCornerRadius(): Float {
+ val drawable = getBackground() ?: return 0f
+ val gradient = findGradientDrawable(drawable) ?: return 0f
+
+ // TODO(b/184121838): Support more than symmetric top & bottom radius.
+ return gradient.cornerRadii?.get(CORNER_RADIUS_BOTTOM_INDEX) ?: gradient.cornerRadius
+ }
+
+ override fun getRootView(): View {
+ return rootView
+ }
+
+ override fun createAnimatorState(): ActivityLaunchAnimator.State {
+ val location = ghostedView.locationOnScreen
+ return ActivityLaunchAnimator.State(
+ top = location[1],
+ bottom = location[1] + ghostedView.height,
+ left = location[0],
+ right = location[0] + ghostedView.width,
+ topCornerRadius = getCurrentTopCornerRadius(),
+ bottomCornerRadius = getCurrentBottomCornerRadius()
+ )
+ }
+
+ override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
+ backgroundView = FrameLayout(rootView.context).apply {
+ forceHasOverlappingRendering(false)
+ }
+ rootViewOverlay.add(backgroundView)
+
+ // We wrap the ghosted view background and use it to draw the expandable background. Its
+ // alpha will be set to 0 as soon as we start drawing the expanding background.
+ val drawable = getBackground()
+ startBackgroundAlpha = drawable?.alpha ?: 0xFF
+ backgroundDrawable = WrappedDrawable(drawable)
+ backgroundView?.background = backgroundDrawable
+
+ // Create a ghost of the view that will be moving and fading out. This allows to fade out
+ // the content before fading out the background.
+ ghostView = GhostView.addGhost(ghostedView, rootView).apply {
+ setLayerType(View.LAYER_TYPE_HARDWARE, null)
+ }
+ }
+
+ override fun onLaunchAnimationProgress(
+ state: ActivityLaunchAnimator.State,
+ progress: Float,
+ linearProgress: Float
+ ) {
+ val ghostView = this.ghostView!!
+ ghostView.translationX = (state.leftChange + state.rightChange) / 2.toFloat()
+ ghostView.translationY = state.topChange.toFloat()
+ ghostView.alpha = state.contentAlpha
+
+ val backgroundView = this.backgroundView!!
+ backgroundView.top = state.top
+ backgroundView.bottom = state.bottom
+ backgroundView.left = state.left
+ backgroundView.right = state.right
+
+ val backgroundDrawable = backgroundDrawable!!
+ backgroundDrawable.alpha = (0xFF * state.backgroundAlpha).toInt()
+ backgroundDrawable.wrapped?.let {
+ setBackgroundCornerRadius(it, state.topCornerRadius, state.bottomCornerRadius)
+ }
+ }
+
+ override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
+ backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha
+
+ GhostView.removeGhost(ghostedView)
+ rootViewOverlay.remove(backgroundView)
+ ghostedView.invalidate()
+ }
+
+ companion object {
+ private const val CORNER_RADIUS_TOP_INDEX = 0
+ private const val CORNER_RADIUS_BOTTOM_INDEX = 4
+
+ /**
+ * Return the first [GradientDrawable] found in [drawable], or null if none is found. If
+ * [drawable] is a [LayerDrawable], this will return the first layer that is a
+ * [GradientDrawable].
+ */
+ private fun findGradientDrawable(drawable: Drawable): GradientDrawable? {
+ if (drawable is GradientDrawable) {
+ return drawable
+ }
+
+ if (drawable is LayerDrawable) {
+ for (i in 0 until drawable.numberOfLayers) {
+ val maybeGradient = drawable.getDrawable(i)
+ if (maybeGradient is GradientDrawable) {
+ return maybeGradient
+ }
+ }
+ }
+
+ return null
+ }
+ }
+
+ private class WrappedDrawable(val wrapped: Drawable?) : Drawable() {
+ companion object {
+ private val SRC_MODE = PorterDuffXfermode(PorterDuff.Mode.SRC)
+ }
+
+ private var currentAlpha = 0xFF
+ private var previousBounds = Rect()
+
+ private var cornerRadii = FloatArray(8) { -1f }
+ private var previousCornerRadii = FloatArray(8)
+
+ override fun draw(canvas: Canvas) {
+ val wrapped = this.wrapped ?: return
+
+ wrapped.copyBounds(previousBounds)
+
+ wrapped.alpha = currentAlpha
+ wrapped.bounds = bounds
+ setXfermode(wrapped, SRC_MODE)
+ applyBackgroundRadii()
+
+ wrapped.draw(canvas)
+
+ // The background view (and therefore this drawable) is drawn before the ghost view, so
+ // the ghosted view background alpha should always be 0 when it is drawn above the
+ // background.
+ wrapped.alpha = 0
+ wrapped.bounds = previousBounds
+ setXfermode(wrapped, null)
+ restoreBackgroundRadii()
+ }
+
+ override fun setAlpha(alpha: Int) {
+ if (alpha != currentAlpha) {
+ currentAlpha = alpha
+ invalidateSelf()
+ }
+ }
+
+ override fun getAlpha() = currentAlpha
+
+ override fun getOpacity(): Int {
+ val wrapped = this.wrapped ?: return PixelFormat.TRANSPARENT
+
+ val previousAlpha = wrapped.alpha
+ wrapped.alpha = currentAlpha
+ val opacity = wrapped.opacity
+ wrapped.alpha = previousAlpha
+ return opacity
+ }
+
+ override fun setColorFilter(filter: ColorFilter?) {
+ wrapped?.colorFilter = filter
+ }
+
+ private fun setXfermode(background: Drawable, mode: PorterDuffXfermode?) {
+ if (background !is LayerDrawable) {
+ background.setXfermode(mode)
+ return
+ }
+
+ // We set the xfermode on the first layer that is not a mask. Most of the time it will
+ // be the "background layer".
+ for (i in 0 until background.numberOfLayers) {
+ if (background.getId(i) != android.R.id.mask) {
+ background.getDrawable(i).setXfermode(mode)
+ break
+ }
+ }
+ }
+
+ fun setBackgroundRadius(topCornerRadius: Float, bottomCornerRadius: Float) {
+ updateRadii(cornerRadii, topCornerRadius, bottomCornerRadius)
+ invalidateSelf()
+ }
+
+ private fun updateRadii(
+ radii: FloatArray,
+ topCornerRadius: Float,
+ bottomCornerRadius: Float
+ ) {
+ radii[0] = topCornerRadius
+ radii[1] = topCornerRadius
+ radii[2] = topCornerRadius
+ radii[3] = topCornerRadius
+
+ radii[4] = bottomCornerRadius
+ radii[5] = bottomCornerRadius
+ radii[6] = bottomCornerRadius
+ radii[7] = bottomCornerRadius
+ }
+
+ private fun applyBackgroundRadii() {
+ if (cornerRadii[0] < 0 || wrapped == null) {
+ return
+ }
+
+ savePreviousBackgroundRadii(wrapped)
+ applyBackgroundRadii(wrapped, cornerRadii)
+ }
+
+ private fun savePreviousBackgroundRadii(background: Drawable) {
+ // TODO(b/184121838): This method assumes that all GradientDrawable in background will
+ // have the same radius. Should we save/restore the radii for each layer instead?
+ val gradient = findGradientDrawable(background) ?: return
+
+ // TODO(b/184121838): GradientDrawable#getCornerRadii clones its radii array. Should we
+ // try to avoid that?
+ val radii = gradient.cornerRadii
+ if (radii != null) {
+ radii.copyInto(previousCornerRadii)
+ } else {
+ // Copy the cornerRadius into previousCornerRadii.
+ val radius = gradient.cornerRadius
+ updateRadii(previousCornerRadii, radius, radius)
+ }
+ }
+
+ private fun applyBackgroundRadii(drawable: Drawable, radii: FloatArray) {
+ if (drawable is GradientDrawable) {
+ drawable.cornerRadii = radii
+ return
+ }
+
+ if (drawable !is LayerDrawable) {
+ return
+ }
+
+ for (i in 0 until drawable.numberOfLayers) {
+ (drawable.getDrawable(i) as? GradientDrawable)?.cornerRadii = radii
+ }
+ }
+
+ private fun restoreBackgroundRadii() {
+ if (cornerRadii[0] < 0 || wrapped == null) {
+ return
+ }
+
+ applyBackgroundRadii(wrapped, previousCornerRadii)
+ }
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index c9f2401..46237148 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -15,10 +15,12 @@
package com.android.systemui.plugins.qs;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.metrics.LogMaker;
import android.service.quicksettings.Tile;
+import android.view.View;
import com.android.internal.logging.InstanceId;
import com.android.systemui.plugins.annotations.DependsOn;
@@ -53,10 +55,16 @@
void removeCallbacks();
QSIconView createTileView(Context context);
-
+
void click();
void secondaryClick();
- void longClick();
+
+ /**
+ * The tile was long clicked.
+ *
+ * @param view The view that was clicked.
+ */
+ void longClick(@Nullable View view);
void userSwitch(int currentUser);
int getMetricsCategory();
diff --git a/packages/SystemUI/res/drawable/circle_wallet_primary_50dp.xml b/packages/SystemUI/res/drawable/circle_wallet_primary_50dp.xml
index de4d882..41d88b4 100644
--- a/packages/SystemUI/res/drawable/circle_wallet_primary_50dp.xml
+++ b/packages/SystemUI/res/drawable/circle_wallet_primary_50dp.xml
@@ -18,5 +18,6 @@
<size
android:height="50dp"
android:width="50dp" />
- <solid android:color="#1A73E8" />
+ <solid android:color="@android:color/transparent" />
+ <stroke android:width="2dp" android:color="#AECBFA" />
</shape>
diff --git a/packages/SystemUI/res/drawable/ic_move_magnification.xml b/packages/SystemUI/res/drawable/ic_move_magnification.xml
index ed97d0cc..642fc31 100644
--- a/packages/SystemUI/res/drawable/ic_move_magnification.xml
+++ b/packages/SystemUI/res/drawable/ic_move_magnification.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -18,7 +19,7 @@
<item>
<shape android:shape="rectangle">
<solid
- android:color="@android:color/black" />
+ android:color="@color/magnification_switch_button_color" />
<size
android:height="@dimen/magnification_drag_view_size"
android:width="@dimen/magnification_drag_view_size"/>
@@ -26,9 +27,14 @@
</item>
<item
android:gravity="center">
- <vector android:height="28dp" android:viewportHeight="512"
- android:viewportWidth="512" android:width="28dp">
- <path android:fillColor="#FFFFFF" android:pathData="M506.528,243.712l-96.224,-80c-4.8,-4 -11.456,-4.832 -17.056,-2.208C387.616,164.16 384,169.792 384,176v48h-96v-96h48c6.208,0 11.84,-3.616 14.496,-9.248c2.624,-5.632 1.792,-12.288 -2.208,-17.056l-80,-96.224c-6.08,-7.296 -18.496,-7.296 -24.608,0l-80,96.224c-3.968,4.8 -4.832,11.456 -2.176,17.056C164.128,124.384 169.792,128 176,128h48v96h-96v-48c0,-6.208 -3.616,-11.84 -9.248,-14.496c-5.6,-2.624 -12.256,-1.792 -17.056,2.208l-96.224,80c-7.296,6.08 -7.296,18.496 0,24.608l96.224,80c4.8,3.968 11.456,4.832 17.056,2.176C124.416,347.872 128,342.208 128,336v-48h96v96h-48c-6.208,0 -11.872,3.616 -14.496,9.248c-2.656,5.632 -1.792,12.288 2.176,17.056l80,96.224c6.08,7.296 18.496,7.296 24.608,0l80,-96.224c4,-4.8 4.832,-11.456 2.208,-17.056C347.84,387.616 342.208,384 336,384h-48v-96h96v48c0,6.208 3.616,11.872 9.248,14.496c5.632,2.656 12.288,1.792 17.056,-2.176l96.224,-80C513.824,262.208 513.824,249.792 506.528,243.712z"/>
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M18.19,12.44l-3.24,-1.62c1.29,-1 2.12,-2.56 2.12,-4.32c0,-3.03 -2.47,-5.5 -5.5,-5.5s-5.5,2.47 -5.5,5.5c0,2.13 1.22,3.98 3,4.89v3.26c-2.11,-0.45 -2.01,-0.44 -2.26,-0.44c-0.53,0 -1.03,0.21 -1.41,0.59L4,16.22l5.09,5.09C9.52,21.75 10.12,22 10.74,22h6.3c0.98,0 1.81,-0.7 1.97,-1.67l0.8,-4.71C20.03,14.32 19.38,13.04 18.19,12.44zM17.84,15.29L17.04,20h-6.3c-0.09,0 -0.17,-0.04 -0.24,-0.1l-3.68,-3.68l4.25,0.89V6.5c0,-0.28 0.22,-0.5 0.5,-0.5c0.28,0 0.5,0.22 0.5,0.5v6h1.76l3.46,1.73C17.69,14.43 17.91,14.86 17.84,15.29zM8.07,6.5c0,-1.93 1.57,-3.5 3.5,-3.5s3.5,1.57 3.5,3.5c0,0.95 -0.38,1.81 -1,2.44V6.5c0,-1.38 -1.12,-2.5 -2.5,-2.5c-1.38,0 -2.5,1.12 -2.5,2.5v2.44C8.45,8.31 8.07,7.45 8.07,6.5z"
+ android:fillColor="#FFFFFF"/>
</vector>
</item>
</layer-list>
diff --git a/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml b/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
index 96e0193..5bb7390 100644
--- a/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
+++ b/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
@@ -30,9 +30,16 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z" />
+ <group>
+ <clip-path
+ android:pathData="M0,0h24v24h-24z"/>
+ <path
+ android:pathData="M11,6.05V8.05H14.59L8,14.64V11.05H6V18.05H13V16.05H9.41L16,9.46V13.05H18V6.05H11Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M20,4.05V20.05H4V4.05H20ZM22,2.05H2V22.05H22V2.05Z"
+ android:fillColor="#ffffff"/>
+ </group>
</vector>
</item>
diff --git a/packages/SystemUI/res/drawable/ic_open_in_new_window.xml b/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
index 368c8df..2d8a5d9 100644
--- a/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
+++ b/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
@@ -26,30 +26,19 @@
<item>
<vector
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <group
- android:translateX="1.500000"
- android:translateY="1.500000">
- <path
- android:fillType="evenOdd"
- android:strokeColor="#FFFFFF"
- android:strokeWidth="2"
- android:pathData="M 3.5 1.5 L 17.5 1.5 Q 19.5 1.5 19.5 3.5 L 19.5 17.5 Q 19.5 19.5 17.5 19.5 L 3.5 19.5 Q 1.5 19.5 1.5 17.5 L 1.5 3.5 Q 1.5 1.5 3.5 1.5 Z" />
- <path
- android:fillType="evenOdd"
- android:strokeColor="#FFFFFF"
- android:strokeWidth="1.5"
- android:pathData="M 4.25 4.25 H 8.75 V 8.75 H 4.25 V 4.25 Z" />
- <path
- android:fillColor="#FFFFFF"
- android:fillType="evenOdd"
- android:strokeWidth="1"
- android:pathData="M 12.5 13.92 L 15.59 17 L 17 15.59 L 13.91 12.5 L 16.5 12.5 L 16.5 10.5 L 10.5 10.5 L 10.5 16.5 L 12.5 16.5 Z" />
- </group>
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M2,12.05V22.05H22V2.05H12V4.05H20V20.05H4V12.05H2Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M10,2.05H2V10.05H10V2.05Z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M18,11.05V13.05H14.41L18.95,17.59L17.54,19L13,14.46V18.05H11V11.05H18Z"
+ android:fillColor="#ffffff"/>
</vector>
</item>
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index bbf69a9..1f90476 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -24,7 +24,7 @@
android:minHeight="48dp"
android:clickable="false"
android:focusable="true"
- android:theme="@style/QSHeaderTheme">
+ android:theme="@style/Theme.SystemUI.QuickSettings.Header">
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 1630244..a99edb9 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -51,6 +51,14 @@
sysui:ignoreRightInset="true"
/>
+ <com.android.systemui.statusbar.ScrimView
+ android:id="@+id/scrim_notifications"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:importantForAccessibility="no"
+ sysui:ignoreRightInset="true"
+ />
+
<com.android.systemui.statusbar.LightRevealScrim
android:id="@+id/light_reveal_scrim"
android:layout_width="match_parent"
@@ -100,4 +108,12 @@
android:ellipsize="marquee"
android:focusable="true" />
</LinearLayout>
+
+ <com.android.systemui.biometrics.AuthRippleView
+ android:id="@+id/auth_ripple"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:importantForAccessibility="no"
+ sysui:ignoreRightInset="true"
+ />
</com.android.systemui.statusbar.phone.NotificationShadeWindowView>
diff --git a/packages/SystemUI/res/layout/window_magnifier_view.xml b/packages/SystemUI/res/layout/window_magnifier_view.xml
index efd24c7..96de5a9 100644
--- a/packages/SystemUI/res/layout/window_magnifier_view.xml
+++ b/packages/SystemUI/res/layout/window_magnifier_view.xml
@@ -77,6 +77,8 @@
android:layout_height="@dimen/magnification_drag_view_size"
android:layout_margin="@dimen/magnification_outer_border_margin"
android:layout_gravity="right|bottom"
+ android:paddingEnd="@dimen/magnifier_drag_handle_padding"
+ android:paddingBottom="@dimen/magnifier_drag_handle_padding"
android:scaleType="center"
android:importantForAccessibility="no"
android:src="@drawable/ic_move_magnification"/>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 4fdeb6f..cd2395e 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -29,4 +29,10 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
+ <!-- Screenshots -->
+ <style name="LongScreenshotActivity" parent="@android:style/Theme.DeviceDefault.DayNight">
+ <item name="android:windowLightStatusBar">false</item>
+ <item name="android:windowLightNavigationBar">false</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index bd92299..0125144 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -642,4 +642,11 @@
<!-- Whether to use window background blur for the volume dialog. -->
<bool name="config_volumeDialogUseBackgroundBlur">false</bool>
+
+ <!-- The properties of the face auth camera in pixels -->
+ <integer-array name="config_face_auth_props">
+ <!-- sensorLocationX -->
+ <!-- sensorLocationY -->
+ <!--sensorRadius -->
+ </integer-array>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5a21b30..237edf8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -718,6 +718,7 @@
<item name="keyguard_clock_line_spacing_scale_burmese" type="dimen" format="float">1</item>
<item name="scrim_behind_alpha" format="float" type="dimen">0.62</item>
+ <dimen name="notification_scrim_corner_radius">32dp</dimen>
<!-- The minimum amount the user needs to swipe to go to the camera / phone. -->
<dimen name="keyguard_min_swipe_amount">110dp</dimen>
@@ -1253,11 +1254,13 @@
<dimen name="magnification_drag_view_size">38dp</dimen>
<dimen name="magnification_controls_size">90dp</dimen>
<dimen name="magnification_switch_button_size">60dp</dimen>
- <dimen name="magnification_switch_button_padding">12dp</dimen>
+ <dimen name="magnification_switch_button_padding">6dp</dimen>
<dimen name="magnifier_left_right_controls_width">35dp</dimen>
<dimen name="magnifier_left_right_controls_height">45dp</dimen>
<dimen name="magnifier_up_down_controls_width">45dp</dimen>
<dimen name="magnifier_up_down_controls_height">40dp</dimen>
+ <!-- The extra padding to show the whole outer border -->
+ <dimen name="magnifier_drag_handle_padding">3dp</dimen>
<!-- Home Controls -->
<dimen name="controls_header_side_margin">4dp</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 0763109..c39db94 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -50,4 +50,6 @@
<bool name="flag_charging_ripple">false</bool>
<bool name="flag_ongoing_call_status_bar_chip">false</bool>
+
+ <bool name="flag_smartspace">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e6fc332..ba07829 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -375,9 +375,10 @@
<item name="*android:dotColor">?android:attr/textColorSecondary</item>
</style>
- <style name="Theme.SystemUI.QuickSettings" parent="@*android:style/Theme.DeviceDefault.SystemUI">
+ <style name="Theme.SystemUI.QuickSettings" parent="@*android:style/Theme.DeviceDefault">
<item name="lightIconTheme">@style/QSIconTheme</item>
<item name="darkIconTheme">@style/QSIconTheme</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:colorError">@*android:color/error_color_material_dark</item>
<item name="android:windowIsFloating">true</item>
<item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item>
@@ -452,7 +453,7 @@
<item name="singleToneColor">@color/dark_mode_qs_icon_color_single_tone</item>
</style>
- <style name="QSHeaderTheme" parent="@style/Theme.SystemUI">
+ <style name="Theme.SystemUI.QuickSettings.Header">
<item name="lightIconTheme">@style/DualToneLightTheme</item>
<item name="darkIconTheme">@style/QSHeaderDarkTheme</item>
</style>
@@ -622,6 +623,8 @@
<!-- Screenshots -->
<style name="LongScreenshotActivity" parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="android:windowNoTitle">true</item>
+ <item name="android:windowLightStatusBar">true</item>
+ <item name="android:windowLightNavigationBar">true</item>
</style>
<!-- Privacy dialog -->
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
index 15312ad..c9dea46 100644
--- a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
@@ -18,11 +18,12 @@
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
+import static com.android.systemui.classifier.Classifier.DISABLED_UDFPS_AFFORDANCE;
+
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.hardware.biometrics.BiometricSourceType;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -33,7 +34,9 @@
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
@@ -53,14 +56,16 @@
@NonNull private final KeyguardViewController mKeyguardViewController;
@NonNull private final StatusBarStateController mStatusBarStateController;
@NonNull private final KeyguardStateController mKeyguardStateController;
+ @NonNull private final FalsingManager mFalsingManager;
@NonNull private final Drawable mButton;
@NonNull private final Drawable mUnlockIcon;
private boolean mIsDozing;
private boolean mIsBouncerShowing;
- private boolean mIsKeyguardShowing;
private boolean mRunningFPS;
private boolean mCanDismissLockScreen;
+ private boolean mQsExpanded;
+ private int mStatusBarState;
private boolean mShowButton;
private boolean mShowUnlockIcon;
@@ -71,16 +76,19 @@
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
@NonNull AuthController authController,
@NonNull KeyguardViewController keyguardViewController,
- @NonNull KeyguardStateController keyguardStateController
+ @NonNull KeyguardStateController keyguardStateController,
+ @NonNull FalsingManager falsingManager
) {
super(view);
- mView.setOnTouchListener(mOnTouchListener);
+ mView.setOnClickListener(v -> onAffordanceClick());
+ mView.setOnLongClickListener(v -> onAffordanceClick());
mView.setSensorProperties(authController.getUdfpsProps().get(0));
mStatusBarStateController = statusBarStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardViewController = keyguardViewController;
mKeyguardStateController = keyguardStateController;
+ mFalsingManager = falsingManager;
final Context context = view.getContext();
mButton = context.getResources().getDrawable(
@@ -94,10 +102,10 @@
@Override
protected void onViewAttached() {
mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
- mIsKeyguardShowing = mKeyguardStateController.isShowing();
mIsDozing = mStatusBarStateController.isDozing();
mRunningFPS = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
+ mStatusBarState = mStatusBarStateController.getState();
mUnlockIcon.setTint(Utils.getColorAttrDefaultColor(mView.getContext(),
R.attr.wallpaperTextColorAccent));
updateVisibility();
@@ -114,6 +122,15 @@
mKeyguardStateController.removeCallback(mKeyguardStateCallback);
}
+ private boolean onAffordanceClick() {
+ if (mFalsingManager.isFalseTouch(DISABLED_UDFPS_AFFORDANCE)) {
+ return false;
+ }
+ mView.setVisibility(View.INVISIBLE);
+ mKeyguardViewController.showBouncer(/* scrim */ true);
+ return true;
+ }
+
/**
* Call when this controller is no longer needed. This will remove the view from its parent.
*/
@@ -123,6 +140,14 @@
}
}
+ /**
+ * Set whether qs is expanded. When QS is expanded, don't show a DisabledUdfps affordance.
+ */
+ public void setQsExpanded(boolean expanded) {
+ mQsExpanded = expanded;
+ updateVisibility();
+ }
+
private void updateVisibility() {
mShowButton = !mCanDismissLockScreen && !mRunningFPS && isLockScreen();
mShowUnlockIcon = mCanDismissLockScreen && isLockScreen();
@@ -139,7 +164,10 @@
}
private boolean isLockScreen() {
- return mIsKeyguardShowing && !mIsDozing && !mIsBouncerShowing;
+ return !mIsDozing
+ && !mIsBouncerShowing
+ && !mQsExpanded
+ && mStatusBarState == StatusBarState.KEYGUARD;
}
@Override
@@ -148,20 +176,13 @@
pw.println(" mShowBouncerButton: " + mShowButton);
pw.println(" mShowUnlockIcon: " + mShowUnlockIcon);
pw.println(" mIsDozing: " + mIsDozing);
- pw.println(" mIsKeyguardShowing: " + mIsKeyguardShowing);
pw.println(" mIsBouncerShowing: " + mIsBouncerShowing);
pw.println(" mRunningFPS: " + mRunningFPS);
pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen);
+ pw.println(" mStatusBarState: " + StatusBarState.toShortString(mStatusBarState));
+ pw.println(" mQsExpanded: " + mQsExpanded);
}
- private final View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- mKeyguardViewController.showBouncer(/* scrim */ true);
- return true;
- }
- };
-
private StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
@@ -169,6 +190,12 @@
mIsDozing = isDozing;
updateVisibility();
}
+
+ @Override
+ public void onStateChanged(int statusBarState) {
+ mStatusBarState = statusBarState;
+ updateVisibility();
+ }
};
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
@@ -193,21 +220,9 @@
private final KeyguardStateController.Callback mKeyguardStateCallback =
new KeyguardStateController.Callback() {
@Override
- public void onKeyguardShowingChanged() {
- updateIsKeyguardShowing();
- updateVisibility();
- }
-
- @Override
public void onUnlockedChanged() {
- updateIsKeyguardShowing();
mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
updateVisibility();
}
-
- private void updateIsKeyguardShowing() {
- mIsKeyguardShowing = mKeyguardStateController.isShowing()
- && !mKeyguardStateController.isKeyguardGoingAway();
- }
};
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 0675200..24b7cd1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -16,8 +16,15 @@
package com.android.keyguard;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
import android.app.WallpaperManager;
+import android.app.smartspace.SmartspaceConfig;
+import android.app.smartspace.SmartspaceManager;
+import android.app.smartspace.SmartspaceSession;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.res.Resources;
import android.provider.Settings;
import android.text.TextUtils;
@@ -25,6 +32,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.clock.ClockManager;
@@ -32,8 +40,12 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -43,6 +55,7 @@
import java.util.Locale;
import java.util.TimeZone;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -68,6 +81,13 @@
private AnimatableClockController mNewLockScreenLargeClockViewController;
private FrameLayout mNewLockScreenLargeClockFrame;
+ private PluginManager mPluginManager;
+ private boolean mIsSmartspaceEnabled;
+ PluginListener mPluginListener;
+ private Executor mUiExecutor;
+ private SmartspaceSession mSmartspaceSession;
+ private SmartspaceSession.Callback mSmartspaceCallback;
+
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
private final StatusBarStateController.StateListener mStateListener =
@@ -96,6 +116,9 @@
private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
private String mTimeFormat;
+ // If set, will replace keyguard_status_area
+ private BcSmartspaceDataPlugin.SmartspaceView mSmartspaceView;
+
@Inject
public KeyguardClockSwitchController(
KeyguardClockSwitch keyguardClockSwitch,
@@ -105,7 +128,10 @@
KeyguardSliceViewController keyguardSliceViewController,
NotificationIconAreaController notificationIconAreaController,
ContentResolver contentResolver,
- BroadcastDispatcher broadcastDispatcher) {
+ BroadcastDispatcher broadcastDispatcher,
+ PluginManager pluginManager,
+ FeatureFlags featureFlags,
+ @Main Executor uiExecutor) {
super(keyguardClockSwitch);
mResources = resources;
mStatusBarStateController = statusBarStateController;
@@ -115,6 +141,9 @@
mNotificationIconAreaController = notificationIconAreaController;
mBroadcastDispatcher = broadcastDispatcher;
mTimeFormat = Settings.System.getString(contentResolver, Settings.System.TIME_12_24);
+ mPluginManager = pluginManager;
+ mIsSmartspaceEnabled = featureFlags.isSmartspaceEnabled();
+ mUiExecutor = uiExecutor;
}
/**
@@ -137,6 +166,63 @@
updateAodIcons();
mNewLockScreenClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view);
mNewLockScreenLargeClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view_large);
+
+ // If a smartspace plugin is detected, replace the existing smartspace
+ // (keyguard_status_area), and initialize a new session
+ mPluginListener = new PluginListener<BcSmartspaceDataPlugin>() {
+
+ @Override
+ public void onPluginConnected(BcSmartspaceDataPlugin plugin, Context pluginContext) {
+ if (!mIsSmartspaceEnabled) return;
+
+ View ksa = mView.findViewById(R.id.keyguard_status_area);
+ int ksaIndex = mView.indexOfChild(ksa);
+ ksa.setVisibility(View.GONE);
+
+ mSmartspaceView = plugin.getView(mView);
+ mSmartspaceView.registerDataProvider(plugin);
+
+ RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
+ MATCH_PARENT, WRAP_CONTENT);
+ lp.addRule(RelativeLayout.BELOW, R.id.new_lockscreen_clock_view);
+ mView.addView((View) mSmartspaceView, ksaIndex, lp);
+
+ View nic = mView.findViewById(
+ com.android.systemui.R.id.left_aligned_notification_icon_container);
+ lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
+ lp.addRule(RelativeLayout.BELOW, ((View) mSmartspaceView).getId());
+ nic.setLayoutParams(lp);
+
+ createSmartspaceSession(plugin);
+ }
+
+ @Override
+ public void onPluginDisconnected(BcSmartspaceDataPlugin plugin) {
+ if (!mIsSmartspaceEnabled) return;
+
+ mView.removeView((View) mSmartspaceView);
+ mView.findViewById(R.id.keyguard_status_area).setVisibility(View.VISIBLE);
+
+ View nic = mView.findViewById(
+ com.android.systemui.R.id.left_aligned_notification_icon_container);
+ RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)
+ nic.getLayoutParams();
+ lp.addRule(RelativeLayout.BELOW, R.id.keyguard_status_area);
+ nic.setLayoutParams(lp);
+
+ mSmartspaceView = null;
+ }
+
+ private void createSmartspaceSession(BcSmartspaceDataPlugin plugin) {
+ mSmartspaceSession = getContext().getSystemService(SmartspaceManager.class)
+ .createSmartspaceSession(
+ new SmartspaceConfig.Builder(getContext(), "lockscreen").build());
+ mSmartspaceCallback = targets -> plugin.onTargetsAvailable(targets);
+ mSmartspaceSession.registerSmartspaceUpdates(mUiExecutor, mSmartspaceCallback);
+ mSmartspaceSession.requestSmartspaceUpdate();
+ }
+ };
+ mPluginManager.addPluginListener(mPluginListener, BcSmartspaceDataPlugin.class, false);
}
@Override
@@ -147,6 +233,13 @@
mStatusBarStateController.removeCallback(mStateListener);
mColorExtractor.removeOnColorsChangedListener(mColorsListener);
mView.setClockPlugin(null, mStatusBarStateController.getState());
+
+ if (mSmartspaceSession != null) {
+ mSmartspaceSession.unregisterSmartspaceUpdates(mSmartspaceCallback);
+ mSmartspaceSession.destroy();
+ mSmartspaceSession = null;
+ }
+ mPluginManager.removePluginListener(mPluginListener);
}
/**
@@ -222,6 +315,11 @@
PropertyAnimator.setProperty(mNewLockScreenLargeClockFrame, AnimatableProperty.SCALE_Y,
scale, props, animate);
}
+
+ if (mSmartspaceView != null) {
+ PropertyAnimator.setProperty((View) mSmartspaceView, AnimatableProperty.TRANSLATION_X,
+ x, props, animate);
+ }
mKeyguardSliceViewController.updatePosition(x, props, animate);
mNotificationIconAreaController.updatePosition(x, props, animate);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index de09eaa6..2219cf4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -315,7 +315,6 @@
private boolean mLogoutEnabled;
// cached value to avoid IPCs
private boolean mIsUdfpsEnrolled;
- private boolean mKeyguardQsUserSwitchEnabled;
// If the user long pressed the lock icon, disabling face auth for the current session.
private boolean mLockIconPressed;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -1953,7 +1952,7 @@
return isFaceAuthEnabledForUser(KeyguardUpdateMonitor.getCurrentUser())
&& !isUdfpsEnrolled();
}
- return !isKeyguardQsUserSwitchEnabled();
+ return true;
}
/**
@@ -1963,17 +1962,6 @@
return mIsUdfpsEnrolled;
}
- /**
- * @return true if the keyguard qs user switcher shortcut is enabled
- */
- public boolean isKeyguardQsUserSwitchEnabled() {
- return mKeyguardQsUserSwitchEnabled;
- }
-
- public void setKeyguardQsUserSwitchEnabled(boolean enabled) {
- mKeyguardQsUserSwitchEnabled = enabled;
- }
-
private final UserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 3d6d381..5507ffa 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -18,8 +18,11 @@
import android.content.Intent;
import android.view.View;
+import androidx.annotation.Nullable;
+
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
import com.android.systemui.statusbar.phone.StatusBar;
import java.util.Optional;
@@ -51,18 +54,27 @@
@Override
public void startPendingIntentDismissingKeyguard(PendingIntent intent,
- Runnable intentSentCallback) {
+ Runnable intentSentUiThreadCallback) {
mActualStarter.ifPresent(
starter -> starter.get().startPendingIntentDismissingKeyguard(intent,
- intentSentCallback));
+ intentSentUiThreadCallback));
}
@Override
public void startPendingIntentDismissingKeyguard(PendingIntent intent,
- Runnable intentSentCallback, View associatedView) {
+ Runnable intentSentUiThreadCallback, View associatedView) {
mActualStarter.ifPresent(
starter -> starter.get().startPendingIntentDismissingKeyguard(intent,
- intentSentCallback, associatedView));
+ intentSentUiThreadCallback, associatedView));
+ }
+
+ @Override
+ public void startPendingIntentDismissingKeyguard(PendingIntent intent,
+ Runnable intentSentUiThreadCallback,
+ ActivityLaunchAnimator.Controller animationController) {
+ mActualStarter.ifPresent(
+ starter -> starter.get().startPendingIntentDismissingKeyguard(intent,
+ intentSentUiThreadCallback, animationController));
}
@Override
@@ -97,12 +109,27 @@
}
@Override
+ public void postStartActivityDismissingKeyguard(Intent intent, int delay,
+ @Nullable ActivityLaunchAnimator.Controller animationController) {
+ mActualStarter.ifPresent(
+ starter -> starter.get().postStartActivityDismissingKeyguard(intent, delay,
+ animationController));
+ }
+
+ @Override
public void postStartActivityDismissingKeyguard(PendingIntent intent) {
mActualStarter.ifPresent(
starter -> starter.get().postStartActivityDismissingKeyguard(intent));
}
@Override
+ public void postStartActivityDismissingKeyguard(PendingIntent intent,
+ ActivityLaunchAnimator.Controller animationController) {
+ mActualStarter.ifPresent(starter ->
+ starter.get().postStartActivityDismissingKeyguard(intent, animationController));
+ }
+
+ @Override
public void postQSRunnableDismissingKeyguard(Runnable runnable) {
mActualStarter.ifPresent(
starter -> starter.get().postQSRunnableDismissingKeyguard(runnable));
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index 2eba952..c23bcb8 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -40,6 +40,7 @@
new PathInterpolator(0.8f, 0f, 0.6f, 1f);
public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
+ public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
public static final Interpolator LINEAR = new LinearInterpolator();
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 9d00262..cc167b9 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -46,6 +46,7 @@
private GlobalRootComponent mRootComponent;
private WMComponent mWMComponent;
private SysUIComponent mSysUIComponent;
+ private boolean mInitializeComponents;
public static <T extends SystemUIFactory> T getInstance() {
return (T) mFactory;
@@ -88,13 +89,13 @@
public void init(Context context, boolean fromTest)
throws ExecutionException, InterruptedException {
// Only initialize components for the main system ui process running as the primary user
- final boolean initializeComponents = !fromTest
+ mInitializeComponents = !fromTest
&& android.os.Process.myUserHandle().isSystem()
&& ActivityThread.currentProcessName().equals(ActivityThread.currentPackageName());
mRootComponent = buildGlobalRootComponent(context);
// Stand up WMComponent
mWMComponent = mRootComponent.getWMComponentBuilder().build();
- if (initializeComponents) {
+ if (mInitializeComponents) {
// Only initialize when not starting from tests since this currently initializes some
// components that shouldn't be run in the test environment
mWMComponent.init();
@@ -102,7 +103,7 @@
// And finally, retrieve whatever SysUI needs from WMShell and build SysUI.
SysUIComponent.Builder builder = mRootComponent.getSysUIComponent();
- if (initializeComponents) {
+ if (mInitializeComponents) {
// Only initialize when not starting from tests since this currently initializes some
// components that shouldn't be run in the test environment
builder = prepareSysUIComponentBuilder(builder, mWMComponent)
@@ -134,7 +135,7 @@
.setStartingSurface(Optional.ofNullable(null));
}
mSysUIComponent = builder.build();
- if (initializeComponents) {
+ if (mInitializeComponents) {
mSysUIComponent.init();
}
@@ -160,6 +161,9 @@
.build();
}
+ protected boolean shouldInitializeComponents() {
+ return mInitializeComponents;
+ }
public GlobalRootComponent getRootComponent() {
return mRootComponent;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index cdd6942..4f5fdc9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -195,6 +195,13 @@
}
@Override
+ public void onAccessibilityActionPerformed(int displayId) {
+ if (mWindowMagnificationConnectionImpl != null) {
+ mWindowMagnificationConnectionImpl.onAccessibilityActionPerformed(displayId);
+ }
+ }
+
+ @Override
public void requestWindowMagnificationConnection(boolean connect) {
if (connect) {
setWindowMagnificationConnection();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
index be7d757..2d620ab 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
@@ -120,4 +120,14 @@
}
}
}
+
+ void onAccessibilityActionPerformed(int displayId) {
+ if (mConnectionCallback != null) {
+ try {
+ mConnectionCallback.onAccessibilityActionPerformed(displayId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform an accessibility action is already performed", e);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 2b666f1..48beea3 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -756,31 +756,23 @@
final float scale = mScale + A11Y_CHANGE_SCALE_DIFFERENCE;
mWindowMagnifierCallback.onPerformScaleAction(mDisplayId,
A11Y_ACTION_SCALE_RANGE.clamp(scale));
- return true;
- }
- if (action == R.id.accessibility_action_zoom_out) {
+ } else if (action == R.id.accessibility_action_zoom_out) {
final float scale = mScale - A11Y_CHANGE_SCALE_DIFFERENCE;
mWindowMagnifierCallback.onPerformScaleAction(mDisplayId,
A11Y_ACTION_SCALE_RANGE.clamp(scale));
- return true;
- }
- if (action == R.id.accessibility_action_move_up) {
+ } else if (action == R.id.accessibility_action_move_up) {
move(0, -mSourceBounds.height());
- return true;
- }
- if (action == R.id.accessibility_action_move_down) {
+ } else if (action == R.id.accessibility_action_move_down) {
move(0, mSourceBounds.height());
- return true;
- }
- if (action == R.id.accessibility_action_move_left) {
+ } else if (action == R.id.accessibility_action_move_left) {
move(-mSourceBounds.width(), 0);
- return true;
- }
- if (action == R.id.accessibility_action_move_right) {
+ } else if (action == R.id.accessibility_action_move_right) {
move(mSourceBounds.width(), 0);
- return true;
+ } else {
+ return false;
}
- return false;
+ mWindowMagnifierCallback.onAccessibilityActionPerformed(mDisplayId);
+ return true;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
index fb1d1b6..628a5e8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
@@ -46,4 +46,11 @@
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
*/
void onPerformScaleAction(int displayId, float scale);
+
+ /**
+ * Called when the accessibility action is performed.
+ *
+ * @param displayId The logical display id.
+ */
+ void onAccessibilityActionPerformed(int displayId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 74f855b..994401d 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -25,24 +25,20 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.location.LocationManager;
import android.media.AudioManager;
import android.media.AudioRecordingConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
-import android.provider.DeviceConfig;
+import android.permission.PermissionManager;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.WorkerThread;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.Dumpable;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
@@ -83,19 +79,12 @@
private final Context mContext;
private final AppOpsManager mAppOps;
private final AudioManager mAudioManager;
- private final LocationManager mLocationManager;
private final IndividualSensorPrivacyController mSensorPrivacyController;
private final SystemClock mClock;
- // mLocationProviderPackages are cached and updated only occasionally
- private static final long LOCATION_PROVIDER_UPDATE_FREQUENCY_MS = 30000;
- private long mLastLocationProviderPackageUpdate;
- private List<String> mLocationProviderPackages;
-
private H mBGHandler;
private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>();
private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>();
- private final PermissionFlagsCache mFlagsCache;
private boolean mListening;
private boolean mMicMuted;
private boolean mCameraDisabled;
@@ -124,7 +113,6 @@
Context context,
@Background Looper bgLooper,
DumpManager dumpManager,
- PermissionFlagsCache cache,
AudioManager audioManager,
IndividualSensorPrivacyController sensorPrivacyController,
BroadcastDispatcher dispatcher,
@@ -132,7 +120,6 @@
) {
mDispatcher = dispatcher;
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- mFlagsCache = cache;
mBGHandler = new H(bgLooper);
final int numOps = OPS.length;
for (int i = 0; i < numOps; i++) {
@@ -143,7 +130,6 @@
mMicMuted = audioManager.isMicrophoneMute()
|| mSensorPrivacyController.isSensorBlocked(MICROPHONE);
mCameraDisabled = mSensorPrivacyController.isSensorBlocked(CAMERA);
- mLocationManager = context.getSystemService(LocationManager.class);
mContext = context;
mClock = clock;
dumpManager.registerDumpable(TAG, this);
@@ -308,102 +294,8 @@
return createdNew;
}
- /**
- * Does the app-op code refer to a user sensitive permission for the specified user id
- * and package. Only user sensitive permission should be shown to the user by default.
- *
- * @param appOpCode The code of the app-op.
- * @param uid The uid of the user.
- * @param packageName The name of the package.
- *
- * @return {@code true} iff the app-op item is user sensitive
- */
- private boolean isUserSensitive(int appOpCode, int uid, String packageName) {
- String permission = AppOpsManager.opToPermission(appOpCode);
- if (permission == null) {
- return false;
- }
- int permFlags = mFlagsCache.getPermissionFlags(permission,
- packageName, uid);
- return (permFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0;
- }
-
- /**
- * Does the app-op item refer to an operation that should be shown to the user.
- * Only specficic ops (like SYSTEM_ALERT_WINDOW) or ops that refer to user sensitive
- * permission should be shown to the user by default.
- *
- * @param item The item
- *
- * @return {@code true} iff the app-op item should be shown to the user
- */
- private boolean isUserVisible(AppOpItem item) {
- return isUserVisible(item.getCode(), item.getUid(), item.getPackageName());
- }
-
- /**
- * Checks if a package is the current location provider.
- *
- * <p>Data is cached to avoid too many calls into system server
- *
- * @param packageName The package that might be the location provider
- *
- * @return {@code true} iff the package is the location provider.
- */
- private boolean isLocationProvider(String packageName) {
- long now = System.currentTimeMillis();
-
- if (mLastLocationProviderPackageUpdate + LOCATION_PROVIDER_UPDATE_FREQUENCY_MS < now) {
- mLastLocationProviderPackageUpdate = now;
- mLocationProviderPackages = mLocationManager.getProviderPackages(
- LocationManager.FUSED_PROVIDER);
- }
-
- return mLocationProviderPackages.contains(packageName);
- }
-
- private boolean isSpeechRecognizerUsage(int opCode, String packageName) {
- if (AppOpsManager.OP_RECORD_AUDIO != opCode) {
- return false;
- }
-
- return packageName.equals(
- mContext.getString(R.string.config_systemSpeechRecognizer));
- }
-
- // TODO ntmyren: remove after teamfood is finished
- private boolean showSystemApps() {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false);
- }
-
- /**
- * Does the app-op, uid and package name, refer to an operation that should be shown to the
- * user. Only specficic ops (like {@link AppOpsManager.OP_SYSTEM_ALERT_WINDOW}) or
- * ops that refer to user sensitive permission should be shown to the user by default.
- *
- * @param item The item
- *
- * @return {@code true} iff the app-op for should be shown to the user
- */
- private boolean isUserVisible(int appOpCode, int uid, String packageName) {
- // currently OP_SYSTEM_ALERT_WINDOW and OP_MONITOR_HIGH_POWER_LOCATION
- // does not correspond to a platform permission
- // which may be user sensitive, so for now always show it to the user.
- if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW
- || appOpCode == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION
- || appOpCode == AppOpsManager.OP_PHONE_CALL_CAMERA
- || appOpCode == AppOpsManager.OP_PHONE_CALL_MICROPHONE) {
- return true;
- }
- // TODO ntmyren: Replace this with more robust check if this moves beyond teamfood
- if (((showSystemApps() && !packageName.equals("android"))
- || appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName))
- || isSpeechRecognizerUsage(appOpCode, packageName)) {
- return true;
- }
-
- return isUserSensitive(appOpCode, uid, packageName);
+ private boolean isUserVisible(String packageName) {
+ return PermissionManager.shouldShowPackageForIndicatorCached(mContext, packageName);
}
/**
@@ -438,7 +330,7 @@
AppOpItem item = mActiveItems.get(i);
if ((userId == UserHandle.USER_ALL
|| UserHandle.getUserId(item.getUid()) == userId)
- && isUserVisible(item) && !item.isDisabled()) {
+ && isUserVisible(item.getPackageName()) && !item.isDisabled()) {
list.add(item);
}
}
@@ -449,7 +341,7 @@
AppOpItem item = mNotedItems.get(i);
if ((userId == UserHandle.USER_ALL
|| UserHandle.getUserId(item.getUid()) == userId)
- && isUserVisible(item)) {
+ && isUserVisible(item.getPackageName())) {
list.add(item);
}
}
@@ -503,7 +395,7 @@
}
private void notifySuscribersWorker(int code, int uid, String packageName, boolean active) {
- if (mCallbacksByCode.contains(code) && isUserVisible(code, uid, packageName)) {
+ if (mCallbacksByCode.contains(code) && isUserVisible(packageName)) {
if (DEBUG) Log.d(TAG, "Notifying of change in package " + packageName);
for (Callback cb: mCallbacksByCode.get(code)) {
cb.onActiveStateChanged(code, uid, packageName, active);
diff --git a/packages/SystemUI/src/com/android/systemui/appops/PermissionFlagsCache.kt b/packages/SystemUI/src/com/android/systemui/appops/PermissionFlagsCache.kt
deleted file mode 100644
index 3fd838b..0000000
--- a/packages/SystemUI/src/com/android/systemui/appops/PermissionFlagsCache.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2020 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.appops
-
-import android.content.pm.PackageManager
-import android.os.UserHandle
-import androidx.annotation.WorkerThread
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.util.Assert
-import java.util.concurrent.Executor
-import javax.inject.Inject
-
-private data class PermissionFlagKey(
- val permission: String,
- val packageName: String,
- val uid: Int
-)
-
-/**
- * Cache for PackageManager's PermissionFlags.
- *
- * After a specific `{permission, package, uid}` has been requested, updates to it will be tracked,
- * and changes to the uid will trigger new requests (in the background).
- */
-@SysUISingleton
-class PermissionFlagsCache @Inject constructor(
- private val packageManager: PackageManager,
- @Background private val executor: Executor
-) : PackageManager.OnPermissionsChangedListener {
-
- private val permissionFlagsCache =
- mutableMapOf<Int, MutableMap<PermissionFlagKey, Int>>()
- private var listening = false
-
- override fun onPermissionsChanged(uid: Int) {
- executor.execute {
- // Only track those that we've seen before
- val keys = permissionFlagsCache.get(uid)
- if (keys != null) {
- keys.mapValuesTo(keys) {
- getFlags(it.key)
- }
- }
- }
- }
-
- /**
- * Retrieve permission flags from cache or PackageManager. There parameters will be passed
- * directly to [PackageManager].
- *
- * Calls to this method should be done from a background thread (though it will only be
- * enforced if the cache is not hit).
- */
- @WorkerThread
- fun getPermissionFlags(permission: String, packageName: String, uid: Int): Int {
- if (!listening) {
- listening = true
- packageManager.addOnPermissionsChangeListener(this)
- }
- val key = PermissionFlagKey(permission, packageName, uid)
- return permissionFlagsCache.getOrPut(uid, { mutableMapOf() }).get(key) ?: run {
- getFlags(key).also {
- Assert.isNotMainThread()
- permissionFlagsCache.get(uid)?.put(key, it)
- }
- }
- }
-
- private fun getFlags(key: PermissionFlagKey): Int {
- return packageManager.getPermissionFlags(key.permission, key.packageName,
- UserHandle.getUserHandleForUid(key.uid))
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 94b4c5f..2802742 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -29,6 +29,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
+import android.graphics.PointF;
import android.graphics.RectF;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
@@ -82,6 +83,7 @@
@Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps;
@Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
@Nullable private final List<FingerprintSensorPropertiesInternal> mUdfpsProps;
+ @Nullable private final PointF mFaceAuthSensorLocation;
// TODO: These should just be saved from onSaveState
private SomeArgs mCurrentDialogArgs;
@@ -261,10 +263,34 @@
}
/**
- * @return where the UDFPS exists on the screen in pixels.
+ * @return where the UDFPS exists on the screen in pixels in portrait mode.
*/
public RectF getUdfpsRegion() {
- return mUdfpsController == null ? null : mUdfpsController.getSensorLocation();
+ return mUdfpsController == null
+ ? null
+ : mUdfpsController.getSensorLocation();
+ }
+
+ /**
+ * @return where the UDFPS exists on the screen in pixels in portrait mode.
+ */
+ public PointF getUdfpsSensorLocation() {
+ if (mUdfpsController == null) {
+ return null;
+ }
+ return new PointF(mUdfpsController.getSensorLocation().centerX(),
+ mUdfpsController.getSensorLocation().centerY());
+ }
+
+ /**
+ * @return where the face authentication sensor exists relative to the screen in pixels in
+ * portrait mode.
+ */
+ public PointF getFaceAuthSensorLocation() {
+ if (mFaceProps == null || mFaceAuthSensorLocation == null) {
+ return null;
+ }
+ return new PointF(mFaceAuthSensorLocation.x, mFaceAuthSensorLocation.y);
}
/**
@@ -339,6 +365,15 @@
}
}
mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null;
+ int[] faceAuthLocation = context.getResources().getIntArray(
+ com.android.systemui.R.array.config_face_auth_props);
+ if (faceAuthLocation == null || faceAuthLocation.length < 2) {
+ mFaceAuthSensorLocation = null;
+ } else {
+ mFaceAuthSensorLocation = new PointF(
+ (float) faceAuthLocation[0],
+ (float) faceAuthLocation[1]);
+ }
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index a1149fd..110351e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -17,17 +17,19 @@
package com.android.systemui.biometrics
import android.content.Context
+import android.content.res.Configuration
+import android.graphics.PointF
import android.hardware.biometrics.BiometricSourceType
-import android.view.View
-import android.view.ViewGroup
-import com.android.internal.annotations.VisibleForTesting
+import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
-import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.ViewController
import java.io.PrintWriter
import javax.inject.Inject
@@ -35,30 +37,82 @@
* Controls the ripple effect that shows when authentication is successful.
* The ripple uses the accent color of the current theme.
*/
-@SysUISingleton
+@StatusBarScope
class AuthRippleController @Inject constructor(
- commandRegistry: CommandRegistry,
- configurationController: ConfigurationController,
- private val context: Context,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor
-) {
- @VisibleForTesting
- var rippleView: AuthRippleView = AuthRippleView(context, attrs = null)
+ private val sysuiContext: Context,
+ private val authController: AuthController,
+ private val configurationController: ConfigurationController,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val commandRegistry: CommandRegistry,
+ private val notificationShadeWindowController: NotificationShadeWindowController,
+ rippleView: AuthRippleView?
+) : ViewController<AuthRippleView>(rippleView) {
+ private var fingerprintSensorLocation: PointF? = null
+ private var faceSensorLocation: PointF? = null
- val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
- override fun onBiometricAuthenticated(
- userId: Int,
- biometricSourceType: BiometricSourceType?,
- isStrongBiometric: Boolean
- ) {
- if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
- rippleView.startRipple()
- }
+ @VisibleForTesting
+ public override fun onViewAttached() {
+ updateRippleColor()
+ updateSensorLocation()
+ configurationController.addCallback(configurationChangedListener)
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
+ }
+
+ @VisibleForTesting
+ public override fun onViewDetached() {
+ keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
+ configurationController.removeCallback(configurationChangedListener)
+ commandRegistry.unregisterCommand("auth-ripple")
+
+ notificationShadeWindowController.setForcePluginOpen(false, this)
+ }
+
+ private fun showRipple(biometricSourceType: BiometricSourceType?) {
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
+ fingerprintSensorLocation != null) {
+ mView.setSensorLocation(fingerprintSensorLocation!!)
+ showRipple()
+ } else if (biometricSourceType == BiometricSourceType.FACE &&
+ faceSensorLocation != null) {
+ mView.setSensorLocation(faceSensorLocation!!)
+ showRipple()
}
}
- init {
- val configurationChangedListener = object : ConfigurationController.ConfigurationListener {
+ private fun showRipple() {
+ notificationShadeWindowController.setForcePluginOpen(true, this)
+ mView.startRipple(Runnable {
+ notificationShadeWindowController.setForcePluginOpen(false, this)
+ })
+ }
+
+ private fun updateSensorLocation() {
+ fingerprintSensorLocation = authController.udfpsSensorLocation
+ faceSensorLocation = authController.faceAuthSensorLocation
+ }
+
+ private fun updateRippleColor() {
+ mView.setColor(
+ Utils.getColorAttr(sysuiContext, android.R.attr.colorAccent).defaultColor)
+ }
+
+ val keyguardUpdateMonitorCallback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricAuthenticated(
+ userId: Int,
+ biometricSourceType: BiometricSourceType?,
+ isStrongBiometric: Boolean
+ ) {
+ showRipple(biometricSourceType)
+ }
+ }
+
+ val configurationChangedListener =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ updateSensorLocation()
+ }
override fun onUiModeChanged() {
updateRippleColor()
}
@@ -68,43 +122,50 @@
override fun onOverlayChanged() {
updateRippleColor()
}
- }
- configurationController.addCallback(configurationChangedListener)
-
- commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
- }
-
- fun setSensorLocation(x: Float, y: Float) {
- rippleView.setSensorLocation(x, y)
- }
-
- fun setViewHost(viewHost: View) {
- // Add the ripple view to its host layout
- viewHost.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
- override fun onViewDetachedFromWindow(view: View?) {}
-
- override fun onViewAttachedToWindow(view: View?) {
- (viewHost as ViewGroup).addView(rippleView)
- keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
- viewHost.removeOnAttachStateChangeListener(this)
- }
- })
-
- updateRippleColor()
- }
-
- private fun updateRippleColor() {
- rippleView.setColor(
- Utils.getColorAttr(context, android.R.attr.colorAccent).defaultColor)
}
inner class AuthRippleCommand : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
- rippleView.startRipple()
+ if (args.isEmpty()) {
+ invalidCommand(pw)
+ } else {
+ when (args[0]) {
+ "fingerprint" -> {
+ pw.println("fingerprint ripple sensorLocation=$fingerprintSensorLocation")
+ showRipple(BiometricSourceType.FINGERPRINT)
+ }
+ "face" -> {
+ pw.println("face ripple sensorLocation=$faceSensorLocation")
+ showRipple(BiometricSourceType.FACE)
+ }
+ "custom" -> {
+ if (args.size != 3 ||
+ args[1].toFloatOrNull() == null ||
+ args[2].toFloatOrNull() == null) {
+ invalidCommand(pw)
+ return
+ }
+ pw.println("custom ripple sensorLocation=" + args[1].toFloat() + ", " +
+ args[2].toFloat())
+ mView.setSensorLocation(PointF(args[1].toFloat(), args[2].toFloat()))
+ showRipple()
+ }
+ else -> invalidCommand(pw)
+ }
+ }
}
override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar auth-ripple")
+ pw.println("Usage: adb shell cmd statusbar auth-ripple <command>")
+ pw.println("Available commands:")
+ pw.println(" fingerprint")
+ pw.println(" face")
+ pw.println(" custom <x-location: int> <y-location: int>")
+ }
+
+ fun invalidCommand(pw: PrintWriter) {
+ pw.println("invalid command")
+ help(pw)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 1270677..374ddae 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -17,6 +17,7 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
@@ -24,9 +25,11 @@
import android.graphics.PointF
import android.util.AttributeSet
import android.view.View
+import android.view.animation.PathInterpolator
+import com.android.internal.graphics.ColorUtils
import com.android.systemui.statusbar.charging.RippleShader
-private const val RIPPLE_ANIMATION_DURATION: Long = 950
+private const val RIPPLE_ANIMATION_DURATION: Long = 1533
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
/**
@@ -36,42 +39,64 @@
class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private var rippleInProgress: Boolean = false
private val rippleShader = RippleShader()
- private val defaultColor: Int = 0xffffffff.toInt()
private val ripplePaint = Paint()
init {
- rippleShader.color = defaultColor
+ rippleShader.color = 0xffffffff.toInt() // default color
rippleShader.progress = 0f
rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH
ripplePaint.shader = rippleShader
- visibility = View.GONE
+ visibility = GONE
}
- fun setSensorLocation(x: Float, y: Float) {
- rippleShader.origin = PointF(x, y)
- rippleShader.radius = maxOf(x, y, width - x, height - y).toFloat()
+ fun setSensorLocation(location: PointF) {
+ rippleShader.origin = location
+ rippleShader.radius = maxOf(location.x, location.y, width - location.x, height - location.y)
+ .toFloat()
}
- fun startRipple() {
+ fun startRipple(onAnimationEnd: Runnable?) {
if (rippleInProgress) {
return // Ignore if ripple effect is already playing
}
+
val animator = ValueAnimator.ofFloat(0f, 1f)
+ animator.interpolator = PathInterpolator(0.4f, 0f, 0f, 1f)
animator.duration = RIPPLE_ANIMATION_DURATION
animator.addUpdateListener { animator ->
val now = animator.currentPlayTime
rippleShader.progress = animator.animatedValue as Float
rippleShader.time = now.toFloat()
+ rippleShader.distortionStrength = 1 - rippleShader.progress
invalidate()
}
- animator.addListener(object : AnimatorListenerAdapter() {
+ val alphaInAnimator = ValueAnimator.ofInt(0, 127)
+ alphaInAnimator.duration = 167
+ alphaInAnimator.addUpdateListener { alphaInAnimator ->
+ rippleShader.color = ColorUtils.setAlphaComponent(rippleShader.color,
+ alphaInAnimator.animatedValue as Int)
+ invalidate()
+ }
+ val alphaOutAnimator = ValueAnimator.ofInt(127, 0)
+ alphaOutAnimator.startDelay = 417
+ alphaOutAnimator.duration = 1116
+ alphaOutAnimator.addUpdateListener { alphaOutAnimator ->
+ rippleShader.color = ColorUtils.setAlphaComponent(rippleShader.color,
+ alphaOutAnimator.animatedValue as Int)
+ invalidate()
+ }
+
+ val animatorSet = AnimatorSet()
+ animatorSet.playTogether(animator, alphaInAnimator, alphaOutAnimator)
+ animatorSet.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
+ onAnimationEnd?.run()
rippleInProgress = false
- visibility = View.GONE
+ visibility = GONE
}
})
- animator.start()
- visibility = View.VISIBLE
+ animatorSet.start()
+ visibility = VISIBLE
rippleInProgress = true
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
index f4993f4..d9e1b50 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
@@ -23,7 +23,6 @@
import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.ViewController;
@@ -47,7 +46,6 @@
@NonNull final DumpManager mDumpManger;
private boolean mNotificationShadeExpanded;
- private int mStatusBarState;
protected UdfpsAnimationViewController(
T view,
@@ -86,7 +84,6 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("mStatusBarState=" + StatusBarState.toShortString(mStatusBarState));
pw.println("mNotificationShadeExpanded=" + mNotificationShadeExpanded);
pw.println("shouldPauseAuth()=" + shouldPauseAuth());
pw.println("isPauseAuth=" + mView.isPauseAuth());
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 2bdbf51..aa818bf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,6 +37,7 @@
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -53,6 +55,7 @@
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -89,9 +92,9 @@
@NonNull private final StatusBarStateController mStatusBarStateController;
@NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
@NonNull private final DumpManager mDumpManager;
- @NonNull private final AuthRippleController mAuthRippleController;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final KeyguardViewMediator mKeyguardViewMediator;
+ @NonNull private FalsingManager mFalsingManager;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -241,6 +244,8 @@
}
// TODO: move isWithinSensorArea to UdfpsController.
if (udfpsView.isWithinSensorArea(event.getX(), event.getY())) {
+ Trace.beginAsyncSection(
+ "UdfpsController.mOnTouchListener#isWithinSensorArea", 1);
// The pointer that causes ACTION_DOWN is always at index 0.
// We need to persist its ID to track it during ACTION_MOVE that could include
// data for many other pointers because of multi-touch support.
@@ -267,6 +272,8 @@
minor, major, v);
final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime;
if (!isFingerDown) {
+ Trace.endAsyncSection(
+ "UdfpsController.mOnTouchListener#isWithinSensorArea", 1);
onFingerDown((int) x, (int) y, minor, major);
Log.v(TAG, "onTouch | finger down: " + touchInfo);
mTouchLogTime = SystemClock.elapsedRealtime();
@@ -292,6 +299,8 @@
Log.v(TAG, "onTouch | finger up");
onFingerUp();
}
+ mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
+
break;
default:
@@ -311,9 +320,9 @@
@NonNull StatusBar statusBar,
@NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@NonNull DumpManager dumpManager,
- @NonNull AuthRippleController authRippleController,
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
- @NonNull KeyguardViewMediator keyguardViewMediator) {
+ @NonNull KeyguardViewMediator keyguardViewMediator,
+ @NonNull FalsingManager falsingManager) {
mContext = context;
mInflater = inflater;
// The fingerprint manager is queried for UDFPS before this class is constructed, so the
@@ -325,9 +334,9 @@
mStatusBarStateController = statusBarStateController;
mKeyguardViewManager = statusBarKeyguardViewManager;
mDumpManager = dumpManager;
- mAuthRippleController = authRippleController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardViewMediator = keyguardViewMediator;
+ mFalsingManager = falsingManager;
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -353,10 +362,6 @@
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
context.registerReceiver(mBroadcastReceiver, filter);
-
- mAuthRippleController.setViewHost(mStatusBar.getNotificationShadeWindowView());
- mAuthRippleController.setSensorLocation(getSensorLocation().centerX(),
- getSensorLocation().centerY());
}
@Nullable
@@ -584,8 +589,11 @@
Log.w(TAG, "Null view in onFingerDown");
return;
}
- mView.startIllumination(() ->
- mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major));
+ Trace.beginAsyncSection("UdfpsController#startIllumination", 1);
+ mView.startIllumination(() -> {
+ Trace.endAsyncSection("UdfpsController#startIllumination", 1);
+ mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
+ });
}
// This method can be called from the UI thread.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index dc0c685..35678e6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -91,6 +91,7 @@
mStatusBarStateController.addCallback(mStateListener);
mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
mStateListener.onStateChanged(mStatusBarStateController.getState());
+ mAlternateAuthInterceptor.setQsExpanded(mKeyguardViewManager.isQsExpanded());
mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
}
@@ -117,6 +118,8 @@
pw.println("mShowBouncer=" + mShowBouncer);
pw.println("mFaceDetectRunning=" + mFaceDetectRunning);
pw.println("mTransitioningFromHomeToKeyguard=" + mTransitioningFromHome);
+ pw.println("mStatusBarState" + StatusBarState.toShortString(mStatusBarState));
+ pw.println("mQsExpanded=" + mQsExpanded);
}
/**
@@ -215,6 +218,7 @@
public void onStateChanged(int statusBarState) {
mStatusBarState = statusBarState;
mView.setStatusBarState(statusBarState);
+ updatePauseAuth();
}
};
@@ -283,7 +287,7 @@
@Override
public void dump(PrintWriter pw) {
- pw.print(getTag());
+ pw.println(getTag());
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index f7beaf1..fb7fabb 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -114,9 +114,11 @@
params.height = WindowManager.LayoutParams.MATCH_PARENT;
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.format = PixelFormat.TRANSLUCENT;
-
params.type = WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
params.setTitle("Charging Animation");
+ params.layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ params.setFitInsetsTypes(0 /* ignore all system bar insets */);
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_DIM_BEHIND;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index 5bdc7a4..e2c62ed 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -218,18 +218,43 @@
}
@Override
- public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
+ public boolean isSimpleTap() {
+ FalsingClassifier.Result result = mSingleTapClassifier.isTap(
+ mDataProvider.getRecentMotionEvents(), 0);
+ mPriorResults = Collections.singleton(result);
+
+ return !result.isFalse();
+ }
+
+ @Override
+ public boolean isFalseTap(@Penalty int penalty) {
if (skipFalsing()) {
return false;
}
+ double falsePenalty = 0;
+ switch(penalty) {
+ case NO_PENALTY:
+ falsePenalty = 0;
+ break;
+ case LOW_PENALTY:
+ falsePenalty = 0.1;
+ break;
+ case MODERATE_PENALTY:
+ falsePenalty = 0.3;
+ break;
+ case HIGH_PENALTY:
+ falsePenalty = 0.6;
+ break;
+ }
+
FalsingClassifier.Result singleTapResult =
mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents().isEmpty()
? mDataProvider.getPriorMotionEvents()
- : mDataProvider.getRecentMotionEvents());
+ : mDataProvider.getRecentMotionEvents(), falsePenalty);
mPriorResults = Collections.singleton(singleTapResult);
- if (!singleTapResult.isFalse() && robustCheck) {
+ if (!singleTapResult.isFalse()) {
if (mDataProvider.isJustUnlockedWithFace()) {
// Immediately pass if a face is detected.
mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1));
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index 47b41f5..4dd8780 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -38,6 +38,8 @@
public static final int BOUNCER_UNLOCK = 8;
public static final int PULSE_EXPAND = 9;
public static final int BRIGHTNESS_SLIDER = 10;
+ public static final int UDFPS_AUTHENTICATION = 11;
+ public static final int DISABLED_UDFPS_AFFORDANCE = 12;
@IntDef({
QUICK_SETTINGS,
@@ -50,7 +52,9 @@
GENERIC,
BOUNCER_UNLOCK,
PULSE_EXPAND,
- BRIGHTNESS_SLIDER
+ BRIGHTNESS_SLIDER,
+ UDFPS_AUTHENTICATION,
+ DISABLED_UDFPS_AFFORDANCE
})
@Retention(RetentionPolicy.SOURCE)
public @interface InteractionType {}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
index 80d7863..6a70622 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
@@ -148,7 +148,9 @@
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
- if (interactionType == Classifier.BRIGHTNESS_SLIDER) {
+ if (interactionType == Classifier.BRIGHTNESS_SLIDER
+ || interactionType == Classifier.UDFPS_AUTHENTICATION
+ || interactionType == Classifier.DISABLED_UDFPS_AFFORDANCE) {
return Result.passed(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
index e7c9d18..b6d529d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
@@ -66,13 +66,13 @@
public boolean isDoubleTap(List<MotionEvent> firstEvents, List<MotionEvent> secondEvents,
StringBuilder reason) {
- Result firstTap = mSingleTapClassifier.isTap(firstEvents);
+ Result firstTap = mSingleTapClassifier.isTap(firstEvents, 0.5);
if (firstTap.isFalse()) {
reason.append("First gesture is not a tap. ").append(firstTap.getReason());
return false;
}
- Result secondTap = mSingleTapClassifier.isTap(secondEvents);
+ Result secondTap = mSingleTapClassifier.isTap(secondEvents, 0.5);
if (secondTap.isFalse()) {
reason.append("Second gesture is not a tap. ").append(secondTap.getReason());
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index d39f124..e557773 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -32,7 +32,7 @@
*/
public class FalsingManagerFake implements FalsingManager {
private boolean mIsFalseTouch;
- private boolean mIsFalseTap;
+ private boolean mIsSimpleTap;
private boolean mIsFalseDoubleTap;
private boolean mIsUnlockingDisabled;
private boolean mIsClassiferEnabled;
@@ -67,12 +67,12 @@
return mIsFalseTouch;
}
- public void setFalseRobustTap(boolean falseRobustTap) {
+ public void setFalseTap(boolean falseRobustTap) {
mIsFalseRobustTap = falseRobustTap;
}
- public void setFalseTap(boolean falseTap) {
- mIsFalseTap = falseTap;
+ public void setSimpleTap(boolean isSimpleTape) {
+ mIsSimpleTap = isSimpleTape;
}
public void setFalseDoubleTap(boolean falseDoubleTap) {
@@ -80,8 +80,13 @@
}
@Override
- public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
- return robustCheck ? mIsFalseRobustTap : mIsFalseTap;
+ public boolean isSimpleTap() {
+ return mIsSimpleTap;
+ }
+
+ @Override
+ public boolean isFalseTap(@Penalty int penalty) {
+ return mIsFalseRobustTap;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 9c29f27..1723291 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -131,8 +131,13 @@
}
@Override
- public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
- return mInternalFalsingManager.isFalseTap(robustCheck, falsePenalty);
+ public boolean isSimpleTap() {
+ return mInternalFalsingManager.isSimpleTap();
+ }
+
+ @Override
+ public boolean isFalseTap(@Penalty int penalty) {
+ return mInternalFalsingManager.isFalseTap(penalty);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
index 68a9e5f..bd6fbfb 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
@@ -42,11 +42,11 @@
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
- return isTap(getRecentMotionEvents());
+ return isTap(getRecentMotionEvents(), 0.5);
}
/** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */
- public Result isTap(List<MotionEvent> motionEvents) {
+ public Result isTap(List<MotionEvent> motionEvents, double falsePenalty) {
if (motionEvents.isEmpty()) {
return falsed(0, "no motion events");
}
@@ -60,13 +60,13 @@
+ Math.abs(event.getX() - downX)
+ "vs "
+ mTouchSlop;
- return falsed(0.5, reason);
+ return falsed(falsePenalty, reason);
} else if (Math.abs(event.getY() - downY) >= mTouchSlop) {
reason = "dY too big for a tap: "
+ Math.abs(event.getY() - downY)
+ " vs "
+ mTouchSlop;
- return falsed(0.5, reason);
+ return falsed(falsePenalty, reason);
}
}
return Result.passed(0);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
index f665565..50e94b3 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
@@ -42,6 +42,11 @@
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
+ if (interactionType == Classifier.UDFPS_AUTHENTICATION
+ || interactionType == Classifier.DISABLED_UDFPS_AFFORDANCE) {
+ return Result.passed(0);
+ }
+
boolean vertical = isVertical();
boolean up = isUp();
boolean right = isRight();
diff --git a/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt
index 10b36e9..bc45113 100644
--- a/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt
@@ -28,6 +28,7 @@
import android.graphics.Outline
import android.graphics.Paint
import android.graphics.PixelFormat
+import android.graphics.Xfermode
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.MathUtils
@@ -48,7 +49,15 @@
class IlluminationDrawable : Drawable() {
private var themeAttrs: IntArray? = null
- private var cornerRadius = 0f
+ private var cornerRadiusOverride = -1f
+ var cornerRadius = 0f
+ get() {
+ return if (cornerRadiusOverride >= 0) {
+ cornerRadiusOverride
+ } else {
+ field
+ }
+ }
private var highlightColor = Color.TRANSPARENT
private var tmpHsl = floatArrayOf(0f, 0f, 0f)
private var paint = Paint()
@@ -122,8 +131,28 @@
throw UnsupportedOperationException("Color filters are not supported")
}
- override fun setAlpha(value: Int) {
- throw UnsupportedOperationException("Alpha is not supported")
+ override fun setAlpha(alpha: Int) {
+ if (alpha == paint.alpha) {
+ return
+ }
+
+ paint.alpha = alpha
+ invalidateSelf()
+
+ lightSources.forEach { it.alpha = alpha }
+ }
+
+ override fun getAlpha(): Int {
+ return paint.alpha
+ }
+
+ override fun setXfermode(mode: Xfermode?) {
+ if (mode == paint.xfermode) {
+ return
+ }
+
+ paint.xfermode = mode
+ invalidateSelf()
}
/**
@@ -171,9 +200,19 @@
fun registerLightSource(lightSource: View) {
if (lightSource.background is LightSourceDrawable) {
- lightSources.add(lightSource.background as LightSourceDrawable)
+ registerLightSource(lightSource.background as LightSourceDrawable)
} else if (lightSource.foreground is LightSourceDrawable) {
- lightSources.add(lightSource.foreground as LightSourceDrawable)
+ registerLightSource(lightSource.foreground as LightSourceDrawable)
}
}
+
+ private fun registerLightSource(lightSource: LightSourceDrawable) {
+ lightSource.alpha = paint.alpha
+ lightSources.add(lightSource)
+ }
+
+ /** Set or remove the corner radius override. This is typically set during animations. */
+ fun setCornerRadiusOverride(cornerRadius: Float?) {
+ cornerRadiusOverride = cornerRadius ?: -1f
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/LightSourceDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/LightSourceDrawable.kt
index cee7101..e6035f3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/LightSourceDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/LightSourceDrawable.kt
@@ -184,8 +184,13 @@
throw UnsupportedOperationException("Color filters are not supported")
}
- override fun setAlpha(value: Int) {
- throw UnsupportedOperationException("Alpha is not supported")
+ override fun setAlpha(alpha: Int) {
+ if (alpha == paint.alpha) {
+ return
+ }
+
+ paint.alpha = alpha
+ invalidateSelf()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index d3ae932..4fd8fe7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -49,6 +49,8 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
+import com.android.systemui.plugins.animation.GhostedViewLaunchAnimatorController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.util.animation.TransitionLayout;
@@ -101,11 +103,12 @@
// This will provide the corners for the album art.
private final ViewOutlineProvider mViewOutlineProvider;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
+
/**
* Initialize a new control panel
- * @param context
+ *
* @param backgroundExecutor background executor, used for processing artwork
- * @param activityStarter activity starter
+ * @param activityStarter activity starter
*/
@Inject
public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
@@ -147,6 +150,7 @@
/**
* Get the view holder used to display media controls
+ *
* @return the view holder
*/
@Nullable
@@ -156,6 +160,7 @@
/**
* Get the view controller used to display media controls
+ *
* @return the media view controller
*/
@NonNull
@@ -165,7 +170,7 @@
/**
* Sets the listening state of the player.
- *
+ * <p>
* Should be set to true when the QS panel is open. Otherwise, false. This is a signal to avoid
* unnecessary work when the QS panel is closed.
*
@@ -177,6 +182,7 @@
/**
* Get the context
+ *
* @return context
*/
public Context getContext() {
@@ -244,7 +250,8 @@
if (clickIntent != null) {
mViewHolder.getPlayer().setOnClickListener(v -> {
if (mMediaViewController.isGutsVisible()) return;
- mActivityStarter.postStartActivityDismissingKeyguard(clickIntent);
+ mActivityStarter.postStartActivityDismissingKeyguard(clickIntent,
+ buildLaunchAnimatorController(mViewHolder.getPlayer()));
});
}
@@ -396,8 +403,42 @@
mMediaViewController.refreshState();
}
+ @Nullable
+ private ActivityLaunchAnimator.Controller buildLaunchAnimatorController(
+ TransitionLayout player) {
+ // TODO(b/174236650): Make sure that the carousel indicator also fades out.
+ // TODO(b/174236650): Instrument the animation to measure jank.
+ return new GhostedViewLaunchAnimatorController(player) {
+ @Override
+ protected float getCurrentTopCornerRadius() {
+ return ((IlluminationDrawable) player.getBackground()).getCornerRadius();
+ }
+
+ @Override
+ protected float getCurrentBottomCornerRadius() {
+ // TODO(b/184121838): Make IlluminationDrawable support top and bottom radius.
+ return getCurrentTopCornerRadius();
+ }
+
+ @Override
+ protected void setBackgroundCornerRadius(Drawable background, float topCornerRadius,
+ float bottomCornerRadius) {
+ // TODO(b/184121838): Make IlluminationDrawable support top and bottom radius.
+ float radius = Math.min(topCornerRadius, bottomCornerRadius);
+ ((IlluminationDrawable) background).setCornerRadiusOverride(radius);
+ }
+
+ @Override
+ public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) {
+ super.onLaunchAnimationEnd(isExpandingFullyAbove);
+ ((IlluminationDrawable) player.getBackground()).setCornerRadiusOverride(null);
+ }
+ };
+ }
+
/**
* Close the guts for this player.
+ *
* @param immediate {@code true} if it should be closed without animation
*/
public void closeGuts(boolean immediate) {
@@ -427,7 +468,7 @@
if (bounds.width() > mAlbumArtSize || bounds.height() > mAlbumArtSize) {
float offsetX = (bounds.width() - mAlbumArtSize) / 2.0f;
float offsetY = (bounds.height() - mAlbumArtSize) / 2.0f;
- bounds.offset((int) -offsetX,(int) -offsetY);
+ bounds.offset((int) -offsetX, (int) -offsetY);
}
drawable.setBounds(bounds);
return drawable;
@@ -435,6 +476,7 @@
/**
* Get the current media controller
+ *
* @return the controller
*/
public MediaController getController() {
@@ -443,6 +485,7 @@
/**
* Check whether the media controlled by this player is currently playing
+ *
* @return whether it is playing, or false if no controller information
*/
public boolean isPlaying() {
@@ -451,6 +494,7 @@
/**
* Check whether the given controller is currently playing
+ *
* @param controller media controller to check
* @return whether it is playing, or false if no controller information
*/
@@ -468,7 +512,7 @@
}
private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
- set.setVisibility(actionId, visible? ConstraintSet.VISIBLE : ConstraintSet.GONE);
+ set.setVisibility(actionId, visible ? ConstraintSet.VISIBLE : ConstraintSet.GONE);
set.setAlpha(actionId, visible ? 1.0f : 0.0f);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 5f6d95f..0fbe1f7 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -319,6 +319,7 @@
CharSequence content = (isMissedCall && !hasMessageText)
? context.getString(R.string.missed_call) : message.getText();
Uri dataUri = message != null ? message.getDataUri() : null;
+ if (DEBUG) Log.d(TAG, "Notification message has text: " + hasMessageText);
return tile
.toBuilder()
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 96fbe69..3bc91bc 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -391,6 +391,7 @@
statusText = getStatusTextByType(status.getActivity());
}
views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
+ views.setViewVisibility(R.id.messages_count, View.GONE);
setMaxLines(views);
// Secondary text color for statuses.
TypedValue typedValue = new TypedValue();
@@ -530,6 +531,7 @@
if (mLayoutSize == LAYOUT_SMALL) {
views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
views.setViewVisibility(R.id.name, View.GONE);
+ views.setViewVisibility(R.id.messages_count, View.GONE);
} else {
views.setViewVisibility(R.id.predefined_icon, View.GONE);
views.setViewVisibility(R.id.name, View.VISIBLE);
@@ -544,6 +546,7 @@
if (mLayoutSize == LAYOUT_SMALL) {
views.setViewVisibility(R.id.name, View.VISIBLE);
views.setViewVisibility(R.id.predefined_icon, View.GONE);
+ views.setViewVisibility(R.id.messages_count, View.GONE);
}
String status = PeopleSpaceUtils.getLastInteractionString(mContext,
mTile.getLastInteractionTimestamp());
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 5be2d4a..117be47 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -285,7 +285,7 @@
updateTilesByUri(key, sbn, action);
}
} catch (Exception e) {
- Log.e(TAG, "Exception: " + e);
+ Log.e(TAG, "Throwing exception: " + e);
}
}
@@ -498,7 +498,7 @@
if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) {
if (DEBUG) Log.i(TAG, "Adding notification to storage, appWidgetId: " + appWidgetId);
storedTile = augmentTileFromNotification(mContext, storedTile, sbn);
- } else if (storedTile.getNotificationKey().equals(sbn.getKey())) {
+ } else if (Objects.equals(storedTile.getNotificationKey(), sbn.getKey())) {
if (DEBUG) {
Log.i(TAG, "Removing notification from storage, appWidgetId: " + appWidgetId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 9a889e0..980024e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -225,16 +225,7 @@
mQsPanelCallback.onScanStateChanged(false);
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-
- if (mShouldAnimate) {
- animateDetailVisibleDiff(x, y, visibleDiff, listener);
- } else {
- if (showingDetail) {
- showImmediately();
- } else {
- hideImmediately();
- }
- }
+ animateDetailVisibleDiff(x, y, visibleDiff, listener);
}
protected void animateDetailVisibleDiff(int x, int y, boolean visibleDiff, AnimatorListener listener) {
@@ -242,27 +233,16 @@
mAnimatingOpen = mDetailAdapter != null;
if (mFullyExpanded || mDetailAdapter != null) {
setAlpha(1);
- mClipper.animateCircularClip(x, y, mDetailAdapter != null, listener);
+ mClipper.updateCircularClip(mShouldAnimate, x, y, mDetailAdapter != null, listener);
} else {
animate().alpha(0)
- .setDuration(FADE_DURATION)
+ .setDuration(mShouldAnimate ? FADE_DURATION : 0)
.setListener(listener)
.start();
}
}
}
- void showImmediately() {
- setVisibility(VISIBLE);
- mClipper.cancelAnimator();
- mClipper.showBackground();
- }
-
- public void hideImmediately() {
- mClipper.cancelAnimator();
- setVisibility(View.GONE);
- }
-
protected void setupDetailFooter(DetailAdapter adapter) {
final Intent settingsIntent = adapter.getSettingsIntent();
mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index daf8ca3..63cedd0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -37,6 +37,19 @@
}
public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
+ updateCircularClip(true /* animate */, x, y, in, listener);
+ }
+
+ /**
+ * @param animate whether or not animation has a duration of 0. Either way, {@code listener}
+ * will be called.
+ * @param x x position where animation should originate
+ * @param y y position where animation should originate
+ * @param in whether animating in or out
+ * @param listener Animation listener. Called whether or not {@code animate} is true.
+ */
+ public void updateCircularClip(boolean animate, int x, int y, boolean in,
+ AnimatorListener listener) {
if (mAnimator != null) {
mAnimator.cancel();
}
@@ -58,15 +71,16 @@
} else {
mAnimator = ViewAnimationUtils.createCircularReveal(mDetail, x, y, r, innerR);
}
- mAnimator.setDuration((long)(mAnimator.getDuration() * 1.5));
+ mAnimator.setDuration(animate ? (long) (mAnimator.getDuration() * 1.5) : 0);
if (listener != null) {
mAnimator.addListener(listener);
}
if (in) {
- mBackground.startTransition((int)(mAnimator.getDuration() * 0.6));
+ mBackground.startTransition(animate ? (int) (mAnimator.getDuration() * 0.6) : 0);
mAnimator.addListener(mVisibleOnStart);
} else {
- mDetail.postDelayed(mReverseBackground, (long)(mAnimator.getDuration() * 0.65));
+ mDetail.postDelayed(mReverseBackground,
+ animate ? (long) (mAnimator.getDuration() * 0.65) : 0);
mAnimator.addListener(mGoneOnEnd);
}
mAnimator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 52e05a4..3467838 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -34,6 +34,7 @@
import com.android.systemui.R;
import com.android.systemui.globalactions.GlobalActionsDialogLite;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
@@ -62,6 +63,7 @@
private final QuickQSPanelController mQuickQSPanelController;
private final TunerService mTunerService;
private final MetricsLogger mMetricsLogger;
+ private final FalsingManager mFalsingManager;
private final SettingsButton mSettingsButton;
private final TextView mBuildText;
private final View mEdit;
@@ -83,8 +85,9 @@
private final View.OnClickListener mSettingsOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- // Don't do anything until view are unhidden
- if (!mExpanded) {
+ // Don't do anything until views are unhidden. Don't do anything if the tap looks
+ // suspicious.
+ if (!mExpanded || mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return;
}
@@ -132,7 +135,7 @@
DeviceProvisionedController deviceProvisionedController, UserTracker userTracker,
QSPanelController qsPanelController, QSDetailDisplayer qsDetailDisplayer,
QuickQSPanelController quickQSPanelController,
- TunerService tunerService, MetricsLogger metricsLogger,
+ TunerService tunerService, MetricsLogger metricsLogger, FalsingManager falsingManager,
@Named(PM_LITE_ENABLED) boolean showPMLiteButton,
GlobalActionsDialogLite globalActionsDialog) {
super(view);
@@ -146,6 +149,7 @@
mQuickQSPanelController = quickQSPanelController;
mTunerService = tunerService;
mMetricsLogger = metricsLogger;
+ mFalsingManager = falsingManager;
mSettingsButton = mView.findViewById(R.id.settings_button);
mBuildText = mView.findViewById(R.id.build);
@@ -184,9 +188,13 @@
return false;
});
- mEdit.setOnClickListener(view ->
- mActivityStarter.postQSRunnableDismissingKeyguard(() ->
- mQsPanelController.showEdit(view)));
+ mEdit.setOnClickListener(view -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return;
+ }
+ mActivityStarter.postQSRunnableDismissingKeyguard(() ->
+ mQsPanelController.showEdit(view));
+ });
mMultiUserSwitch.setQSDetailDisplayer(mQsDetailDisplayer);
mQsPanelController.setFooterPageIndicator(mPageIndicator);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index a45b1319..abe3219 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -173,7 +173,7 @@
@Override
public void init(QSTile tile) {
init(v -> tile.click(), v -> tile.secondaryClick(), view -> {
- tile.longClick();
+ tile.longClick(this);
return true;
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index e8fc245b..375c79f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -31,6 +31,7 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
@@ -43,6 +44,7 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
+import android.view.View;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
@@ -58,6 +60,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
@@ -276,7 +279,7 @@
mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_CLICK, 0, getMetricsSpec(),
getInstanceId());
mQSLogger.logTileClick(mTileSpec, mStatusBarStateController.getState(), mState.state);
- if (!mFalsingManager.isFalseTap(true, 0.1)) {
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
mHandler.sendEmptyMessage(H.CLICK);
}
}
@@ -292,14 +295,15 @@
mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
}
- public void longClick() {
+ @Override
+ public void longClick(@Nullable View view) {
mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)
.addTaggedData(FIELD_STATUS_BAR_STATE,
mStatusBarStateController.getState())));
mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_LONG_PRESS, 0, getMetricsSpec(),
getInstanceId());
mQSLogger.logTileLongClick(mTileSpec, mStatusBarStateController.getState(), mState.state);
- mHandler.sendEmptyMessage(H.LONG_CLICK);
+ mHandler.obtainMessage(H.LONG_CLICK, view).sendToTarget();
}
public LogMaker populate(LogMaker logMaker) {
@@ -374,10 +378,15 @@
/**
* Handles long click on the tile by launching the {@link Intent} defined in
- * {@link QSTileImpl#getLongClickIntent}
+ * {@link QSTileImpl#getLongClickIntent}.
+ *
+ * @param view The view from which the opening window will be animated.
*/
- protected void handleLongClick() {
- mActivityStarter.postStartActivityDismissingKeyguard(getLongClickIntent(), 0);
+ protected void handleLongClick(@Nullable View view) {
+ ActivityLaunchAnimator.Controller animationController =
+ view != null ? ActivityLaunchAnimator.Controller.fromView(view) : null;
+ mActivityStarter.postStartActivityDismissingKeyguard(getLongClickIntent(), 0,
+ animationController);
}
/**
@@ -614,7 +623,7 @@
handleSecondaryClick();
} else if (msg.what == LONG_CLICK) {
name = "handleLongClick";
- handleLongClick();
+ handleLongClick((View) msg.obj);
} else if (msg.what == REFRESH_STATE) {
name = "handleRefreshState";
handleRefreshState(msg.obj);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
index 7a8b2c6..b953323 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
@@ -118,7 +118,11 @@
override fun setClickable(clickable: Boolean) {
super.setClickable(clickable)
background = if (clickable && mShowRippleEffect) {
- mTileBackground
+ mRipple?.also {
+ // In case that the colorBackgroundDrawable was used as the background, make sure
+ // it has the correct callback instead of null
+ colorBackgroundDrawable?.callback = it
+ }
} else {
colorBackgroundDrawable
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index fa99eed..d78dbae9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -142,7 +142,7 @@
}
@Override
- protected void handleLongClick() {
+ protected void handleLongClick(View view) {
handleClick();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 31a98db..b7cb615 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -22,6 +22,7 @@
import android.os.Looper;
import android.provider.MediaStore;
import android.service.quicksettings.Tile;
+import android.view.View;
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
@@ -107,7 +108,7 @@
}
@Override
- protected void handleLongClick() {
+ protected void handleLongClick(View view) {
handleClick();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index bf96558..47212d2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -48,6 +48,7 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.ui.WalletActivity;
import java.util.List;
import java.util.concurrent.Executor;
@@ -117,8 +118,22 @@
@Override
protected void handleClick() {
- mActivityStarter.postStartActivityDismissingKeyguard(
- mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0);
+ mUiHandler.post(() -> {
+ mHost.collapsePanels();
+ if (mHasCard) {
+ Intent intent = new Intent(mContext, WalletActivity.class)
+ .setAction(Intent.ACTION_VIEW)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ } else {
+ if (mQuickAccessWalletClient.createWalletIntent() == null) {
+ Log.w(TAG, "Could not get intent of the wallet app.");
+ return;
+ }
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0);
+ }
+ });
}
@Override
@@ -147,9 +162,7 @@
} else {
state.state = Tile.STATE_UNAVAILABLE;
}
- if (!isDeviceLocked) {
- state.sideViewDrawable = mCardViewDrawable;
- }
+ state.sideViewDrawable = isDeviceLocked ? null : mCardViewDrawable;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 8e6398f..9525975 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -105,9 +105,7 @@
}
} else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE
&& view.getTag(R.id.cross_fade_layer_type_changed_tag) != null) {
- if (view.getTag(R.id.cross_fade_layer_type_changed_tag) != null) {
- view.setLayerType(View.LAYER_TYPE_NONE, null);
- }
+ view.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index f51fbed..ec3a857 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -97,4 +97,8 @@
public boolean isOngoingCallStatusBarChipEnabled() {
return mFlagReader.isEnabled(R.bool.flag_ongoing_call_status_bar_chip);
}
+
+ public boolean isSmartspaceEnabled() {
+ return mFlagReader.isEnabled(R.bool.flag_smartspace);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 2856ebb..23e6a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -576,6 +576,7 @@
mKeysKeptForRemoteInputHistory.remove(key);
}
if (mRemoteInputController.isRemoteInputActive(entry)) {
+ entry.mRemoteEditImeVisible = false;
mRemoteInputController.removeRemoteInput(entry, null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index e27c1a2..bb6165a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -35,7 +35,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator
+import com.android.systemui.statusbar.notification.ExpandAnimationParameters
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK
import com.android.systemui.statusbar.phone.DozeParameters
@@ -107,11 +107,18 @@
else 0)
}
+ var qsPanelExpansion = 0f
+ set(value) {
+ if (field == value) return
+ field = value
+ scheduleUpdate()
+ }
+
/**
* When launching an app from the shade, the animations progress should affect how blurry the
* shade is, overriding the expansion amount.
*/
- var notificationLaunchAnimationParams: ActivityLaunchAnimator.ExpandAnimationParameters? = null
+ var notificationLaunchAnimationParams: ExpandAnimationParameters? = null
set(value) {
field = value
if (value != null) {
@@ -158,8 +165,9 @@
updateScheduled = false
val normalizedBlurRadius = MathUtils.constrain(shadeAnimation.radius,
blurUtils.minBlurRadius, blurUtils.maxBlurRadius)
- val combinedBlur = (shadeSpring.radius * INTERACTION_BLUR_FRACTION +
+ var combinedBlur = (shadeSpring.radius * INTERACTION_BLUR_FRACTION +
normalizedBlurRadius * ANIMATION_BLUR_FRACTION).toInt()
+ combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsPanelExpansion))
var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius).toFloat()
shadeRadius *= 1f - brightnessMirrorSpring.ratio
val launchProgress = notificationLaunchAnimationParams?.linearProgress ?: 0f
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 24515f7..b6357b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -90,9 +90,14 @@
/** Sets the state of whether the user activities are forced or not. */
default void setForceUserActivity(boolean forceUserActivity) {}
- /** Sets the state of whether the user activities are forced or not. */
+ /** Sets the state of whether an activity is launching or not. */
default void setLaunchingActivity(boolean launching) {}
+ /** Get whether an activity is launching or not. */
+ default boolean isLaunchingActivity() {
+ return false;
+ }
+
/** Sets the state of whether the scrim is visible or not. */
default void setScrimsVisibility(int scrimsVisibility) {}
@@ -137,7 +142,7 @@
default void setDozing(boolean dozing) {}
/** Sets the state of whether plugin open is forced or not. */
- default void setForcePluginOpen(boolean forcePluginOpen) {}
+ default void setForcePluginOpen(boolean forcePluginOpen, Object token) {}
/** Gets whether we are forcing plugin open or not. */
default boolean getForcePluginOpen() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 6023b7f..c811fdd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -26,17 +26,18 @@
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.View;
+import androidx.annotation.DimenRes;
import androidx.core.graphics.ColorUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
+import com.android.systemui.R;
import java.util.concurrent.Executor;
@@ -47,6 +48,10 @@
* need to be careful to synchronize when necessary.
*/
public class ScrimView extends View {
+
+ @DimenRes
+ private static final int CORNER_RADIUS = R.dimen.notification_scrim_corner_radius;
+
private final Object mColorLock = new Object();
@GuardedBy("mColorLock")
@@ -260,4 +265,27 @@
mExecutor.execute(r);
}
}
+
+ /**
+ * Make bottom edge concave so overlap between layers is not visible for alphas between 0 and 1
+ * @return height of concavity
+ */
+ public float enableBottomEdgeConcave() {
+ if (mDrawable instanceof ScrimDrawable) {
+ float radius = getResources().getDimensionPixelSize(CORNER_RADIUS);
+ ((ScrimDrawable) mDrawable).setBottomEdgeConcave(radius);
+ return radius;
+ }
+ return 0;
+ }
+
+ /**
+ * Enable view to have rounded corners with radius of {@link #CORNER_RADIUS}
+ */
+ public void enableRoundedCorners() {
+ if (mDrawable instanceof ScrimDrawable) {
+ int radius = getResources().getDimensionPixelSize(CORNER_RADIUS);
+ ((ScrimDrawable) mDrawable).setRoundedCorners(radius);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
index 77b4186..3196eba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
@@ -33,11 +33,11 @@
* Expanding ripple effect that shows when charging begins.
*/
class ChargingRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
- private var rippleInProgress: Boolean = false
private val rippleShader = RippleShader()
private val defaultColor: Int = 0xffffffff.toInt()
private val ripplePaint = Paint()
+ var rippleInProgress: Boolean = false
var radius: Float = 0.0f
set(value) { rippleShader.radius = value }
var origin: PointF = PointF()
@@ -62,7 +62,8 @@
super.onAttachedToWindow()
}
- fun startRipple() {
+ @JvmOverloads
+ fun startRipple(onAnimationEnd: Runnable? = null) {
if (rippleInProgress) {
return // Ignore if ripple effect is already playing
}
@@ -80,6 +81,7 @@
override fun onAnimationEnd(animation: Animator?) {
rippleInProgress = false
visibility = View.GONE
+ onAnimationEnd?.run()
}
})
animator.start()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index 2900462..71af271 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -17,11 +17,11 @@
package com.android.systemui.statusbar.charging
import android.content.Context
-import android.content.res.Configuration
+import android.graphics.PixelFormat
import android.graphics.PointF
import android.util.DisplayMetrics
import android.view.View
-import android.view.ViewGroupOverlay
+import android.view.WindowManager
import com.android.internal.annotations.VisibleForTesting
import com.android.settingslib.Utils
import com.android.systemui.dagger.SysUISingleton
@@ -30,9 +30,7 @@
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.KeyguardStateController
import java.io.PrintWriter
-import java.lang.Integer.max
import javax.inject.Inject
/***
@@ -45,11 +43,22 @@
batteryController: BatteryController,
configurationController: ConfigurationController,
featureFlags: FeatureFlags,
- private val context: Context,
- private val keyguardStateController: KeyguardStateController
+ private val context: Context
) {
private var charging: Boolean? = null
private val rippleEnabled: Boolean = featureFlags.isChargingRippleEnabled
+ private val windowLayoutParams = WindowManager.LayoutParams().apply {
+ width = WindowManager.LayoutParams.MATCH_PARENT
+ height = WindowManager.LayoutParams.MATCH_PARENT
+ layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ format = PixelFormat.TRANSLUCENT
+ type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY
+ fitInsetsTypes = 0 // Ignore insets from all system bars
+ title = "Wired Charging Animation"
+ flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
+ }
+
@VisibleForTesting
var rippleView: ChargingRippleView = ChargingRippleView(context, attrs = null)
@@ -68,8 +77,8 @@
val wasCharging = charging
charging = nowCharging
// Only triggers when the keyguard is active and the device is just plugged in.
- if (wasCharging == false && nowCharging && keyguardStateController.isShowing) {
- rippleView.startRipple()
+ if ((wasCharging == null || !wasCharging) && nowCharging) {
+ startRipple()
}
}
}
@@ -85,46 +94,41 @@
override fun onOverlayChanged() {
updateRippleColor()
}
- override fun onConfigChanged(newConfig: Configuration?) {
- layoutRippleView()
- }
}
configurationController.addCallback(configurationChangedListener)
commandRegistry.registerCommand("charging-ripple") { ChargingRippleCommand() }
- }
-
- fun setViewHost(viewHost: View) {
- // Add the ripple view as an overlay of the root view so that it always
- // shows on top.
- viewHost.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
- override fun onViewDetachedFromWindow(view: View?) {}
-
- override fun onViewAttachedToWindow(view: View?) {
- (viewHost.viewRootImpl.view.overlay as ViewGroupOverlay).add(rippleView)
- layoutRippleView()
- viewHost.removeOnAttachStateChangeListener(this)
- }
- })
-
updateRippleColor()
}
- private fun layoutRippleView() {
- // Overlays are not auto measured and laid out so we do it manually here.
+ fun startRipple() {
+ if (rippleView.rippleInProgress) {
+ return
+ }
+ val mWM = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+ windowLayoutParams.packageName = context.opPackageName
+ rippleView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
+ override fun onViewDetachedFromWindow(view: View?) {}
+
+ override fun onViewAttachedToWindow(view: View?) {
+ layoutRipple()
+ rippleView.startRipple(Runnable {
+ mWM.removeView(rippleView)
+ })
+ rippleView.removeOnAttachStateChangeListener(this)
+ }
+ })
+ mWM.addView(rippleView, windowLayoutParams)
+ }
+
+ private fun layoutRipple() {
+ // TODO(shanh): Set origin base on phone orientation.
val displayMetrics = DisplayMetrics()
context.display.getRealMetrics(displayMetrics)
val width = displayMetrics.widthPixels
val height = displayMetrics.heightPixels
- if (width != rippleView.width || height != rippleView.height) {
- rippleView.apply {
- measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY))
- layout(0, 0, width, height)
- origin = PointF(width / 2f, height.toFloat())
- radius = max(width, height).toFloat()
- }
- }
+ rippleView.origin = PointF(width / 2f, height.toFloat())
+ rippleView.radius = Integer.max(width, height).toFloat()
}
private fun updateRippleColor() {
@@ -134,7 +138,7 @@
inner class ChargingRippleCommand : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
- rippleView.startRipple()
+ startRipple()
}
override fun help(pw: PrintWriter) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
deleted file mode 100644
index 23d13d3..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- * Copyright (C) 2018 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.statusbar.notification;
-
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_APP_START;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.app.ActivityManager;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.MathUtils;
-import android.view.IRemoteAnimationFinishedCallback;
-import android.view.IRemoteAnimationRunner;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
-import android.view.SyncRtSurfaceTransactionApplier;
-import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-
-import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.systemui.Interpolators;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
-import com.android.systemui.statusbar.phone.NotificationPanelViewController;
-import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
-
-import java.util.concurrent.Executor;
-
-/**
- * A class that allows activities to be launched in a seamless way where the notification
- * transforms nicely into the starting window.
- */
-public class ActivityLaunchAnimator {
-
- private static final int ANIMATION_DURATION = 400;
- public static final long ANIMATION_DURATION_FADE_CONTENT = 67;
- public static final long ANIMATION_DURATION_FADE_APP = 200;
- public static final long ANIMATION_DELAY_ICON_FADE_IN = ANIMATION_DURATION -
- CollapsedStatusBarFragment.FADE_IN_DURATION - CollapsedStatusBarFragment.FADE_IN_DELAY
- - 16;
- private static final int ANIMATION_DURATION_NAV_FADE_IN = 266;
- private static final int ANIMATION_DURATION_NAV_FADE_OUT = 133;
- private static final long ANIMATION_DELAY_NAV_FADE_IN =
- ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN;
- private static final Interpolator NAV_FADE_IN_INTERPOLATOR =
- new PathInterpolator(0f, 0f, 0f, 1f);
- private static final Interpolator NAV_FADE_OUT_INTERPOLATOR =
- new PathInterpolator(0.2f, 0f, 1f, 1f);
- private static final long LAUNCH_TIMEOUT = 500;
- private final NotificationPanelViewController mNotificationPanel;
- private final NotificationListContainer mNotificationContainer;
- private final float mWindowCornerRadius;
- private final NotificationShadeWindowViewController mNotificationShadeWindowViewController;
- private final NotificationShadeDepthController mDepthController;
- private final Executor mMainExecutor;
- private Callback mCallback;
- private final Runnable mTimeoutRunnable = () -> {
- setAnimationPending(false);
- mCallback.onExpandAnimationTimedOut();
- };
- private boolean mAnimationPending;
- private boolean mAnimationRunning;
- private boolean mIsLaunchForActivity;
-
- public ActivityLaunchAnimator(
- NotificationShadeWindowViewController notificationShadeWindowViewController,
- Callback callback,
- NotificationPanelViewController notificationPanel,
- NotificationShadeDepthController depthController,
- NotificationListContainer container,
- Executor mainExecutor) {
- mNotificationPanel = notificationPanel;
- mNotificationContainer = container;
- mDepthController = depthController;
- mNotificationShadeWindowViewController = notificationShadeWindowViewController;
- mCallback = callback;
- mMainExecutor = mainExecutor;
- mWindowCornerRadius = ScreenDecorationsUtils
- .getWindowCornerRadius(mNotificationShadeWindowViewController.getView()
- .getResources());
- }
-
- public RemoteAnimationAdapter getLaunchAnimation(
- View sourceView, boolean occluded) {
- if (!(sourceView instanceof ExpandableNotificationRow)
- || !mCallback.areLaunchAnimationsEnabled() || occluded) {
- return null;
- }
- AnimationRunner animationRunner = new AnimationRunner(
- (ExpandableNotificationRow) sourceView);
- return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
- ANIMATION_DURATION - 150 /* statusBarTransitionDelay */);
- }
-
- public boolean isAnimationPending() {
- return mAnimationPending;
- }
-
- /**
- * Set the launch result the intent requested
- *
- * @param launchResult the launch result
- * @param wasIntentActivity was this launch for an activity
- */
- public void setLaunchResult(int launchResult, boolean wasIntentActivity) {
- mIsLaunchForActivity = wasIntentActivity;
- setAnimationPending((launchResult == ActivityManager.START_TASK_TO_FRONT
- || launchResult == ActivityManager.START_SUCCESS)
- && mCallback.areLaunchAnimationsEnabled());
- }
-
- public boolean isLaunchForActivity() {
- return mIsLaunchForActivity;
- }
-
- private void setAnimationPending(boolean pending) {
- mAnimationPending = pending;
- mNotificationShadeWindowViewController.setExpandAnimationPending(pending);
- if (pending) {
- mNotificationShadeWindowViewController.getView().postDelayed(mTimeoutRunnable,
- LAUNCH_TIMEOUT);
- } else {
- mNotificationShadeWindowViewController.getView().removeCallbacks(mTimeoutRunnable);
- }
- }
-
- public boolean isAnimationRunning() {
- return mAnimationRunning;
- }
-
- class AnimationRunner extends IRemoteAnimationRunner.Stub {
-
- private final ExpandableNotificationRow mSourceNotification;
- private final ExpandAnimationParameters mParams;
- private final Rect mWindowCrop = new Rect();
- private boolean mIsFullScreenLaunch = true;
- private final SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier;
-
- private final float mNotificationStartTopCornerRadius;
- private final float mNotificationStartBottomCornerRadius;
-
- AnimationRunner(ExpandableNotificationRow sourceNotification) {
- mSourceNotification = sourceNotification;
- mParams = new ExpandAnimationParameters();
- mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(mSourceNotification);
- mNotificationStartTopCornerRadius = mSourceNotification.getCurrentBackgroundRadiusTop();
- mNotificationStartBottomCornerRadius =
- mSourceNotification.getCurrentBackgroundRadiusBottom();
- }
-
- @Override
- public void onAnimationStart(@WindowManager.TransitionOldType int transit,
- RemoteAnimationTarget[] remoteAnimationTargets,
- RemoteAnimationTarget[] remoteAnimationWallpaperTargets,
- RemoteAnimationTarget[] remoteAnimationNonAppTargets,
- IRemoteAnimationFinishedCallback iRemoteAnimationFinishedCallback)
- throws RemoteException {
- mMainExecutor.execute(() -> {
- RemoteAnimationTarget primary = getPrimaryRemoteAnimationTarget(
- remoteAnimationTargets);
- if (primary == null) {
- setAnimationPending(false);
- invokeCallback(iRemoteAnimationFinishedCallback);
- mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
- return;
- }
-
- setExpandAnimationRunning(true);
- mIsFullScreenLaunch = primary.position.y == 0
- && primary.sourceContainerBounds.height()
- >= mNotificationPanel.getHeight();
- if (!mIsFullScreenLaunch) {
- mNotificationPanel.collapseWithDuration(ANIMATION_DURATION);
- }
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
- mParams.startPosition = mSourceNotification.getLocationOnScreen();
- mParams.startTranslationZ = mSourceNotification.getTranslationZ();
- mParams.startClipTopAmount = mSourceNotification.getClipTopAmount();
- if (mSourceNotification.isChildInGroup()) {
- int parentClip = mSourceNotification
- .getNotificationParent().getClipTopAmount();
- mParams.parentStartClipTopAmount = parentClip;
- // We need to calculate how much the child is clipped by the parent
- // because children always have 0 clipTopAmount
- if (parentClip != 0) {
- float childClip = parentClip
- - mSourceNotification.getTranslationY();
- if (childClip > 0.0f) {
- mParams.startClipTopAmount = (int) Math.ceil(childClip);
- }
- }
- }
- int targetWidth = primary.sourceContainerBounds.width();
- // If the notification panel is collapsed, the clip may be larger than the height.
- int notificationHeight = Math.max(mSourceNotification.getActualHeight()
- - mSourceNotification.getClipBottomAmount(), 0);
- int notificationWidth = mSourceNotification.getWidth();
- final RemoteAnimationTarget navigationBarTarget =
- getNavBarRemoteAnimationTarget(remoteAnimationNonAppTargets);
- anim.setDuration(ANIMATION_DURATION);
- anim.setInterpolator(Interpolators.LINEAR);
- anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mParams.linearProgress = animation.getAnimatedFraction();
- float progress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
- mParams.linearProgress);
- int newWidth = (int) MathUtils.lerp(notificationWidth,
- targetWidth, progress);
- mParams.left = (int) ((targetWidth - newWidth) / 2.0f);
- mParams.right = mParams.left + newWidth;
- mParams.top = (int) MathUtils.lerp(mParams.startPosition[1],
- primary.position.y, progress);
- mParams.bottom = (int) MathUtils.lerp(mParams.startPosition[1]
- + notificationHeight,
- primary.position.y + primary.sourceContainerBounds.bottom,
- progress);
- mParams.topCornerRadius = MathUtils.lerp(mNotificationStartTopCornerRadius,
- mWindowCornerRadius, progress);
- mParams.bottomCornerRadius = MathUtils.lerp(
- mNotificationStartBottomCornerRadius,
- mWindowCornerRadius, progress);
- applyParamsToWindow(primary);
- applyParamsToNotification(mParams);
- applyParamsToNotificationShade(mParams);
- applyNavigationBarParamsToWindow(navigationBarTarget);
- }
- });
- anim.addListener(new AnimatorListenerAdapter() {
- private boolean mWasCancelled;
-
- @Override
- public void onAnimationStart(Animator animation) {
- InteractionJankMonitor.getInstance().begin(mSourceNotification,
- CUJ_NOTIFICATION_APP_START);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mWasCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- setExpandAnimationRunning(false);
- invokeCallback(iRemoteAnimationFinishedCallback);
- if (!mWasCancelled) {
- InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_APP_START);
- } else {
- InteractionJankMonitor.getInstance().cancel(CUJ_NOTIFICATION_APP_START);
- }
- }
- });
- anim.start();
- setAnimationPending(false);
- });
- }
-
- private void invokeCallback(IRemoteAnimationFinishedCallback callback) {
- try {
- callback.onAnimationFinished();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
- private RemoteAnimationTarget getPrimaryRemoteAnimationTarget(
- RemoteAnimationTarget[] remoteAnimationTargets) {
- RemoteAnimationTarget primary = null;
- for (RemoteAnimationTarget app : remoteAnimationTargets) {
- if (app.mode == RemoteAnimationTarget.MODE_OPENING) {
- primary = app;
- break;
- }
- }
- return primary;
- }
-
- private RemoteAnimationTarget getNavBarRemoteAnimationTarget(
- RemoteAnimationTarget[] remoteAnimationTargets) {
- RemoteAnimationTarget navBar = null;
- for (RemoteAnimationTarget target : remoteAnimationTargets) {
- if (target.windowType == TYPE_NAVIGATION_BAR) {
- navBar = target;
- break;
- }
- }
- return navBar;
- }
-
- private void setExpandAnimationRunning(boolean running) {
- mNotificationPanel.setLaunchingNotification(running);
- mSourceNotification.setExpandAnimationRunning(running);
- mNotificationShadeWindowViewController.setExpandAnimationRunning(running);
- mNotificationContainer.setExpandingNotification(running ? mSourceNotification : null);
- mAnimationRunning = running;
- if (!running) {
- mCallback.onExpandAnimationFinished(mIsFullScreenLaunch);
- applyParamsToNotification(null);
- applyParamsToNotificationShade(null);
- }
-
- }
-
- private void applyParamsToNotificationShade(ExpandAnimationParameters params) {
- mNotificationContainer.applyExpandAnimationParams(params);
- mNotificationPanel.applyExpandAnimationParams(params);
- mDepthController.setNotificationLaunchAnimationParams(params);
- }
-
- private void applyParamsToNotification(ExpandAnimationParameters params) {
- mSourceNotification.applyExpandAnimationParams(params);
- }
-
- private void applyParamsToWindow(RemoteAnimationTarget app) {
- Matrix m = new Matrix();
- m.postTranslate(0, (float) (mParams.top - app.position.y));
- mWindowCrop.set(mParams.left, 0, mParams.right, mParams.getHeight());
- float cornerRadius = Math.min(mParams.topCornerRadius, mParams.bottomCornerRadius);
- SurfaceParams params = new SurfaceParams.Builder(app.leash)
- .withAlpha(1f)
- .withMatrix(m)
- .withWindowCrop(mWindowCrop)
- .withLayer(app.prefixOrderIndex)
- .withCornerRadius(cornerRadius)
- .withVisibility(true)
- .build();
- mSyncRtTransactionApplier.scheduleApply(params);
- }
-
- private void applyNavigationBarParamsToWindow(RemoteAnimationTarget navBarTarget) {
- if (navBarTarget == null) {
- return;
- }
-
- // calculate navigation bar fade-out progress
- final float fadeOutProgress = mParams.getProgress(0,
- ANIMATION_DURATION_NAV_FADE_OUT);
-
- // calculate navigation bar fade-in progress
- final float fadeInProgress = mParams.getProgress(ANIMATION_DELAY_NAV_FADE_IN,
- ANIMATION_DURATION_NAV_FADE_OUT);
-
- final SurfaceParams.Builder builder = new SurfaceParams.Builder(navBarTarget.leash);
- if (fadeInProgress > 0) {
- Matrix m = new Matrix();
- m.postTranslate(0, (float) (mParams.top - navBarTarget.position.y));
- mWindowCrop.set(mParams.left, 0, mParams.right, mParams.getHeight());
- builder.withMatrix(m)
- .withWindowCrop(mWindowCrop)
- .withVisibility(true);
- builder.withAlpha(NAV_FADE_IN_INTERPOLATOR.getInterpolation(fadeInProgress));
- } else {
- builder.withAlpha(1f - NAV_FADE_OUT_INTERPOLATOR.getInterpolation(fadeOutProgress));
- }
- mSyncRtTransactionApplier.scheduleApply(builder.build());
- }
-
- @Override
- public void onAnimationCancelled() throws RemoteException {
- mMainExecutor.execute(() -> {
- setAnimationPending(false);
- mCallback.onLaunchAnimationCancelled();
- });
- }
- };
-
- public static class ExpandAnimationParameters {
- public float linearProgress;
- int[] startPosition;
- float startTranslationZ;
- int left;
- int top;
- int right;
- int bottom;
- int startClipTopAmount;
- int parentStartClipTopAmount;
- float topCornerRadius;
- float bottomCornerRadius;
-
- public ExpandAnimationParameters() {
- }
-
- public int getTop() {
- return top;
- }
-
- public int getBottom() {
- return bottom;
- }
-
- public int getWidth() {
- return right - left;
- }
-
- public int getHeight() {
- return bottom - top;
- }
-
- public int getTopChange() {
- // We need this compensation to ensure that the QS moves in sync.
- int clipTopAmountCompensation = 0;
- if (startClipTopAmount != 0.0f) {
- clipTopAmountCompensation = (int) MathUtils.lerp(0, startClipTopAmount,
- Interpolators.FAST_OUT_SLOW_IN.getInterpolation(linearProgress));
- }
- return Math.min(top - startPosition[1] - clipTopAmountCompensation, 0);
- }
-
- public float getProgress() {
- return linearProgress;
- }
-
- public float getProgress(long delay, long duration) {
- return MathUtils.constrain((linearProgress * ANIMATION_DURATION - delay)
- / duration, 0.0f, 1.0f);
- }
-
- public int getStartClipTopAmount() {
- return startClipTopAmount;
- }
-
- public int getParentStartClipTopAmount() {
- return parentStartClipTopAmount;
- }
-
- public float getStartTranslationZ() {
- return startTranslationZ;
- }
-
- public float getTopCornerRadius() {
- return topCornerRadius;
- }
-
- public float getBottomCornerRadius() {
- return bottomCornerRadius;
- }
- }
-
- public interface Callback {
-
- /**
- * Called when the launch animation was cancelled.
- */
- void onLaunchAnimationCancelled();
-
- /**
- * Called when the launch animation has timed out without starting an actual animation.
- */
- void onExpandAnimationTimedOut();
-
- /**
- * Called when the expand animation has finished.
- *
- * @param launchIsFullScreen True if this launch was fullscreen, such that now the window
- * fills the whole screen
- */
- void onExpandAnimationFinished(boolean launchIsFullScreen);
-
- /**
- * Are animations currently enabled.
- */
- boolean areLaunchAnimationsEnabled();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
new file mode 100644
index 0000000..d5835fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
@@ -0,0 +1,44 @@
+package com.android.systemui.statusbar.notification
+
+import android.util.MathUtils
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.Interpolators
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator
+import kotlin.math.min
+
+/** Parameters for the notifications expand animations. */
+class ExpandAnimationParameters(
+ top: Int,
+ bottom: Int,
+ left: Int,
+ right: Int,
+
+ topCornerRadius: Float = 0f,
+ bottomCornerRadius: Float = 0f
+) : ActivityLaunchAnimator.State(top, bottom, left, right, topCornerRadius, bottomCornerRadius) {
+ @VisibleForTesting
+ constructor() : this(
+ top = 0, bottom = 0, left = 0, right = 0, topCornerRadius = 0f, bottomCornerRadius = 0f
+ )
+
+ var startTranslationZ = 0f
+ var startClipTopAmount = 0
+ var parentStartClipTopAmount = 0
+ var progress = 0f
+ var linearProgress = 0f
+
+ override val topChange: Int
+ get() {
+ // We need this compensation to ensure that the QS moves in sync.
+ var clipTopAmountCompensation = 0
+ if (startClipTopAmount.toFloat() != 0.0f) {
+ clipTopAmountCompensation = MathUtils.lerp(0f, startClipTopAmount.toFloat(),
+ Interpolators.FAST_OUT_SLOW_IN.getInterpolation(linearProgress)).toInt()
+ }
+ return min(super.topChange - clipTopAmountCompensation, 0)
+ }
+
+ fun getProgress(delay: Long, duration: Long): Float {
+ return ActivityLaunchAnimator.getProgress(linearProgress, delay, duration)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
new file mode 100644
index 0000000..2f966b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -0,0 +1,136 @@
+package com.android.systemui.statusbar.notification
+
+import android.view.View
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.systemui.statusbar.NotificationShadeDepthController
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import com.android.systemui.statusbar.phone.NotificationPanelViewController
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator
+import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController
+import kotlin.math.ceil
+import kotlin.math.max
+
+/** A provider of [NotificationLaunchAnimatorController]. */
+class NotificationLaunchAnimatorControllerProvider(
+ private val notificationShadeWindowViewController: NotificationShadeWindowViewController,
+ private val notificationPanelViewController: NotificationPanelViewController,
+ private val notificationListContainer: NotificationListContainer,
+ private val depthController: NotificationShadeDepthController
+) {
+ fun getAnimatorController(
+ notification: ExpandableNotificationRow
+ ): NotificationLaunchAnimatorController {
+ return NotificationLaunchAnimatorController(
+ notificationShadeWindowViewController,
+ notificationPanelViewController,
+ notificationListContainer,
+ depthController,
+ notification
+ )
+ }
+}
+
+/**
+ * An [ActivityLaunchAnimator.Controller] that animates an [ExpandableNotificationRow]. An instance
+ * of this class can be passed to [ActivityLaunchAnimator.startIntentWithAnimation] to animate a
+ * notification expanding into an opening window.
+ */
+class NotificationLaunchAnimatorController(
+ private val notificationShadeWindowViewController: NotificationShadeWindowViewController,
+ private val notificationPanelViewController: NotificationPanelViewController,
+ private val notificationListContainer: NotificationListContainer,
+ private val depthController: NotificationShadeDepthController,
+ private val notification: ExpandableNotificationRow
+) : ActivityLaunchAnimator.Controller {
+ override fun getRootView(): View = notification.rootView
+
+ override fun createAnimatorState(): ActivityLaunchAnimator.State {
+ // If the notification panel is collapsed, the clip may be larger than the height.
+ val height = max(0, notification.actualHeight - notification.clipBottomAmount)
+ val location = notification.locationOnScreen
+
+ val params = ExpandAnimationParameters(
+ top = location[1],
+ bottom = location[1] + height,
+ left = location[0],
+ right = location[0] + notification.width,
+ topCornerRadius = notification.currentBackgroundRadiusTop,
+ bottomCornerRadius = notification.currentBackgroundRadiusBottom
+ )
+
+ params.startTranslationZ = notification.translationZ
+ params.startClipTopAmount = notification.clipTopAmount
+ if (notification.isChildInGroup) {
+ val parentClip = notification.notificationParent.clipTopAmount
+ params.parentStartClipTopAmount = parentClip
+
+ // We need to calculate how much the child is clipped by the parent because children
+ // always have 0 clipTopAmount
+ if (parentClip != 0) {
+ val childClip = parentClip - notification.translationY
+ if (childClip > 0) {
+ params.startClipTopAmount = ceil(childClip.toDouble()).toInt()
+ }
+ }
+ }
+
+ return params
+ }
+
+ override fun onIntentStarted(willAnimate: Boolean) {
+ notificationShadeWindowViewController.setExpandAnimationRunning(willAnimate)
+ }
+
+ override fun onLaunchAnimationCancelled() {
+ // TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started
+ // here?
+ notificationShadeWindowViewController.setExpandAnimationRunning(false)
+ }
+
+ override fun onLaunchAnimationTimedOut() {
+ notificationShadeWindowViewController.setExpandAnimationRunning(false)
+ }
+
+ override fun onLaunchAnimationAborted() {
+ notificationShadeWindowViewController.setExpandAnimationRunning(false)
+ }
+
+ override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
+ notificationPanelViewController.setLaunchingNotification(true)
+ notification.isExpandAnimationRunning = true
+ notificationListContainer.setExpandingNotification(notification)
+
+ InteractionJankMonitor.getInstance().begin(notification,
+ InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
+ }
+
+ override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
+ InteractionJankMonitor.getInstance().end(InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
+
+ notificationPanelViewController.setLaunchingNotification(false)
+ notification.isExpandAnimationRunning = false
+ notificationShadeWindowViewController.setExpandAnimationRunning(false)
+ notificationListContainer.setExpandingNotification(null)
+ applyParams(null)
+ }
+
+ private fun applyParams(params: ExpandAnimationParameters?) {
+ notification.applyExpandAnimationParams(params)
+ notificationListContainer.applyExpandAnimationParams(params)
+ notificationPanelViewController.applyExpandAnimationParams(params)
+ depthController.notificationLaunchAnimationParams = params
+ }
+
+ override fun onLaunchAnimationProgress(
+ state: ActivityLaunchAnimator.State,
+ progress: Float,
+ linearProgress: Float
+ ) {
+ val params = state as ExpandAnimationParameters
+ params.progress = progress
+ params.linearProgress = linearProgress
+
+ applyParams(params)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 18e5ead..17f70cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -720,6 +720,10 @@
mCurrentAppearInterpolator = mSlowOutFastInInterpolator;
mCurrentAlphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
targetValue = 1.0f;
+ if (!mIsHeadsUpAnimation && isChildInGroup()) {
+ // slower fade in of children to avoid visibly overlapping with other children
+ mCurrentAlphaInterpolator = Interpolators.SLOW_OUT_LINEAR_IN;
+ }
} else {
mCurrentAppearInterpolator = Interpolators.FAST_OUT_SLOW_IN;
mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator;
@@ -819,6 +823,10 @@
if (mIsHeadsUpAnimation && !mIsAppearing) {
startWidthFraction = 0;
}
+ if (mIsAppearing && !mIsHeadsUpAnimation && isChildInGroup()) {
+ // Children in a group (when not heads up) should simply fade in.
+ startWidthFraction = 1;
+ }
float width = MathUtils.lerp(startWidthFraction, 1.0f, 1.0f - widthFraction)
* getWidth();
float left;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
index 3f7b8af..edd97af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
@@ -125,7 +125,7 @@
result = mNotificationTapHelper.onTouchEvent(ev, mView.getActualHeight());
} else if (ev.getAction() == MotionEvent.ACTION_UP) {
// If this is a false tap, capture the even so it doesn't result in a click.
- return mFalsingManager.isFalseTap(true, 0.1);
+ return mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY);
}
return result;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a3a4014..2ada281 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -19,7 +19,6 @@
import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
@@ -79,6 +78,7 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -86,7 +86,7 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -881,7 +881,7 @@
// Other parts of the system may intercept and handle all the falsing.
// Otherwise, if we see motion and follow-on events, try to classify them as a tap.
if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
- mFalsingManager.isFalseTap(true, 0.3);
+ mFalsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY);
}
return super.onInterceptTouchEvent(ev);
}
@@ -2045,9 +2045,8 @@
float extraWidthForClipping = params.getWidth() - getWidth();
setExtraWidthForClipping(extraWidthForClipping);
int top = params.getTop();
- float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
int startClipTopAmount = params.getStartClipTopAmount();
- int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation);
+ int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, params.getProgress());
if (mNotificationParent != null) {
float parentY = mNotificationParent.getTranslationY();
top -= parentY;
@@ -2096,7 +2095,7 @@
if (expandAnimationRunning) {
contentView.animate()
.alpha(0f)
- .setDuration(ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT)
+ .setDuration(ActivityLaunchAnimator.ANIMATION_DURATION_FADE_OUT_CONTENT)
.setInterpolator(Interpolators.ALPHA_OUT);
setAboveShelf(true);
mExpandAnimationRunning = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index 9588563..07d1e68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -31,7 +31,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
/**
* A view that can be used for both the dimmed and normal background of an notification.
@@ -277,13 +278,14 @@
invalidate();
}
- public void setExpandAnimationParams(ActivityLaunchAnimator.ExpandAnimationParameters params) {
+ /** Set the current expand animation parameters. */
+ public void setExpandAnimationParams(ExpandAnimationParameters params) {
mActualHeight = params.getHeight();
mActualWidth = params.getWidth();
float alphaProgress = Interpolators.ALPHA_IN.getInterpolation(
params.getProgress(
- ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT /* delay */,
- ActivityLaunchAnimator.ANIMATION_DURATION_FADE_APP /* duration */));
+ ActivityLaunchAnimator.ANIMATION_DURATION_FADE_OUT_CONTENT /* delay */,
+ ActivityLaunchAnimator.ANIMATION_DURATION_FADE_IN_WINDOW /* duration */));
mBackground.setAlpha((int) (mDrawableAlpha * (1.0f - alphaProgress)));
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 72f3216..2a2e733f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -16,14 +16,13 @@
package com.android.systemui.statusbar.notification.stack;
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
-
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 40c0b89..ad06e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.stack;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
@@ -91,6 +90,7 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 7baad1c..ce7b397 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -75,8 +75,8 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
@@ -1497,8 +1497,7 @@
}
@Override
- public void applyExpandAnimationParams(
- ActivityLaunchAnimator.ExpandAnimationParameters params) {
+ public void applyExpandAnimationParams(ExpandAnimationParameters params) {
mView.applyExpandAnimationParams(params);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 555df5c..364b532 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -26,7 +26,6 @@
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static java.lang.Float.isNaN;
@@ -100,6 +99,7 @@
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -111,16 +111,17 @@
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -178,6 +179,10 @@
* Fling until QS is completely hidden.
*/
private static final int FLING_HIDE = 2;
+ private static final long ANIMATION_DELAY_ICON_FADE_IN =
+ ActivityLaunchAnimator.ANIMATION_DURATION - CollapsedStatusBarFragment.FADE_IN_DURATION
+ - CollapsedStatusBarFragment.FADE_IN_DELAY - 16;
+
private final DozeParameters mDozeParameters;
private final OnHeightChangedListener mOnHeightChangedListener = new OnHeightChangedListener();
private final OnClickListener mOnClickListener = new OnClickListener();
@@ -477,6 +482,7 @@
private final UserManager mUserManager;
private final ShadeController mShadeController;
private final MediaDataManager mMediaDataManager;
+ private NotificationShadeDepthController mDepthController;
private int mDisplayId;
/**
@@ -576,6 +582,7 @@
ScrimController scrimController,
UserManager userManager,
MediaDataManager mediaDataManager,
+ NotificationShadeDepthController notificationShadeDepthController,
AmbientState ambientState,
FeatureFlags featureFlags) {
super(view, falsingManager, dozeLog, keyguardStateController,
@@ -594,6 +601,7 @@
mNotificationIconAreaController = notificationIconAreaController;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
+ mDepthController = notificationShadeDepthController;
mFeatureFlags = featureFlags;
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
@@ -603,7 +611,6 @@
mKeyguardQsUserSwitchEnabled =
mKeyguardUserSwitcherEnabled && mResources.getBoolean(
R.bool.config_keyguard_user_switch_opens_qs_details);
- keyguardUpdateMonitor.setKeyguardQsUserSwitchEnabled(mKeyguardQsUserSwitchEnabled);
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
mView.setWillNotDraw(!DEBUG);
@@ -1844,6 +1851,10 @@
mPulseExpansionHandler.setQsExpanded(expanded);
mKeyguardBypassController.setQSExpanded(expanded);
mStatusBarKeyguardViewManager.setQsExpanded(expanded);
+
+ if (mDisabledUdfpsController != null) {
+ mDisabledUdfpsController.setQsExpanded(expanded);
+ }
}
}
@@ -1991,8 +2002,21 @@
float qsExpansionFraction = getQsExpansionFraction();
mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
- mScrimController.setQsExpansion(qsExpansionFraction);
+ mScrimController.setQsPosition(qsExpansionFraction,
+ calculateQsBottomPosition(qsExpansionFraction));
mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
+ mDepthController.setQsPanelExpansion(qsExpansionFraction);
+ }
+
+ private int calculateQsBottomPosition(float qsExpansionFraction) {
+ int qsBottomY = (int) getHeaderTranslation() + mQs.getQsMinExpansionHeight();
+ if (qsExpansionFraction != 0.0) {
+ qsBottomY = (int) MathUtils.lerp(
+ qsBottomY, mQs.getDesiredHeight(), qsExpansionFraction);
+ }
+ // to account for shade overshooting animation, see setSectionPadding method
+ if (mSectionPadding > 0) qsBottomY += mSectionPadding;
+ return qsBottomY;
}
private String determineAccessibilityPaneTitle() {
@@ -3208,8 +3232,7 @@
return;
}
- boolean hideIcons = params.getProgress(
- ActivityLaunchAnimator.ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
+ boolean hideIcons = params.getProgress(ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
if (hideIcons != mHideIconsDuringNotificationLaunch) {
mHideIconsDuringNotificationLaunch = hideIcons;
if (!hideIcons) {
@@ -3544,7 +3567,8 @@
mUpdateMonitor,
mAuthController,
mStatusBarKeyguardViewManager,
- mKeyguardStateController);
+ mKeyguardStateController,
+ mFalsingManager);
mDisabledUdfpsController.init();
} else if (mDisabledUdfpsController != null && !udfpsEnrolled) {
mDisabledUdfpsController.destroy();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index d074e64..5aecb72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -527,6 +527,11 @@
}
@Override
+ public boolean isLaunchingActivity() {
+ return mCurrentState.mLaunchingActivity;
+ }
+
+ @Override
public void setScrimsVisibility(int scrimsVisibility) {
mCurrentState.mScrimsVisibility = scrimsVisibility;
apply(mCurrentState);
@@ -606,12 +611,21 @@
apply(mCurrentState);
}
+ private final Set<Object> mForceOpenTokens = new HashSet<>();
@Override
- public void setForcePluginOpen(boolean forcePluginOpen) {
- mCurrentState.mForcePluginOpen = forcePluginOpen;
- apply(mCurrentState);
- if (mForcePluginOpenListener != null) {
- mForcePluginOpenListener.onChange(forcePluginOpen);
+ public void setForcePluginOpen(boolean forceOpen, Object token) {
+ if (forceOpen) {
+ mForceOpenTokens.add(token);
+ } else {
+ mForceOpenTokens.remove(token);
+ }
+ final boolean previousForceOpenState = mCurrentState.mForcePluginOpen;
+ mCurrentState.mForcePluginOpen = !mForceOpenTokens.isEmpty();
+ if (previousForceOpenState != mCurrentState.mForcePluginOpen) {
+ apply(mCurrentState);
+ if (mForcePluginOpenListener != null) {
+ mForcePluginOpenListener.onChange(mCurrentState.mForcePluginOpen);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 2ff7c99..72f7ff8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -92,7 +92,6 @@
private View mBrightnessMirror;
private boolean mTouchActive;
private boolean mTouchCancelled;
- private boolean mExpandAnimationPending;
private boolean mExpandAnimationRunning;
private NotificationStackScrollLayout mStackScrollLayout;
private PhoneStatusBarView mStatusBarView;
@@ -235,7 +234,7 @@
|| ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
setTouchActive(false);
}
- if (mTouchCancelled || mExpandAnimationRunning || mExpandAnimationPending) {
+ if (mTouchCancelled || mExpandAnimationRunning) {
return false;
}
mFalsingCollector.onTouchEvent(ev);
@@ -435,8 +434,6 @@
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print(" mExpandAnimationPending=");
- pw.println(mExpandAnimationPending);
pw.print(" mExpandAnimationRunning=");
pw.println(mExpandAnimationRunning);
pw.print(" mTouchCancelled=");
@@ -445,19 +442,10 @@
pw.println(mTouchActive);
}
- public void setExpandAnimationPending(boolean pending) {
- if (mExpandAnimationPending != pending) {
- mExpandAnimationPending = pending;
- mNotificationShadeWindowController
- .setLaunchingActivity(mExpandAnimationPending | mExpandAnimationRunning);
- }
- }
-
public void setExpandAnimationRunning(boolean running) {
if (mExpandAnimationRunning != running) {
mExpandAnimationRunning = running;
- mNotificationShadeWindowController
- .setLaunchingActivity(mExpandAnimationPending | mExpandAnimationRunning);
+ mNotificationShadeWindowController.setLaunchingActivity(mExpandAnimationRunning);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java
index 66df936..95ecd3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java
@@ -64,7 +64,7 @@
mTrackTouch = event.getY() <= maxTouchableHeight;
break;
case MotionEvent.ACTION_MOVE:
- if (mTrackTouch && mFalsingManager.isFalseTap(false, 0)) {
+ if (mTrackTouch && !mFalsingManager.isSimpleTap()) {
makeInactive();
mTrackTouch = false;
}
@@ -78,10 +78,10 @@
// 1) See if we have confidence that we can activate after a single tap.
// 2) Else, see if it looks like a tap at all and check for a double-tap.
- if (!mFalsingManager.isFalseTap(true, 0)) {
+ if (!mFalsingManager.isFalseTap(FalsingManager.NO_PENALTY)) {
makeInactive();
return mDoubleTapListener.onDoubleTap();
- } else if (!mFalsingManager.isFalseTap(false, 0)) {
+ } else if (mFalsingManager.isSimpleTap()) {
if (mSlideBackListener != null && mSlideBackListener.onSlideBack()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 270a0f8..681f450 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -24,7 +24,6 @@
import android.annotation.IntDef;
import android.app.AlarmManager;
import android.graphics.Color;
-import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Trace;
import android.util.Log;
@@ -49,7 +48,6 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -142,6 +140,7 @@
private ScrimState mState = ScrimState.UNINITIALIZED;
private ScrimView mScrimInFront;
+ private ScrimView mNotificationsScrim;
private ScrimView mScrimBehind;
@Nullable
private ScrimView mScrimForBubble;
@@ -156,7 +155,6 @@
private final KeyguardVisibilityCallback mKeyguardVisibilityCallback;
private final Handler mHandler;
private final Executor mMainExecutor;
- private final BlurUtils mBlurUtils;
private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
@@ -180,6 +178,7 @@
private float mInFrontAlpha = NOT_INITIALIZED;
private float mBehindAlpha = NOT_INITIALIZED;
+ private float mNotificationsAlpha = NOT_INITIALIZED;
private float mBubbleAlpha = NOT_INITIALIZED;
private int mInFrontTint;
@@ -209,12 +208,11 @@
AlarmManager alarmManager, KeyguardStateController keyguardStateController,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
- BlurUtils blurUtils, ConfigurationController configurationController,
+ ConfigurationController configurationController,
FeatureFlags featureFlags, @Main Executor mainExecutor) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = featureFlags.isShadeOpaque() ? BUSY_SCRIM_ALPHA : GAR_SCRIM_ALPHA;
ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(BUBBLE_SCRIM_ALPHA);
- mBlurUtils = blurUtils;
mKeyguardStateController = keyguardStateController;
mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
@@ -259,13 +257,16 @@
/**
* Attach the controller to the supplied views.
*/
- public void attachViews(
- ScrimView scrimBehind, ScrimView scrimInFront, @Nullable ScrimView scrimForBubble) {
- mScrimBehind = scrimBehind;
+ public void attachViews(ScrimView behindScrim, ScrimView notificationsScrim,
+ ScrimView scrimInFront, @Nullable ScrimView scrimForBubble) {
+ mNotificationsScrim = notificationsScrim;
+ mScrimBehind = behindScrim;
mScrimInFront = scrimInFront;
mScrimForBubble = scrimForBubble;
updateThemeColors();
+ mNotificationsScrim.enableRoundedCorners();
+
if (mScrimBehindChangeRunnable != null) {
mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable, mMainExecutor);
mScrimBehindChangeRunnable = null;
@@ -280,6 +281,7 @@
}
mScrimBehind.setDefaultFocusHighlightEnabled(false);
+ mNotificationsScrim.setDefaultFocusHighlightEnabled(false);
mScrimInFront.setDefaultFocusHighlightEnabled(false);
if (mScrimForBubble != null) {
mScrimForBubble.setDefaultFocusHighlightEnabled(false);
@@ -344,6 +346,7 @@
// We need to disable focus otherwise AOD would end up with a gray overlay.
mScrimInFront.setFocusable(!state.isLowPowerState());
mScrimBehind.setFocusable(!state.isLowPowerState());
+ mNotificationsScrim.setFocusable(!state.isLowPowerState());
// Cancel blanking transitions that were pending before we requested a new state
if (mPendingFrameCallback != null) {
@@ -484,18 +487,20 @@
}
/**
- * Current state of the QuickSettings expansion when pulling it from the top.
+ * Current state of the QuickSettings when pulling it from the top.
*
- * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
+ * @param expansionFraction From 0 to 1 where 0 means collapsed and 1 expanded.
+ * @param qsPanelBottomY absolute Y position of qs panel bottom
*/
- public void setQsExpansion(float fraction) {
- if (isNaN(fraction)) {
+ public void setQsPosition(float expansionFraction, int qsPanelBottomY) {
+ if (isNaN(expansionFraction)) {
return;
}
- if (mQsExpansion != fraction) {
- mQsExpansion = fraction;
+ shiftNotificationsScrim(qsPanelBottomY);
+ updateNotificationsScrimAlpha(qsPanelBottomY);
+ if (mQsExpansion != expansionFraction) {
+ mQsExpansion = expansionFraction;
Log.d(TAG, "set qs fraction");
-
boolean relevantState = (mState == ScrimState.SHADE_LOCKED
|| mState == ScrimState.KEYGUARD
|| mState == ScrimState.PULSING
@@ -507,6 +512,32 @@
}
}
+ private void shiftNotificationsScrim(int qsPanelBottomY) {
+ if (qsPanelBottomY > 0) {
+ mNotificationsScrim.setTranslationY(qsPanelBottomY);
+ } else {
+ mNotificationsScrim.setTranslationY(0);
+ }
+ }
+
+ private void updateNotificationsScrimAlpha(int qsPanelBottomY) {
+ float newAlpha = 0;
+ if (qsPanelBottomY > 0) {
+ float interpolator = 0;
+ if (mState == ScrimState.UNLOCKED || mState == ScrimState.SHADE_LOCKED) {
+ interpolator = getInterpolatedFraction();
+ } else {
+ interpolator = mQsExpansion;
+ }
+ newAlpha = MathUtils.lerp(0, 1, interpolator);
+ }
+ if (newAlpha != mNotificationsAlpha) {
+ mNotificationsAlpha = newAlpha;
+ // update alpha without animating
+ mNotificationsScrim.setViewAlpha(newAlpha);
+ }
+ }
+
private void setOrAdaptCurrentAnimation(@Nullable View scrim) {
if (scrim == null) {
return;
@@ -575,6 +606,7 @@
return;
}
setOrAdaptCurrentAnimation(mScrimBehind);
+ setOrAdaptCurrentAnimation(mNotificationsScrim);
setOrAdaptCurrentAnimation(mScrimInFront);
setOrAdaptCurrentAnimation(mScrimForBubble);
dispatchScrimState(mScrimBehind.getViewAlpha());
@@ -591,14 +623,6 @@
}
/**
- * Sets the given drawable as the background of the scrim that shows up behind the
- * notifications.
- */
- public void setScrimBehindDrawable(Drawable drawable) {
- mScrimBehind.setDrawable(drawable);
- }
-
- /**
* Sets the front scrim opacity in AOD so it's not as bright.
* <p>
* Displays usually don't support multiple dimming settings when in low power mode.
@@ -667,10 +691,13 @@
mNeedsDrawableColorUpdate = false;
// Only animate scrim color if the scrim view is actually visible
boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0 && !mBlankScreen;
- boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen;
+ boolean animateBehindScrim = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen;
+ boolean animateScrimNotifications = mNotificationsScrim.getViewAlpha() != 0
+ && !mBlankScreen;
mScrimInFront.setColors(mColors, animateScrimInFront);
- mScrimBehind.setColors(mColors, animateScrimBehind);
+ mScrimBehind.setColors(mColors, animateScrimNotifications);
+ mNotificationsScrim.setColors(mColors, animateScrimNotifications);
dispatchScrimState(mScrimBehind.getViewAlpha());
}
@@ -687,6 +714,7 @@
}
setScrimAlpha(mScrimInFront, mInFrontAlpha);
setScrimAlpha(mScrimBehind, mBehindAlpha);
+ setScrimAlpha(mNotificationsScrim, mNotificationsAlpha);
if (mScrimForBubble != null) {
boolean animateScrimForBubble = mScrimForBubble.getViewAlpha() != 0 && !mBlankScreen;
@@ -744,7 +772,9 @@
if (scrim == mScrimInFront) {
return "front_scrim";
} else if (scrim == mScrimBehind) {
- return "back_scrim";
+ return "behind_scrim";
+ } else if (scrim == mNotificationsScrim) {
+ return "notifications_scrim";
} else if (scrim == mScrimForBubble) {
return "bubble_scrim";
}
@@ -817,6 +847,8 @@
return mInFrontAlpha;
} else if (scrim == mScrimBehind) {
return mBehindAlpha;
+ } else if (scrim == mNotificationsScrim) {
+ return mNotificationsAlpha;
} else if (scrim == mScrimForBubble) {
return mBubbleAlpha;
} else {
@@ -829,6 +861,8 @@
return mInFrontTint;
} else if (scrim == mScrimBehind) {
return mBehindTint;
+ } else if (scrim == mNotificationsScrim) {
+ return Color.TRANSPARENT;
} else if (scrim == mScrimForBubble) {
return mBubbleTint;
} else {
@@ -858,8 +892,9 @@
}
if (isAnimating(mScrimBehind)
- || isAnimating(mScrimInFront)
- || isAnimating(mScrimForBubble)) {
+ || isAnimating(mNotificationsScrim)
+ || isAnimating(mScrimInFront)
+ || isAnimating(mScrimForBubble)) {
if (callback != null && callback != mCallback) {
// Since we only notify the callback that we're finished once everything has
// finished, we need to make sure that any changing callbacks are also invoked
@@ -884,7 +919,7 @@
// At the end of the animation we need to remove the tint.
if (mState == ScrimState.UNLOCKED) {
mInFrontTint = Color.TRANSPARENT;
- mBehindTint = Color.TRANSPARENT;
+ mBehindTint = mState.getBehindTint();
mBubbleTint = Color.TRANSPARENT;
updateScrimColor(mScrimInFront, mInFrontAlpha, mInFrontTint);
updateScrimColor(mScrimBehind, mBehindAlpha, mBehindTint);
@@ -996,12 +1031,6 @@
mScrimBehind.postOnAnimationDelayed(callback, 32 /* delayMillis */);
}
- public int getBackgroundColor() {
- int color = mColors.getMainColor();
- return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)),
- Color.red(color), Color.green(color), Color.blue(color));
- }
-
public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
// TODO: remove this. This is necessary because of an order-of-operations limitation.
// The fix is to move more of these class into @StatusBarScope
@@ -1047,7 +1076,7 @@
pw.print(" tint=0x");
pw.println(Integer.toHexString(mScrimInFront.getTint()));
- pw.print(" backScrim:");
+ pw.print(" behindScrim:");
pw.print(" viewAlpha=");
pw.print(mScrimBehind.getViewAlpha());
pw.print(" alpha=");
@@ -1055,6 +1084,14 @@
pw.print(" tint=0x");
pw.println(Integer.toHexString(mScrimBehind.getTint()));
+ pw.print(" notificationsScrim:");
+ pw.print(" viewAlpha=");
+ pw.print(mNotificationsScrim.getViewAlpha());
+ pw.print(" alpha=");
+ pw.print(mNotificationsAlpha);
+ pw.print(" tint=0x");
+ pw.println(Integer.toHexString(mNotificationsScrim.getTint()));
+
pw.print(" bubbleScrim:");
pw.print(" viewAlpha=");
pw.print(mScrimForBubble.getViewAlpha());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index b82863e..a9774d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -129,6 +129,13 @@
mBehindAlpha = mDefaultScrimAlpha;
mBubbleAlpha = 0f;
mFrontAlpha = 0f;
+ mBehindTint = Color.BLACK;
+ }
+
+ // to make sure correct color is returned before "prepare" is called
+ @Override
+ public int getBehindTint() {
+ return Color.BLACK;
}
},
@@ -228,7 +235,7 @@
mAnimateChange = !mLaunchingAffordanceWithPreview;
mFrontTint = Color.TRANSPARENT;
- mBehindTint = Color.TRANSPARENT;
+ mBehindTint = Color.BLACK;
mBubbleTint = Color.TRANSPARENT;
mBlankScreen = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 8ed9cd6..7e433e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -173,6 +173,7 @@
import com.android.systemui.plugins.OverlayPlugin;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -206,11 +207,10 @@
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.ChargingRippleView;
import com.android.systemui.statusbar.charging.WiredChargingRippleController;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -263,7 +263,7 @@
ActivityStarter, KeyguardStateController.Callback,
OnHeadsUpChangedListener, CommandQueue.Callbacks,
ColorExtractor.OnColorsChangedListener, ConfigurationListener,
- StatusBarStateController.StateListener, ActivityLaunchAnimator.Callback,
+ StatusBarStateController.StateListener,
LifecycleOwner, BatteryController.BatteryStateChangeCallback {
public static final boolean MULTIUSER_DEBUG = false;
@@ -385,7 +385,6 @@
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
private LightRevealScrim mLightRevealScrim;
- private ChargingRippleView mChargingRipple;
private WiredChargingRippleController mChargingRippleAnimationController;
private PowerButtonReveal mPowerButtonReveal;
private CircleReveal mCircleReveal;
@@ -682,6 +681,9 @@
new FalsingManager.FalsingBeliefListener() {
@Override
public void onFalse() {
+ // Hides quick settings.
+ mNotificationPanelViewController.resetViews(true);
+ // Hides bouncer and quick-quick settings.
mStatusBarKeyguardViewManager.reset(true);
}
};
@@ -692,6 +694,7 @@
private boolean mVibrateOnOpening;
private final VibratorHelper mVibratorHelper;
private ActivityLaunchAnimator mActivityLaunchAnimator;
+ private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
protected StatusBarNotificationPresenter mPresenter;
private NotificationActivityStarter mNotificationActivityStarter;
private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
@@ -1058,7 +1061,7 @@
mMainThreadHandler.post(() -> {
mOverlays.remove(plugin);
mNotificationShadeWindowController
- .setForcePluginOpen(mOverlays.size() != 0);
+ .setForcePluginOpen(mOverlays.size() != 0, this);
});
}
@@ -1081,7 +1084,7 @@
.setStateListener(b -> mOverlays.forEach(
o -> o.setCollapseDesired(b)));
mNotificationShadeWindowController
- .setForcePluginOpen(mOverlays.size() != 0);
+ .setForcePluginOpen(mOverlays.size() != 0, this);
});
}
}
@@ -1215,6 +1218,8 @@
});
ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind);
+ ScrimView notificationsScrim = mNotificationShadeWindowView
+ .findViewById(R.id.scrim_notifications);
ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front);
ScrimView scrimForBubble = mBubblesManagerOptional.isPresent()
? mBubblesManagerOptional.get().getScrimForBubble() : null;
@@ -1223,10 +1228,9 @@
mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible);
mLockscreenLockIconController.onScrimVisibilityChanged(scrimsVisible);
});
- mScrimController.attachViews(scrimBehind, scrimInFront, scrimForBubble);
+ mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront, scrimForBubble);
mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
- mChargingRippleAnimationController.setViewHost(mNotificationShadeWindowView);
updateLightRevealScrimVisibility();
mNotificationPanelViewController.initDependencies(
@@ -1370,16 +1374,18 @@
private void setUpPresenter() {
// Set up the initial notification state.
- mActivityLaunchAnimator = new ActivityLaunchAnimator(
- mNotificationShadeWindowViewController, this, mNotificationPanelViewController,
- mNotificationShadeDepthControllerLazy.get(),
+ mActivityLaunchAnimator = new ActivityLaunchAnimator();
+ mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
+ mNotificationShadeWindowViewController,
+ mNotificationPanelViewController,
mStackScrollerController.getNotificationListContainer(),
- mContext.getMainExecutor());
+ mNotificationShadeDepthControllerLazy.get()
+ );
// TODO: inject this.
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
mHeadsUpManager, mNotificationShadeWindowView, mStackScrollerController,
- mDozeScrimController, mScrimController, mActivityLaunchAnimator,
+ mDozeScrimController, mScrimController, mNotificationShadeWindowController,
mDynamicPrivacyController, mKeyguardStateController,
mKeyguardIndicationController,
this /* statusBar */, mShadeController, mCommandQueue, mInitController,
@@ -1392,6 +1398,7 @@
mStatusBarNotificationActivityStarterBuilder
.setStatusBar(this)
.setActivityLaunchAnimator(mActivityLaunchAnimator)
+ .setNotificationAnimatorControllerProvider(mNotificationAnimationProvider)
.setNotificationPresenter(mPresenter)
.setNotificationPanelViewController(mNotificationPanelViewController)
.build();
@@ -1519,6 +1526,7 @@
mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
mLockscreenLockIconController = statusBarComponent.getLockscreenLockIconController();
mLockscreenLockIconController.init();
+ statusBarComponent.getAuthRippleController().init();
mNotificationPanelViewController.setLaunchAffordanceListener(
mLockscreenLockIconController::onShowingLaunchAffordanceChanged);
@@ -1798,7 +1806,8 @@
@Override
public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
startActivityDismissingKeyguard(intent, false, dismissShade,
- false /* disallowEnterPictureInPictureWhileLaunching */, callback, 0);
+ false /* disallowEnterPictureInPictureWhileLaunching */, callback, 0,
+ null /* animationController */);
}
public void setQsExpanded(boolean expanded) {
@@ -1990,16 +1999,16 @@
return mHeadsUpAppearanceController.shouldBeVisible();
}
+ /** A launch animation was cancelled. */
//TODO: These can / should probably be moved to NotificationPresenter or ShadeController
- @Override
public void onLaunchAnimationCancelled() {
if (!mPresenter.isCollapsing()) {
onClosingFinished();
}
}
- @Override
- public void onExpandAnimationFinished(boolean launchIsFullScreen) {
+ /** A launch animation ended. */
+ public void onLaunchAnimationEnd(boolean launchIsFullScreen) {
if (!mPresenter.isCollapsing()) {
onClosingFinished();
}
@@ -2008,20 +2017,20 @@
}
}
- @Override
- public void onExpandAnimationTimedOut() {
+ /** A launch animation timed out. */
+ public void onLaunchAnimationTimedOut(boolean isLaunchForActivity) {
if (mPresenter.isPresenterFullyCollapsed() && !mPresenter.isCollapsing()
- && mActivityLaunchAnimator != null
- && !mActivityLaunchAnimator.isLaunchForActivity()) {
+ && isLaunchForActivity) {
onClosingFinished();
} else {
mShadeController.collapsePanel(true /* animate */);
}
}
- @Override
+ /** Whether we should animate an activity launch. */
public boolean areLaunchAnimationsEnabled() {
- return mState == StatusBarState.SHADE;
+ // TODO(b/184121838): Support lock screen launch animations.
+ return mState == StatusBarState.SHADE && !isOccluded();
}
public boolean isDeviceInVrMode() {
@@ -2725,7 +2734,7 @@
boolean dismissShade, int flags) {
startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade,
false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
- flags);
+ flags, null /* animationController */);
}
public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
@@ -2733,55 +2742,75 @@
startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 0);
}
- public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
+ private void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
- final Callback callback, int flags) {
+ final Callback callback, int flags,
+ @Nullable ActivityLaunchAnimator.Controller animationController) {
if (onlyProvisioned && !mDeviceProvisionedController.isDeviceProvisioned()) return;
final boolean afterKeyguardGone = mActivityIntentHelper.wouldLaunchResolverActivity(
intent, mLockscreenUserManager.getCurrentUserId());
+
+ ActivityLaunchAnimator.Controller animController = null;
+ if (animationController != null && areLaunchAnimationsEnabled()) {
+ animController = dismissShade ? new StatusBarLaunchAnimatorController(
+ animationController, this, true /* isLaunchForActivity */)
+ : animationController;
+ }
+ final ActivityLaunchAnimator.Controller animCallbackForLambda = animController;
+
+ // If we animate, we will dismiss the shade only once the animation is done. This is taken
+ // care of by the StatusBarLaunchAnimationController.
+ boolean dismissShadeDirectly = dismissShade && animController == null;
+
Runnable runnable = () -> {
mAssistManagerLazy.get().hideAssist();
intent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(flags);
- int result = ActivityManager.START_CANCELED;
- ActivityOptions options = new ActivityOptions(getActivityOptions(mDisplayId,
- null /* remoteAnimation */));
- options.setDisallowEnterPictureInPictureWhileLaunching(
- disallowEnterPictureInPictureWhileLaunching);
- if (CameraIntents.isInsecureCameraIntent(intent)) {
- // Normally an activity will set it's requested rotation
- // animation on its window. However when launching an activity
- // causes the orientation to change this is too late. In these cases
- // the default animation is used. This doesn't look good for
- // the camera (as it rotates the camera contents out of sync
- // with physical reality). So, we ask the WindowManager to
- // force the crossfade animation if an orientation change
- // happens to occur during the launch.
- options.setRotationAnimationHint(
- WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
- }
- if (intent.getAction() == Settings.Panel.ACTION_VOLUME) {
- // Settings Panel is implemented as activity(not a dialog), so
- // underlying app is paused and may enter picture-in-picture mode
- // as a result.
- // So we need to disable picture-in-picture mode here
- // if it is volume panel.
- options.setDisallowEnterPictureInPictureWhileLaunching(true);
- }
- try {
- result = ActivityTaskManager.getService().startActivityAsUser(
- null, mContext.getBasePackageName(), mContext.getAttributionTag(),
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
- options.toBundle(), UserHandle.CURRENT.getIdentifier());
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to start activity", e);
- }
+ int[] result = new int[] { ActivityManager.START_CANCELED };
+
+ mActivityLaunchAnimator.startIntentWithAnimation(animCallbackForLambda, (adapter) -> {
+ ActivityOptions options = new ActivityOptions(
+ getActivityOptions(mDisplayId, adapter));
+ options.setDisallowEnterPictureInPictureWhileLaunching(
+ disallowEnterPictureInPictureWhileLaunching);
+ if (CameraIntents.isInsecureCameraIntent(intent)) {
+ // Normally an activity will set it's requested rotation
+ // animation on its window. However when launching an activity
+ // causes the orientation to change this is too late. In these cases
+ // the default animation is used. This doesn't look good for
+ // the camera (as it rotates the camera contents out of sync
+ // with physical reality). So, we ask the WindowManager to
+ // force the crossfade animation if an orientation change
+ // happens to occur during the launch.
+ options.setRotationAnimationHint(
+ WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
+ }
+ if (intent.getAction() == Settings.Panel.ACTION_VOLUME) {
+ // Settings Panel is implemented as activity(not a dialog), so
+ // underlying app is paused and may enter picture-in-picture mode
+ // as a result.
+ // So we need to disable picture-in-picture mode here
+ // if it is volume panel.
+ options.setDisallowEnterPictureInPictureWhileLaunching(true);
+ }
+
+ try {
+ result[0] = ActivityTaskManager.getService().startActivityAsUser(
+ null, mContext.getBasePackageName(), mContext.getAttributionTag(),
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
+ options.toBundle(), UserHandle.CURRENT.getIdentifier());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to start activity", e);
+ }
+ return result[0];
+ });
+
if (callback != null) {
- callback.onActivityStarted(result);
+ callback.onActivityStarted(result[0]);
}
};
Runnable cancelRunnable = () -> {
@@ -2789,7 +2818,7 @@
callback.onActivityStarted(ActivityManager.START_CANCELED);
}
};
- executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
+ executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShadeDirectly,
afterKeyguardGone, true /* deferred */);
}
@@ -3134,18 +3163,34 @@
}
@Override
- public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
- mHandler.post(() -> startPendingIntentDismissingKeyguard(intent));
+ public void postStartActivityDismissingKeyguard(PendingIntent intent) {
+ postStartActivityDismissingKeyguard(intent, null /* animationController */);
+ }
+
+ @Override
+ public void postStartActivityDismissingKeyguard(final PendingIntent intent,
+ @Nullable ActivityLaunchAnimator.Controller animationController) {
+ mHandler.post(() -> startPendingIntentDismissingKeyguard(intent,
+ null /* intentSentUiThreadCallback */, animationController));
}
@Override
public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
- mHandler.postDelayed(() ->
- handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/), delay);
+ postStartActivityDismissingKeyguard(intent, delay, null /* animationController */);
}
- private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
- startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
+ @Override
+ public void postStartActivityDismissingKeyguard(Intent intent, int delay,
+ @Nullable ActivityLaunchAnimator.Controller animationController) {
+ mHandler.postDelayed(
+ () ->
+ startActivityDismissingKeyguard(intent, true /* onlyProvisioned */,
+ true /* dismissShade */,
+ false /* disallowEnterPictureInPictureWhileLaunching */,
+ null /* callback */,
+ 0 /* flags */,
+ animationController),
+ delay);
}
@Override
@@ -3618,6 +3663,23 @@
mShadeController.runPostCollapseRunnables();
}
+ /**
+ * Collapse the panel directly if we are on the main thread, post the collapsing on the main
+ * thread if we are not.
+ */
+ void collapsePanelOnMainThread() {
+ if (Looper.getMainLooper().isCurrentThread()) {
+ mShadeController.collapsePanel();
+ } else {
+ mContext.getMainExecutor().execute(mShadeController::collapsePanel);
+ }
+ }
+
+ /** Collapse the panel. The collapsing will be animated for the given {@code duration}. */
+ void collapsePanelWithDuration(int duration) {
+ mNotificationPanelViewController.collapseWithDuration(duration);
+ }
+
@Override
public void onStatePreChange(int oldState, int newState) {
// If we're visible and switched to SHADE_LOCKED (the user dragged
@@ -4043,7 +4105,8 @@
final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
startActivityDismissingKeyguard(cameraIntent,
false /* onlyProvisioned */, true /* dismissShade */,
- true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0);
+ true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
+ null /* animationController */);
} else {
if (!mDeviceInteractive) {
// Avoid flickering of the scrim when we instant launch the camera and the bouncer
@@ -4094,7 +4157,8 @@
if (!mStatusBarKeyguardViewManager.isShowing()) {
startActivityDismissingKeyguard(emergencyIntent,
false /* onlyProvisioned */, true /* dismissShade */,
- true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0);
+ true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
+ null /* animationController */);
return;
}
@@ -4415,7 +4479,14 @@
KeyboardShortcuts.dismiss();
}
- public void executeActionDismissingKeyguard(Runnable action, boolean afterKeyguardGone) {
+ /**
+ * Dismiss the keyguard then execute an action.
+ *
+ * @param action The action to execute after dismissing the keyguard.
+ * @param collapsePanel Whether we should collapse the panel after dismissing the keyguard.
+ */
+ private void executeActionDismissingKeyguard(Runnable action, boolean afterKeyguardGone,
+ boolean collapsePanel) {
if (!mDeviceProvisionedController.isDeviceProvisioned()) return;
dismissKeyguardThenExecute(() -> {
@@ -4431,7 +4502,8 @@
action.run();
}).start();
- return mShadeController.collapsePanel();
+ boolean deferred = collapsePanel ? mShadeController.collapsePanel() : false;
+ return deferred;
}, afterKeyguardGone);
}
@@ -4443,27 +4515,54 @@
@Override
public void startPendingIntentDismissingKeyguard(
final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback) {
- startPendingIntentDismissingKeyguard(intent, intentSentUiThreadCallback, null /* row */);
+ startPendingIntentDismissingKeyguard(intent, intentSentUiThreadCallback,
+ (ActivityLaunchAnimator.Controller) null);
+ }
+
+ @Override
+ public void startPendingIntentDismissingKeyguard(PendingIntent intent,
+ Runnable intentSentUiThreadCallback, View associatedView) {
+ ActivityLaunchAnimator.Controller animationController = null;
+ if (associatedView instanceof ExpandableNotificationRow) {
+ animationController = mNotificationAnimationProvider.getAnimatorController(
+ ((ExpandableNotificationRow) associatedView));
+ }
+
+ startPendingIntentDismissingKeyguard(intent, intentSentUiThreadCallback,
+ animationController);
}
@Override
public void startPendingIntentDismissingKeyguard(
final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback,
- View associatedView) {
+ @Nullable ActivityLaunchAnimator.Controller animationController) {
final boolean afterKeyguardGone = intent.isActivity()
&& mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
mLockscreenUserManager.getCurrentUserId());
+ boolean animate = animationController != null && areLaunchAnimationsEnabled();
+ boolean collapse = !animate;
executeActionDismissingKeyguard(() -> {
try {
- intent.send(null, 0, null, null, null, null, getActivityOptions(
- mDisplayId,
- mActivityLaunchAnimator.getLaunchAnimation(associatedView, isOccluded())));
+ // We wrap animationCallback with a StatusBarLaunchAnimatorController so that the
+ // shade is collapsed after the animation (or when it is cancelled, aborted, etc).
+ ActivityLaunchAnimator.Controller controller =
+ animate ? new StatusBarLaunchAnimatorController(animationController, this,
+ intent.isActivity())
+ : null;
+
+ mActivityLaunchAnimator.startPendingIntentWithAnimation(
+ controller,
+ (animationAdapter) -> intent.sendAndReturnResult(null, 0, null, null, null,
+ null, getActivityOptions(mDisplayId, animationAdapter)));
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
Log.w(TAG, "Sending intent failed: " + e);
-
+ if (!collapse) {
+ // executeActionDismissingKeyguard did not collapse for us already.
+ collapsePanelOnMainThread();
+ }
// TODO: Dismiss Keyguard.
}
if (intent.isActivity()) {
@@ -4472,7 +4571,7 @@
if (intentSentUiThreadCallback != null) {
postOnUiThread(intentSentUiThreadCallback);
}
- }, afterKeyguardGone);
+ }, afterKeyguardGone, collapse);
}
private void postOnUiThread(Runnable runnable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index ef2444e..2815ce7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -187,6 +187,7 @@
private int mLastBiometricMode;
private boolean mLastLockVisible;
private boolean mLastLockOrientationIsPortrait;
+ private boolean mQsExpanded;
private OnDismissAction mAfterKeyguardGoneAction;
private Runnable mKeyguardGoneCancelAction;
@@ -1128,9 +1129,16 @@
}
/**
+ * Whether qs is currently expanded.
+ */
+ public boolean isQsExpanded() {
+ return mQsExpanded;
+ }
+ /**
* Set whether qs is currently expanded
*/
public void setQsExpanded(boolean expanded) {
+ mQsExpanded = expanded;
if (mAlternateAuthInterceptor != null) {
mAlternateAuthInterceptor.setQsExpanded(expanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
new file mode 100644
index 0000000..d45f64f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
@@ -0,0 +1,47 @@
+package com.android.systemui.statusbar.phone
+
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator
+
+/**
+ * A [ActivityLaunchAnimator.Controller] that takes care of collapsing the status bar at the right
+ * time.
+ */
+class StatusBarLaunchAnimatorController(
+ private val delegate: ActivityLaunchAnimator.Controller,
+ private val statusBar: StatusBar,
+ private val isLaunchForActivity: Boolean = true
+) : ActivityLaunchAnimator.Controller by delegate {
+ override fun onIntentStarted(willAnimate: Boolean) {
+ delegate.onIntentStarted(willAnimate)
+ if (!willAnimate) {
+ statusBar.collapsePanelOnMainThread()
+ }
+ }
+
+ override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
+ delegate.onLaunchAnimationStart(isExpandingFullyAbove)
+ if (!isExpandingFullyAbove) {
+ statusBar.collapsePanelWithDuration(ActivityLaunchAnimator.ANIMATION_DURATION.toInt())
+ }
+ }
+
+ override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
+ delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
+ statusBar.onLaunchAnimationEnd(isExpandingFullyAbove)
+ }
+
+ override fun onLaunchAnimationCancelled() {
+ delegate.onLaunchAnimationCancelled()
+ statusBar.onLaunchAnimationCancelled()
+ }
+
+ override fun onLaunchAnimationTimedOut() {
+ delegate.onLaunchAnimationTimedOut()
+ statusBar.onLaunchAnimationTimedOut(isLaunchForActivity)
+ }
+
+ override fun onLaunchAnimationAborted() {
+ delegate.onLaunchAnimationAborted()
+ statusBar.collapsePanelOnMainThread()
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 801ac96..2e918da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -21,7 +21,6 @@
import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -40,7 +39,6 @@
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.EventLog;
-import android.view.RemoteAnimationAdapter;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
@@ -52,6 +50,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
@@ -60,11 +59,10 @@
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -124,6 +122,7 @@
private final NotificationPresenter mPresenter;
private final NotificationPanelViewController mNotificationPanel;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
+ private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
private final OnUserInteractionCallback mOnUserInteractionCallback;
private boolean mIsCollapsingToShowActivityOverLockscreen;
@@ -162,7 +161,8 @@
StatusBar statusBar,
NotificationPresenter presenter,
NotificationPanelViewController panel,
- ActivityLaunchAnimator activityLaunchAnimator) {
+ ActivityLaunchAnimator activityLaunchAnimator,
+ NotificationLaunchAnimatorControllerProvider notificationAnimationProvider) {
mContext = context;
mCommandQueue = commandQueue;
mMainThreadHandler = mainThreadHandler;
@@ -198,6 +198,7 @@
mPresenter = presenter;
mNotificationPanel = panel;
mActivityLaunchAnimator = activityLaunchAnimator;
+ mNotificationAnimationProvider = notificationAnimationProvider;
if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@@ -400,17 +401,15 @@
}
if (Looper.getMainLooper().isCurrentThread()) {
- mBubblesManagerOptional.get().expandStackAndSelectBubble(entry);
+ expandBubbleStack(entry);
} else {
- mMainThreadHandler.post(
- () -> mBubblesManagerOptional.get().expandStackAndSelectBubble(entry));
+ mMainThreadHandler.post(() -> expandBubbleStack(entry));
}
+ }
- // expandStackAndSelectBubble won't affect shouldCollapse, so we can collapse directly even
- // if we are not on the main thread.
- if (shouldCollapse()) {
- collapseOnMainThread();
- }
+ private void expandBubbleStack(NotificationEntry entry) {
+ mBubblesManagerOptional.get().expandStackAndSelectBubble(entry);
+ mShadeController.collapsePanel();
}
private void startNotificationIntent(
@@ -420,32 +419,36 @@
ExpandableNotificationRow row,
boolean wasOccluded,
boolean isActivityIntent) {
- RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(row,
- wasOccluded);
mLogger.logStartNotificationIntent(entry.getKey(), intent);
try {
- if (adapter != null) {
- ActivityTaskManager.getService()
- .registerRemoteAnimationForNextActivityStart(
- intent.getCreatorPackage(), adapter);
+ ActivityLaunchAnimator.Controller animationController = null;
+ if (!wasOccluded && mStatusBar.areLaunchAnimationsEnabled()) {
+ animationController = new StatusBarLaunchAnimatorController(
+ mNotificationAnimationProvider.getAnimatorController(row), mStatusBar,
+ isActivityIntent);
}
- long eventTime = row.getAndResetLastActionUpTime();
- Bundle options = eventTime > 0
- ? getActivityOptions(
- mStatusBar.getDisplayId(),
- adapter,
- mKeyguardStateController.isShowing(),
- eventTime)
- : getActivityOptions(mStatusBar.getDisplayId(), adapter);
- int launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
- null, null, options);
- mMainThreadHandler.post(() -> {
- mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
- if (shouldCollapse()) {
- collapseOnMainThread();
- }
- });
- } catch (RemoteException | PendingIntent.CanceledException e) {
+
+ mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
+ (adapter) -> {
+ long eventTime = row.getAndResetLastActionUpTime();
+ Bundle options = eventTime > 0
+ ? getActivityOptions(
+ mStatusBar.getDisplayId(),
+ adapter,
+ mKeyguardStateController.isShowing(),
+ eventTime)
+ : getActivityOptions(mStatusBar.getDisplayId(), adapter);
+ return intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
+ null, null, options);
+ });
+
+ // Note that other cases when we should still collapse (like activity already on top) is
+ // handled by the StatusBarLaunchAnimatorController.
+ boolean shouldCollapse = animationController == null;
+ if (shouldCollapse) {
+ collapseOnMainThread();
+ }
+ } catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
mLogger.logSendingIntentFailed(e);
@@ -458,20 +461,30 @@
ExpandableNotificationRow row) {
mActivityStarter.dismissKeyguardThenExecute(() -> {
AsyncTask.execute(() -> {
- int launchResult = TaskStackBuilder.create(mContext)
- .addNextIntentWithParentStack(intent)
- .startActivities(getActivityOptions(
- mStatusBar.getDisplayId(),
- mActivityLaunchAnimator.getLaunchAnimation(
- row, mStatusBar.isOccluded())),
- new UserHandle(UserHandle.getUserId(appUid)));
+ ActivityLaunchAnimator.Controller animationController = null;
+ if (!mStatusBar.isOccluded() && mStatusBar.areLaunchAnimationsEnabled()) {
+ animationController = new StatusBarLaunchAnimatorController(
+ mNotificationAnimationProvider.getAnimatorController(row), mStatusBar,
+ true /* isActivityIntent */);
+ }
+
+ mActivityLaunchAnimator.startIntentWithAnimation(
+ animationController,
+ (adapter) -> TaskStackBuilder.create(mContext)
+ .addNextIntentWithParentStack(intent)
+ .startActivities(getActivityOptions(
+ mStatusBar.getDisplayId(),
+ adapter),
+ new UserHandle(UserHandle.getUserId(appUid))));
+
+ // Note that other cases when we should still collapse (like activity already on
+ // top) is handled by the StatusBarLaunchAnimatorController.
+ boolean shouldCollapse = animationController == null;
// Putting it back on the main thread, since we're touching views
mMainThreadHandler.post(() -> {
- mActivityLaunchAnimator.setLaunchResult(launchResult,
- true /* isActivityIntent */);
removeHUN(row);
- if (shouldCollapse()) {
+ if (shouldCollapse) {
mCommandQueue.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
true /* force */);
}
@@ -494,11 +507,10 @@
tsb.addNextIntent(intent);
}
tsb.startActivities(null, UserHandle.CURRENT);
- if (shouldCollapse()) {
- // Putting it back on the main thread, since we're touching views
- mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
- CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
- }
+
+ // Putting it back on the main thread, since we're touching views
+ mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
});
return true;
}, null, false /* afterKeyguardGone */);
@@ -576,11 +588,6 @@
}
}
- private boolean shouldCollapse() {
- return mStatusBarStateController.getState() != StatusBarState.SHADE
- || !mActivityLaunchAnimator.isAnimationPending();
- }
-
private boolean shouldSuppressFullScreenIntent(NotificationEntry entry) {
if (mPresenter.isDeviceInVrMode()) {
return true;
@@ -639,6 +646,7 @@
private NotificationPresenter mNotificationPresenter;
private NotificationPanelViewController mNotificationPanelViewController;
private ActivityLaunchAnimator mActivityLaunchAnimator;
+ private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
@Inject
public Builder(
@@ -714,12 +722,20 @@
return this;
}
+ /** Set the ActivityLaunchAnimator. */
public Builder setActivityLaunchAnimator(ActivityLaunchAnimator activityLaunchAnimator) {
mActivityLaunchAnimator = activityLaunchAnimator;
return this;
}
- /** Set the NotificationPanelViewController */
+ /** Set the NotificationLaunchAnimatorControllerProvider. */
+ public Builder setNotificationAnimatorControllerProvider(
+ NotificationLaunchAnimatorControllerProvider notificationAnimationProvider) {
+ mNotificationAnimationProvider = notificationAnimationProvider;
+ return this;
+ }
+
+ /** Set the NotificationPanelViewController. */
public Builder setNotificationPanelViewController(
NotificationPanelViewController notificationPanelViewController) {
mNotificationPanelViewController = notificationPanelViewController;
@@ -759,7 +775,8 @@
mStatusBar,
mNotificationPresenter,
mNotificationPanelViewController,
- mActivityLaunchAnimator);
+ mActivityLaunchAnimator,
+ mNotificationAnimationProvider);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 94edd1e..088f947 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -57,7 +57,6 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.AboveShelfObserver;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -117,7 +116,7 @@
private final AccessibilityManager mAccessibilityManager;
private final KeyguardManager mKeyguardManager;
- private final ActivityLaunchAnimator mActivityLaunchAnimator;
+ private final NotificationShadeWindowController mNotificationShadeWindowController;
private final IStatusBarService mBarService;
private final DynamicPrivacyController mDynamicPrivacyController;
private boolean mReinflateNotificationsOnUserSwitched;
@@ -133,7 +132,7 @@
NotificationStackScrollLayoutController stackScrollerController,
DozeScrimController dozeScrimController,
ScrimController scrimController,
- ActivityLaunchAnimator activityLaunchAnimator,
+ NotificationShadeWindowController notificationShadeWindowController,
DynamicPrivacyController dynamicPrivacyController,
KeyguardStateController keyguardStateController,
KeyguardIndicationController keyguardIndicationController,
@@ -152,7 +151,7 @@
mShadeController = shadeController;
mCommandQueue = commandQueue;
mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView());
- mActivityLaunchAnimator = activityLaunchAnimator;
+ mNotificationShadeWindowController = notificationShadeWindowController;
mAboveShelfObserver.setListener(statusBarWindow.findViewById(
R.id.notification_container_parent));
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -272,8 +271,7 @@
@Override
public boolean isCollapsing() {
return mNotificationPanel.isCollapsing()
- || mActivityLaunchAnimator.isAnimationPending()
- || mActivityLaunchAnimator.isAnimationRunning();
+ || mNotificationShadeWindowController.isLaunchingActivity();
}
private void maybeEndAmbientPulse() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
index ecd9613..e0cbbf0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
@@ -18,6 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
@@ -79,4 +80,10 @@
*/
@StatusBarScope
LockscreenLockIconController getLockscreenLockIconController();
+
+ /**
+ * Creates an AuthRippleController
+ */
+ @StatusBarScope
+ AuthRippleController getAuthRippleController();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 781abe6..0ce7538 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import com.android.systemui.R;
+import com.android.systemui.biometrics.AuthRippleView;
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
@@ -44,4 +45,13 @@
NotificationShadeWindowView notificationShadeWindowView) {
return notificationShadeWindowView.findViewById(R.id.lock_icon);
}
+
+ /** */
+ @Provides
+ @StatusBarComponent.StatusBarScope
+ @Nullable
+ public static AuthRippleView getAuthRippleView(
+ NotificationShadeWindowView notificationShadeWindowView) {
+ return notificationShadeWindowView.findViewById(R.id.auth_ripple);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index fc9a35d..c9011f4 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -81,7 +81,7 @@
@SysUISingleton
public class ThemeOverlayController extends SystemUI implements Dumpable {
protected static final String TAG = "ThemeOverlayController";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean DEBUG = true;
protected static final int NEUTRAL = 0;
protected static final int ACCENT = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
index 603d423..46611e0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
@@ -50,6 +50,8 @@
private var desiredMeasureWidth = 0
private var desiredMeasureHeight = 0
+ private var transitionVisibility = View.VISIBLE
+
/**
* The measured state of this view which is the one we will lay ourselves out with. This
* may differ from the currentState if there is an external animation or transition running.
@@ -81,6 +83,13 @@
}
}
+ override fun setTransitionVisibility(visibility: Int) {
+ // We store the last transition visibility assigned to this view to restore it later if
+ // necessary.
+ super.setTransitionVisibility(visibility)
+ transitionVisibility = visibility
+ }
+
override fun onFinishInflate() {
super.onFinishInflate()
val childCount = childCount
@@ -162,7 +171,16 @@
updateBounds()
translationX = currentState.translation.x
translationY = currentState.translation.y
+
CrossFadeHelper.fadeIn(this, currentState.alpha)
+
+ // CrossFadeHelper#fadeIn will change this view visibility, which overrides the transition
+ // visibility. We set the transition visibility again to make sure that this view plays well
+ // with GhostView, which sets the transition visibility and is used for activity launch
+ // animations.
+ if (transitionVisibility != View.VISIBLE) {
+ setTransitionVisibility(transitionVisibility)
+ }
}
private fun applyCurrentStateOnPredraw() {
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index ba063a8..c1835db 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -28,8 +28,10 @@
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.LifecycleActivity;
@@ -44,6 +46,7 @@
private final QuickAccessWalletClient mQuickAccessWalletClient;
private final KeyguardStateController mKeyguardStateController;
+ private final KeyguardDismissUtil mKeyguardDismissUtil;
private final ActivityStarter mActivityStarter;
private final Executor mExecutor;
private final Handler mHandler;
@@ -54,12 +57,14 @@
public WalletActivity(
QuickAccessWalletClient quickAccessWalletClient,
KeyguardStateController keyguardStateController,
+ KeyguardDismissUtil keyguardDismissUtil,
ActivityStarter activityStarter,
@Background Executor executor,
- @Background Handler handler,
+ @Main Handler handler,
UserTracker userTracker) {
mQuickAccessWalletClient = quickAccessWalletClient;
mKeyguardStateController = keyguardStateController;
+ mKeyguardDismissUtil = keyguardDismissUtil;
mActivityStarter = activityStarter;
mExecutor = executor;
mHandler = handler;
@@ -88,20 +93,30 @@
mExecutor,
mHandler,
mUserTracker,
- !mKeyguardStateController.isUnlocked());
+ mKeyguardStateController);
+ // Clicking the wallet button will open the wallet app if the device is unlocked; bring up
+ // the security bouncer otherwise.
walletView.getWalletButton().setOnClickListener(
- v -> mActivityStarter.startActivity(
- mQuickAccessWalletClient.createWalletIntent(), true));
+ v -> {
+ if (mKeyguardStateController.isUnlocked()) {
+ mActivityStarter.startActivity(
+ mQuickAccessWalletClient.createWalletIntent(), true);
+ } else {
+ mKeyguardDismissUtil.executeWhenUnlocked(() -> false, false);
+ }
+ });
}
@Override
protected void onStart() {
super.onStart();
+ mKeyguardStateController.addCallback(mWalletScreenController);
}
@Override
protected void onResume() {
super.onResume();
+ mWalletScreenController.queryWalletCards();
}
@Override
@@ -116,6 +131,7 @@
@Override
protected void onDestroy() {
+ mKeyguardStateController.removeCallback(mWalletScreenController);
mWalletScreenController.onDismissed();
super.onDestroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
index a93f0f0..d195062 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
@@ -42,6 +42,7 @@
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.util.ArrayList;
import java.util.List;
@@ -52,7 +53,8 @@
public class WalletScreenController implements
WalletCardCarousel.OnSelectionListener,
QuickAccessWalletClient.OnWalletCardsRetrievedCallback,
- QuickAccessWalletClient.WalletServiceEventListener {
+ QuickAccessWalletClient.WalletServiceEventListener,
+ KeyguardStateController.Callback {
private static final String TAG = "WalletScreenCtrl";
private static final String PREFS_HAS_CARDS = "has_cards";
@@ -65,6 +67,7 @@
private final ActivityStarter mActivityStarter;
private final Executor mExecutor;
private final Handler mHandler;
+ private final KeyguardStateController mKeyguardStateController;
private final Runnable mSelectionRunnable = this::selectCard;
private final SharedPreferences mPrefs;
private final WalletView mWalletView;
@@ -72,7 +75,6 @@
@VisibleForTesting String mSelectedCardId;
@VisibleForTesting boolean mIsDismissed;
- private boolean mIsDeviceLocked;
private boolean mHasRegisteredListener;
public WalletScreenController(
@@ -83,12 +85,13 @@
Executor executor,
Handler handler,
UserTracker userTracker,
- boolean isDeviceLocked) {
+ KeyguardStateController keyguardStateController) {
mContext = context;
mWalletClient = walletClient;
mActivityStarter = activityStarter;
mExecutor = executor;
mHandler = handler;
+ mKeyguardStateController = keyguardStateController;
mPrefs = userTracker.getUserContext().getSharedPreferences(TAG, Context.MODE_PRIVATE);
mWalletView = walletView;
mWalletView.setMinimumHeight(getExpectedMinHeight());
@@ -105,7 +108,6 @@
// to decrease perceived latency.
showEmptyStateView();
}
- mIsDeviceLocked = isDeviceLocked;
}
/**
@@ -122,11 +124,17 @@
for (WalletCard card : walletCards) {
data.add(new QAWalletCardViewInfo(mContext, card));
}
+
+ // Get on main thread for UI updates.
mHandler.post(() -> {
+ if (mIsDismissed) {
+ return;
+ }
if (data.isEmpty()) {
showEmptyStateView();
} else {
- mWalletView.showCardCarousel(data, response.getSelectedIndex(), mIsDeviceLocked);
+ mWalletView.showCardCarousel(
+ data, response.getSelectedIndex(), !mKeyguardStateController.isUnlocked());
}
// The empty state view will not be shown preemptively next time if cards were returned
mPrefs.edit().putBoolean(PREFS_HAS_CARDS, !data.isEmpty()).apply();
@@ -140,10 +148,10 @@
*/
@Override
public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
- if (mIsDismissed) {
- return;
- }
mHandler.post(() -> {
+ if (mIsDismissed) {
+ return;
+ }
mWalletView.showErrorMessage(error.getMessage());
});
}
@@ -170,6 +178,11 @@
}
@Override
+ public void onKeyguardFadingAwayChanged() {
+ queryWalletCards();
+ }
+
+ @Override
public void onCardSelected(@NonNull WalletCardViewInfo card) {
if (mIsDismissed) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index d2f0720..a379394 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -103,7 +103,9 @@
CharSequence centerCardText = centerCard.getLabel();
Drawable icon = centerCard.getIcon();
if (icon != null) {
- mIcon.setImageDrawable(resizeDrawable(getResources(), icon));
+ Drawable drawable = resizeDrawable(getResources(), icon);
+ drawable.setTint(mContext.getColor(R.color.GM2_blue_600));
+ mIcon.setImageDrawable(drawable);
mIcon.setVisibility(VISIBLE);
} else {
mIcon.setVisibility(INVISIBLE);
@@ -126,7 +128,6 @@
mCardCarouselContainer.setVisibility(VISIBLE);
mErrorView.setVisibility(GONE);
if (isDeviceLocked) {
- // TODO(b/182964813): Add click action to prompt device unlock.
mWalletButton.setText(R.string.wallet_button_label_device_locked);
} else {
mWalletButton.setText(R.string.wallet_button_label_device_unlocked);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 33b2d67..743dd46 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -157,11 +157,12 @@
@WMSingleton
@Provides
static PhonePipMenuController providesPipPhoneMenuController(Context context,
- PipMediaController pipMediaController, SystemWindows systemWindows,
+ PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+ SystemWindows systemWindows,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler) {
- return new PhonePipMenuController(context, pipMediaController, systemWindows,
- mainExecutor, mainHandler);
+ return new PhonePipMenuController(context, pipBoundsState, pipMediaController,
+ systemWindows, mainExecutor, mainHandler);
}
@WMSingleton
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 70a7b7a..0fcd79b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -18,26 +18,34 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.res.Resources;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.clock.ClockManager;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
@@ -50,6 +58,8 @@
import org.mockito.MockitoAnnotations;
import org.mockito.verification.VerificationMode;
+import java.util.concurrent.Executor;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@@ -78,6 +88,12 @@
ContentResolver mContentResolver;
@Mock
BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private PluginManager mPluginManager;
+ @Mock
+ private FeatureFlags mFeatureFlags;
+ @Mock
+ private Executor mExecutor;
private KeyguardClockSwitchController mController;
@@ -87,6 +103,8 @@
when(mView.findViewById(com.android.systemui.R.id.left_aligned_notification_icon_container))
.thenReturn(mNotificationIcons);
+ when(mView.getContext()).thenReturn(getContext());
+ when(mFeatureFlags.isSmartspaceEnabled()).thenReturn(true);
when(mView.isAttachedToWindow()).thenReturn(true);
when(mResources.getString(anyInt())).thenReturn("h:mm");
mController = new KeyguardClockSwitchController(
@@ -98,7 +116,10 @@
mKeyguardSliceViewController,
mNotificationIconAreaController,
mContentResolver,
- mBroadcastDispatcher);
+ mBroadcastDispatcher,
+ mPluginManager,
+ mFeatureFlags,
+ mExecutor);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
@@ -182,6 +203,45 @@
verify(mView).setClockPlugin(mClockPlugin, StatusBarState.SHADE);
}
+ @Test
+ public void testSmartspacePluginConnectedRemovesKeyguardStatusArea() {
+ mController.init();
+
+ View statusArea = mock(View.class);
+ when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(statusArea);
+
+ View nic = mock(View.class);
+ when(mView.findViewById(R.id.left_aligned_notification_icon_container)).thenReturn(nic);
+ when(nic.getLayoutParams()).thenReturn(mock(RelativeLayout.LayoutParams.class));
+
+ BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
+ TestView view = mock(TestView.class);
+ when(plugin.getView(any())).thenReturn(view);
+
+ mController.mPluginListener.onPluginConnected(plugin, mContext);
+ verify(statusArea).setVisibility(View.GONE);
+ }
+
+ @Test
+ public void testSmartspacePluginDisconnectedShowsKeyguardStatusArea() {
+ mController.init();
+
+ View statusArea = mock(View.class);
+ when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(statusArea);
+
+ View nic = mock(View.class);
+ when(mView.findViewById(R.id.left_aligned_notification_icon_container)).thenReturn(nic);
+ when(nic.getLayoutParams()).thenReturn(mock(RelativeLayout.LayoutParams.class));
+
+ BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
+ TestView view = mock(TestView.class);
+ when(plugin.getView(any())).thenReturn(view);
+
+ mController.mPluginListener.onPluginConnected(plugin, mContext);
+ mController.mPluginListener.onPluginDisconnected(plugin);
+ verify(statusArea).setVisibility(View.VISIBLE);
+ }
+
private void verifyAttachment(VerificationMode times) {
verify(mClockManager, times).addOnClockChangedListener(
any(ClockManager.ClockChangedListener.class));
@@ -191,4 +251,12 @@
any(ColorExtractor.OnColorsChangedListener.class));
verify(mView, times).updateColors(mGradientColors);
}
+
+ private static class TestView extends View implements BcSmartspaceDataPlugin.SmartspaceView {
+ TestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void registerDataProvider(BcSmartspaceDataPlugin plugin) { }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 9659610e..d3a2d2e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -303,6 +303,19 @@
}
@Test
+ public void performA11yActions_visible_notifyAccessibilityActionPerformed() {
+ final int displayId = mContext.getDisplayId();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN,
+ Float.NaN);
+ });
+
+ mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null);
+
+ verify(mWindowMagnifierCallback).onAccessibilityActionPerformed(eq(displayId));
+ }
+
+ @Test
public void onNavigationModeChanged_updateMirrorViewLayout() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index ad1ce76..7833114 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -118,6 +118,16 @@
}
@Test
+ public void onAccessibilityActionPerformed_enabled_notifyCallback() throws RemoteException {
+ mCommandQueue.requestWindowMagnificationConnection(true);
+ waitForIdleSync();
+
+ mWindowMagnification.onAccessibilityActionPerformed(Display.DEFAULT_DISPLAY);
+
+ verify(mConnectionCallback).onAccessibilityActionPerformed(eq(Display.DEFAULT_DISPLAY));
+ }
+
+ @Test
public void onConfigurationChanged_updateModeSwitches() {
final Configuration config = new Configuration();
config.densityDpi = Configuration.DENSITY_DPI_ANY;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 8252ff4..3f0831c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -49,6 +50,7 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
@@ -71,6 +73,7 @@
public class AppOpsControllerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
private static final String TEST_ATTRIBUTION_NAME = "attribution";
+ private static final String SYSTEM_PKG = "android";
private static final int TEST_UID = UserHandle.getUid(0, 0);
private static final int TEST_UID_OTHER = UserHandle.getUid(1, 0);
private static final int TEST_UID_NON_USER_SENSITIVE = UserHandle.getUid(2, 0);
@@ -84,8 +87,6 @@
@Mock
private DumpManager mDumpManager;
@Mock
- private PermissionFlagsCache mFlagsCache;
- @Mock
private PackageManager mPackageManager;
@Mock
private IndividualSensorPrivacyController mSensorPrivacyController;
@@ -101,22 +102,19 @@
private AppOpsControllerImpl mController;
private TestableLooper mTestableLooper;
+ private String mExemptedRolePkgName;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
+ mExemptedRolePkgName = getContext().getString(R.string.config_systemUiIntelligence);
getContext().addMockSystemService(AppOpsManager.class, mAppOpsManager);
// All permissions of TEST_UID and TEST_UID_OTHER are user sensitive. None of
// TEST_UID_NON_USER_SENSITIVE are user sensitive.
getContext().setMockPackageManager(mPackageManager);
- when(mFlagsCache.getPermissionFlags(anyString(), anyString(), eq(TEST_UID))).thenReturn(
- PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED);
- when(mFlagsCache.getPermissionFlags(anyString(), anyString(), eq(TEST_UID_OTHER)))
- .thenReturn(PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED);
- when(mFlagsCache.getPermissionFlags(anyString(), anyString(),
- eq(TEST_UID_NON_USER_SENSITIVE))).thenReturn(0);
doAnswer((invocation) -> mRecordingCallback = invocation.getArgument(0))
.when(mAudioManager).registerAudioRecordingCallback(any(), any());
@@ -135,7 +133,6 @@
mContext,
mTestableLooper.getLooper(),
mDumpManager,
- mFlagsCache,
mAudioManager,
mSensorPrivacyController,
mDispatcher,
@@ -242,18 +239,26 @@
}
@Test
- public void nonUserSensitiveOpsAreIgnored() {
+ public void systemAndExemptedRolesAreIgnored() {
+ assumeFalse(mExemptedRolePkgName == null || mExemptedRolePkgName.equals(""));
+
mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
- TEST_UID_NON_USER_SENSITIVE, TEST_PACKAGE_NAME, true);
+ TEST_UID_NON_USER_SENSITIVE, mExemptedRolePkgName, true);
+ assertEquals(0, mController.getActiveAppOpsForUser(
+ UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE)).size());
+ mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
+ TEST_UID_NON_USER_SENSITIVE, SYSTEM_PKG, true);
assertEquals(0, mController.getActiveAppOpsForUser(
UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE)).size());
}
@Test
- public void nonUserSensitiveOpsNotNotified() {
+ public void exemptedRoleNotNotified() {
+ assumeFalse(mExemptedRolePkgName == null || mExemptedRolePkgName.equals(""));
+
mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
- TEST_UID_NON_USER_SENSITIVE, TEST_PACKAGE_NAME, true);
+ TEST_UID_NON_USER_SENSITIVE, mExemptedRolePkgName, true);
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/PermissionFlagsCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/appops/PermissionFlagsCacheTest.kt
deleted file mode 100644
index 0fb0ce0..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/PermissionFlagsCacheTest.kt
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2020 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.appops
-
-import android.content.pm.PackageManager
-import android.os.UserHandle
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotEquals
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyString
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.Mockito.never
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class PermissionFlagsCacheTest : SysuiTestCase() {
-
- companion object {
- const val TEST_PERMISSION = "test_permission"
- const val TEST_PACKAGE = "test_package"
- const val TEST_UID1 = 1000
- const val TEST_UID2 = UserHandle.PER_USER_RANGE + 1000
- }
-
- @Mock
- private lateinit var packageManager: PackageManager
-
- private lateinit var executor: FakeExecutor
- private lateinit var flagsCache: PermissionFlagsCache
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
-
- executor = FakeExecutor(FakeSystemClock())
-
- flagsCache = PermissionFlagsCache(packageManager, executor)
- executor.runAllReady()
- }
-
- @Test
- fun testNotListeningByDefault() {
- verify(packageManager, never()).addOnPermissionsChangeListener(any())
- }
-
- @Test
- fun testGetCorrectFlags() {
- `when`(packageManager.getPermissionFlags(anyString(), anyString(), any())).thenReturn(0)
- `when`(packageManager.getPermissionFlags(
- TEST_PERMISSION,
- TEST_PACKAGE,
- UserHandle.getUserHandleForUid(TEST_UID1))
- ).thenReturn(1)
-
- assertEquals(1, flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1))
- assertNotEquals(1, flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID2))
- }
-
- @Test
- fun testFlagIsCached() {
- flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1)
-
- flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1)
-
- verify(packageManager, times(1)).getPermissionFlags(
- TEST_PERMISSION,
- TEST_PACKAGE,
- UserHandle.getUserHandleForUid(TEST_UID1)
- )
- }
-
- @Test
- fun testListeningAfterFirstRequest() {
- flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1)
-
- verify(packageManager).addOnPermissionsChangeListener(any())
- }
-
- @Test
- fun testListeningOnlyOnce() {
- flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1)
-
- flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID2)
-
- verify(packageManager, times(1)).addOnPermissionsChangeListener(any())
- }
-
- @Test
- fun testUpdateFlag() {
- assertEquals(0, flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1))
-
- `when`(packageManager.getPermissionFlags(
- TEST_PERMISSION,
- TEST_PACKAGE,
- UserHandle.getUserHandleForUid(TEST_UID1))
- ).thenReturn(1)
-
- flagsCache.onPermissionsChanged(TEST_UID1)
-
- executor.runAllReady()
-
- assertEquals(1, flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1))
- }
-
- @Test
- fun testUpdateFlag_notUpdatedIfUidHasNotBeenRequestedBefore() {
- flagsCache.getPermissionFlags(TEST_PERMISSION, TEST_PACKAGE, TEST_UID1)
-
- flagsCache.onPermissionsChanged(TEST_UID2)
-
- executor.runAllReady()
-
- verify(packageManager, never()).getPermissionFlags(
- TEST_PERMISSION,
- TEST_PACKAGE,
- UserHandle.getUserHandleForUid(TEST_UID2)
- )
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 02ba304..d395075 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -16,14 +16,14 @@
package com.android.systemui.biometrics
+import android.graphics.PointF
import android.hardware.biometrics.BiometricSourceType
import android.testing.AndroidTestingRunner
-import android.view.View
-import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.ConfigurationController
import org.junit.Before
@@ -32,6 +32,8 @@
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -41,38 +43,50 @@
@RunWith(AndroidTestingRunner::class)
class AuthRippleControllerTest : SysuiTestCase() {
private lateinit var controller: AuthRippleController
+ @Mock private lateinit var rippleView: AuthRippleView
@Mock private lateinit var commandRegistry: CommandRegistry
@Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock private lateinit var rippleView: AuthRippleView
- @Mock private lateinit var viewHost: ViewGroup
+ @Mock private lateinit var authController: AuthController
+ @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@Before
-
fun setUp() {
MockitoAnnotations.initMocks(this)
controller = AuthRippleController(
- commandRegistry, configurationController, context, keyguardUpdateMonitor)
- controller.rippleView = rippleView // Replace the real ripple view with a mock instance
- controller.setViewHost(viewHost)
+ context,
+ authController,
+ configurationController,
+ keyguardUpdateMonitor,
+ commandRegistry,
+ notificationShadeWindowController,
+ rippleView
+ )
+ controller.init()
}
@Test
- fun testAddRippleView() {
- val listenerCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
- verify(viewHost).addOnAttachStateChangeListener(listenerCaptor.capture())
+ fun testFingerprintTriggerRipple() {
+ val fpsLocation = PointF(5f, 5f)
+ `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
+ controller.onViewAttached()
- // Fake attach to window
- listenerCaptor.value.onViewAttachedToWindow(viewHost)
- verify(viewHost).addView(rippleView)
+ val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+ verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+
+ captor.value.onBiometricAuthenticated(
+ 0 /* userId */,
+ BiometricSourceType.FINGERPRINT /* type */,
+ false /* isStrongBiometric */)
+ verify(rippleView).setSensorLocation(fpsLocation)
+ verify(rippleView).startRipple(any())
}
@Test
- fun testTriggerRipple() {
- // Fake attach to window
- val listenerCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
- verify(viewHost).addOnAttachStateChangeListener(listenerCaptor.capture())
- listenerCaptor.value.onViewAttachedToWindow(viewHost)
+ fun testFaceTriggerRipple() {
+ val faceLocation = PointF(5f, 5f)
+ `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation)
+ controller.onViewAttached()
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
@@ -81,17 +95,43 @@
0 /* userId */,
BiometricSourceType.FACE /* type */,
false /* isStrongBiometric */)
- verify(rippleView, never()).startRipple()
+ verify(rippleView).setSensorLocation(faceLocation)
+ verify(rippleView).startRipple(any())
+ }
+
+ @Test
+ fun testNullFaceSensorLocationDoesNothing() {
+ `when`(authController.faceAuthSensorLocation).thenReturn(null)
+ controller.onViewAttached()
+
+ val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+ verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+
+ captor.value.onBiometricAuthenticated(
+ 0 /* userId */,
+ BiometricSourceType.FACE /* type */,
+ false /* isStrongBiometric */)
+ verify(rippleView, never()).startRipple(any())
+ }
+
+ @Test
+ fun testNullFingerprintSensorLocationDoesNothing() {
+ `when`(authController.udfpsSensorLocation).thenReturn(null)
+ controller.onViewAttached()
+
+ val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+ verify(keyguardUpdateMonitor).registerCallback(captor.capture())
captor.value.onBiometricAuthenticated(
0 /* userId */,
BiometricSourceType.FINGERPRINT /* type */,
false /* isStrongBiometric */)
- verify(rippleView).startRipple()
+ verify(rippleView, never()).startRipple(any())
}
@Test
fun testUpdateRippleColor() {
+ controller.onViewAttached()
val captor = ArgumentCaptor
.forClass(ConfigurationController.ConfigurationListener::class.java)
verify(configurationController).addCallback(captor.capture())
@@ -104,10 +144,4 @@
captor.value.onUiModeChanged()
verify(rippleView).setColor(ArgumentMatchers.anyInt())
}
-
- @Test
- fun testForwardsSensorLocation() {
- controller.setSensorLocation(5f, 5f)
- verify(rippleView).setSensorLocation(5f, 5f)
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 9504970..bbd3ce8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -48,6 +48,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -100,13 +101,13 @@
@Mock
private DumpManager mDumpManager;
@Mock
- private AuthRippleController mAuthRippleController;
- @Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private KeyguardViewMediator mKeyguardViewMediator;
@Mock
private IUdfpsOverlayControllerCallback mUdfpsOverlayControllerCallback;
+ @Mock
+ private FalsingManager mFalsingManager;
private FakeExecutor mFgExecutor;
@@ -157,9 +158,9 @@
mStatusBar,
mStatusBarKeyguardViewManager,
mDumpManager,
- mAuthRippleController,
mKeyguardUpdateMonitor,
- mKeyguardViewMediator);
+ mKeyguardViewMediator,
+ mFalsingManager);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index 923cae8..a7f9fe4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -16,6 +16,9 @@
package com.android.systemui.classifier;
+import static com.android.systemui.plugins.FalsingManager.HIGH_PENALTY;
+import static com.android.systemui.plugins.FalsingManager.NO_PENALTY;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -55,8 +58,6 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class BrightLineClassifierTest extends SysuiTestCase {
- private static final long DOUBLE_TAP_TIMEOUT_MS = 1000;
-
private BrightLineFalsingManager mBrightLineFalsingManager;
@Mock
private FalsingDataProvider mFalsingDataProvider;
@@ -91,7 +92,7 @@
.thenReturn(mPassedResult);
when(mClassifierB.classifyGesture(anyInt(), anyDouble(), anyDouble()))
.thenReturn(mPassedResult);
- when(mSingleTapClassfier.isTap(any(List.class))).thenReturn(mPassedResult);
+ when(mSingleTapClassfier.isTap(any(List.class), anyDouble())).thenReturn(mPassedResult);
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
.thenReturn(mPassedResult);
mClassifiers.add(mClassifierA);
@@ -170,13 +171,13 @@
@Test
public void testIsFalseTap_BasicCheck() {
- when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mFalsedResult);
+ when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mFalsedResult);
- assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isTrue();
+ assertThat(mBrightLineFalsingManager.isSimpleTap()).isFalse();
- when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
+ when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult);
- assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isFalse();
+ assertThat(mBrightLineFalsingManager.isSimpleTap()).isTrue();
}
@Test
@@ -185,26 +186,26 @@
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(new ArrayList<>());
when(mFalsingDataProvider.getPriorMotionEvents()).thenReturn(mMotionEventList);
- mBrightLineFalsingManager.isFalseTap(false, 0);
- verify(mSingleTapClassfier).isTap(mMotionEventList);
+ mBrightLineFalsingManager.isFalseTap(0);
+ verify(mSingleTapClassfier).isTap(mMotionEventList, 0);
}
@Test
public void testIsFalseTap_RobustCheck_NoFaceAuth() {
- when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
+ when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult);
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
.thenReturn(mFalsedResult);
when(mHistoryTracker.falseBelief()).thenReturn(1.0);
mFalsingDataProvider.setJustUnlockedWithFace(false);
- assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isTrue();
+ assertThat(mBrightLineFalsingManager.isFalseTap(NO_PENALTY)).isTrue();
}
@Test
public void testIsFalseTap_RobustCheck_FaceAuth() {
- when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
+ when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult);
when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
- assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isFalse();
+ assertThat(mBrightLineFalsingManager.isFalseTap(NO_PENALTY)).isFalse();
}
@Test
@@ -230,7 +231,7 @@
@Test
public void testHistory_singleTap() {
// When trying to classify single taps, we don't immediately add results to history.
- mBrightLineFalsingManager.isFalseTap(false, 0);
+ mBrightLineFalsingManager.isFalseTap(HIGH_PENALTY);
mGestureFinalizedListener.onGestureFinalized(1000);
verify(mHistoryTracker).addResults(anyCollection(), eq(1000L));
}
@@ -238,9 +239,9 @@
@Test
public void testHistory_multipleSingleTaps() {
// When trying to classify single taps, we don't immediately add results to history.
- mBrightLineFalsingManager.isFalseTap(false, 0);
+ mBrightLineFalsingManager.isFalseTap(HIGH_PENALTY);
mGestureFinalizedListener.onGestureFinalized(1000);
- mBrightLineFalsingManager.isFalseTap(false, 0);
+ mBrightLineFalsingManager.isFalseTap(HIGH_PENALTY);
mGestureFinalizedListener.onGestureFinalized(2000);
verify(mHistoryTracker).addResults(anyCollection(), eq(1000L));
verify(mHistoryTracker).addResults(anyCollection(), eq(2000L));
@@ -249,10 +250,10 @@
@Test
public void testHistory_doubleTap() {
// When trying to classify single taps, we don't immediately add results to history.
- mBrightLineFalsingManager.isFalseTap(false, 0);
+ mBrightLineFalsingManager.isFalseTap(HIGH_PENALTY);
mGestureFinalizedListener.onGestureFinalized(1000);
// Before checking for double tap, we may check for single-tap on the second gesture.
- mBrightLineFalsingManager.isFalseTap(false, 0);
+ mBrightLineFalsingManager.isFalseTap(HIGH_PENALTY);
mBrightLineFalsingManager.isFalseDoubleTap();
mGestureFinalizedListener.onGestureFinalized(2000);
@@ -270,8 +271,8 @@
.thenReturn(mFalsedResult);
assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
- when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mFalsedResult);
- assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isFalse();
+ when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mFalsedResult);
+ assertThat(mBrightLineFalsingManager.isSimpleTap()).isFalse();
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
.thenReturn(mFalsedResult);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
index f726cbe..2ceee6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.when;
@@ -78,7 +79,7 @@
@Test
public void testSingleTap() {
- when(mSingleTapClassifier.isTap(anyList())).thenReturn(mFalsedResult);
+ when(mSingleTapClassifier.isTap(anyList(), anyDouble())).thenReturn(mFalsedResult);
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
addMotionEvent(0, 1, MotionEvent.ACTION_UP, TOUCH_SLOP, 1);
@@ -88,7 +89,7 @@
@Test
public void testDoubleTap() {
- when(mSingleTapClassifier.isTap(anyList())).thenReturn(mPassedResult);
+ when(mSingleTapClassifier.isTap(anyList(), anyDouble())).thenReturn(mPassedResult);
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
@@ -104,7 +105,8 @@
@Test
public void testBadFirstTap() {
- when(mSingleTapClassifier.isTap(anyList())).thenReturn(mPassedResult, mFalsedResult);
+ when(mSingleTapClassifier.isTap(anyList(), anyDouble()))
+ .thenReturn(mPassedResult, mFalsedResult);
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
@@ -120,7 +122,8 @@
@Test
public void testBadSecondTap() {
- when(mSingleTapClassifier.isTap(anyList())).thenReturn(mFalsedResult, mPassedResult);
+ when(mSingleTapClassifier.isTap(anyList(), anyDouble()))
+ .thenReturn(mFalsedResult, mPassedResult);
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
@@ -136,7 +139,7 @@
@Test
public void testBadTouchSlop() {
- when(mSingleTapClassifier.isTap(anyList())).thenReturn(mFalsedResult);
+ when(mSingleTapClassifier.isTap(anyList(), anyDouble())).thenReturn(mFalsedResult);
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
@@ -152,7 +155,7 @@
@Test
public void testBadTouchSlow() {
- when(mSingleTapClassifier.isTap(anyList())).thenReturn(mFalsedResult);
+ when(mSingleTapClassifier.isTap(anyList(), anyDouble())).thenReturn(mFalsedResult);
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
index 1524107..e3c800e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
@@ -142,12 +142,12 @@
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
- assertThat(mClassifier.isTap(mMotionEvents).isFalse()).isFalse();
+ assertThat(mClassifier.isTap(mMotionEvents, 0.5).isFalse()).isFalse();
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, TOUCH_SLOP + 1);
- assertThat(mClassifier.isTap(mMotionEvents).isFalse()).isTrue();
+ assertThat(mClassifier.isTap(mMotionEvents, 0.5).isFalse()).isTrue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
index 8db0f33..107ac83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
@@ -162,6 +162,9 @@
assertEquals(View.GONE, smallResult.findViewById(R.id.predefined_icon).getVisibility());
// Shows person icon.
assertEquals(View.VISIBLE, smallResult.findViewById(R.id.person_icon).getVisibility());
+ // No messages count.
+ assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
+
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_width_for_large));
@@ -220,6 +223,8 @@
// Has person icon.
assertEquals(View.VISIBLE,
smallResult.findViewById(R.id.person_icon).getVisibility());
+ // No messages count.
+ assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_width_for_large));
@@ -281,6 +286,8 @@
// Has person icon.
assertEquals(View.VISIBLE,
smallResult.findViewById(R.id.person_icon).getVisibility());
+ // No messages count.
+ assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_width_for_large));
@@ -342,6 +349,8 @@
// Has person icon.
assertEquals(View.VISIBLE,
smallResult.findViewById(R.id.person_icon).getVisibility());
+ // No messages count.
+ assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_width_for_large));
@@ -404,6 +413,8 @@
smallResult.findViewById(R.id.predefined_icon).getVisibility());
// Has person icon.
assertEquals(View.VISIBLE, smallResult.findViewById(R.id.person_icon).getVisibility());
+ // No messages count.
+ assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_width_for_large));
@@ -471,7 +482,7 @@
smallResult.findViewById(R.id.person_icon).getVisibility());
// Has a single message, no count shown.
- assertEquals(View.GONE, result.findViewById(R.id.messages_count).getVisibility());
+ assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_width_for_large));
@@ -497,7 +508,7 @@
assertThat(statusContent.getMaxLines()).isEqualTo(3);
// Has a single message, no count shown.
- assertEquals(View.GONE, result.findViewById(R.id.messages_count).getVisibility());
+ assertEquals(View.GONE, largeResult.findViewById(R.id.messages_count).getVisibility());
}
@@ -544,7 +555,7 @@
smallResult.findViewById(R.id.person_icon).getVisibility());
// Has two messages, show count.
- assertEquals(View.VISIBLE, result.findViewById(R.id.messages_count).getVisibility());
+ assertEquals(View.VISIBLE, smallResult.findViewById(R.id.messages_count).getVisibility());
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_width_for_large));
@@ -570,7 +581,7 @@
assertThat(statusContent.getMaxLines()).isEqualTo(3);
// Has two messages, show count.
- assertEquals(View.VISIBLE, result.findViewById(R.id.messages_count).getVisibility());
+ assertEquals(View.VISIBLE, largeResult.findViewById(R.id.messages_count).getVisibility());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/plugins/animation/ActivityLaunchAnimatorTest.kt
new file mode 100644
index 0000000..722b0b1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/animation/ActivityLaunchAnimatorTest.kt
@@ -0,0 +1,188 @@
+package com.android.systemui.plugins.animation
+
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import android.graphics.Point
+import android.graphics.Rect
+import android.os.Looper
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.IRemoteAnimationFinishedCallback
+import android.view.RemoteAnimationAdapter
+import android.view.RemoteAnimationTarget
+import android.view.SurfaceControl
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertNotNull
+import junit.framework.Assert.assertNull
+import junit.framework.Assert.assertTrue
+import junit.framework.AssertionFailedError
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Spy
+import org.mockito.junit.MockitoJUnit
+import kotlin.concurrent.thread
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class ActivityLaunchAnimatorTest : SysuiTestCase() {
+ private val activityLaunchAnimator = ActivityLaunchAnimator()
+ private val rootView = View(mContext)
+ @Spy private val controller = TestLaunchAnimatorController(rootView)
+ @Mock lateinit var iCallback: IRemoteAnimationFinishedCallback
+
+ @get:Rule val rule = MockitoJUnit.rule()
+
+ private fun startIntentWithAnimation(
+ controller: ActivityLaunchAnimator.Controller? = this.controller,
+ intentStarter: (RemoteAnimationAdapter?) -> Int
+ ) {
+ // We start in a new thread so that we can ensure that the callbacks are called in the main
+ // thread.
+ thread {
+ activityLaunchAnimator.startIntentWithAnimation(controller, intentStarter)
+ }.join()
+ }
+
+ @Test
+ fun animationAdapterIsNullIfControllerIsNull() {
+ var startedIntent = false
+ var animationAdapter: RemoteAnimationAdapter? = null
+
+ startIntentWithAnimation(controller = null) { adapter ->
+ startedIntent = true
+ animationAdapter = adapter
+
+ ActivityManager.START_SUCCESS
+ }
+
+ assertTrue(startedIntent)
+ assertNull(animationAdapter)
+ }
+
+ @Test
+ fun animatesIfActivityOpens() {
+ val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java)
+ var animationAdapter: RemoteAnimationAdapter? = null
+ startIntentWithAnimation { adapter ->
+ animationAdapter = adapter
+ ActivityManager.START_SUCCESS
+ }
+
+ assertNotNull(animationAdapter)
+ waitForIdleSync()
+ verify(controller).onIntentStarted(willAnimateCaptor.capture())
+ assertTrue(willAnimateCaptor.value)
+ }
+
+ @Test
+ fun doesNotAnimateIfActivityIsAlreadyOpen() {
+ val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java)
+ startIntentWithAnimation { ActivityManager.START_DELIVERED_TO_TOP }
+
+ waitForIdleSync()
+ verify(controller).onIntentStarted(willAnimateCaptor.capture())
+ assertFalse(willAnimateCaptor.value)
+ }
+
+ @Test
+ fun doesNotStartIfAnimationIsCancelled() {
+ val runner = ActivityLaunchAnimator.Runner(controller)
+ runner.onAnimationCancelled()
+ runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
+
+ waitForIdleSync()
+ verify(controller).onLaunchAnimationCancelled()
+ verify(controller, never()).onLaunchAnimationStart(anyBoolean())
+ }
+
+ @Test
+ fun abortsIfNoOpeningWindowIsFound() {
+ val runner = ActivityLaunchAnimator.Runner(controller)
+ runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
+
+ waitForIdleSync()
+ verify(controller).onLaunchAnimationAborted()
+ verify(controller, never()).onLaunchAnimationStart(anyBoolean())
+ }
+
+ @Test
+ fun startsAnimationIfWindowIsOpening() {
+ val runner = ActivityLaunchAnimator.Runner(controller)
+ runner.onAnimationStart(0, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback)
+ waitForIdleSync()
+ verify(controller).onLaunchAnimationStart(anyBoolean())
+ }
+
+ private fun fakeWindow() = RemoteAnimationTarget(
+ 0, RemoteAnimationTarget.MODE_OPENING, SurfaceControl(), false, Rect(), Rect(), 0,
+ Point(), Rect(), Rect(), WindowConfiguration(), false, SurfaceControl(), Rect(),
+ ActivityManager.RunningTaskInfo()
+ )
+}
+
+/**
+ * A simple implementation of [ActivityLaunchAnimator.Controller] which throws if it is called
+ * outside of the main thread.
+ */
+private class TestLaunchAnimatorController(
+ private val rootView: View
+) : ActivityLaunchAnimator.Controller {
+ override fun getRootView(): View = rootView
+
+ override fun createAnimatorState() = ActivityLaunchAnimator.State(
+ top = 100,
+ bottom = 200,
+ left = 300,
+ right = 400,
+ topCornerRadius = 10f,
+ bottomCornerRadius = 20f
+ )
+
+ private fun assertOnMainThread() {
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ throw AssertionFailedError("Called outside of main thread.")
+ }
+ }
+
+ override fun onIntentStarted(willAnimate: Boolean) {
+ assertOnMainThread()
+ }
+
+ override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
+ assertOnMainThread()
+ }
+
+ override fun onLaunchAnimationProgress(
+ state: ActivityLaunchAnimator.State,
+ progress: Float,
+ linearProgress: Float
+ ) {
+ assertOnMainThread()
+ }
+
+ override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
+ assertOnMainThread()
+ }
+
+ override fun onLaunchAnimationCancelled() {
+ assertOnMainThread()
+ }
+
+ override fun onLaunchAnimationTimedOut() {
+ assertOnMainThread()
+ }
+
+ override fun onLaunchAnimationAborted() {
+ assertOnMainThread()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 650ee50..21fec91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -38,6 +38,7 @@
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.globalactions.GlobalActionsDialogLite;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
@@ -121,7 +122,7 @@
mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
new QSDetailDisplayer(), mQuickQSPanelController, mFakeTunerService,
- mMetricsLogger, false, mGlobalActionsDialog);
+ mMetricsLogger, new FalsingManagerFake(), false, mGlobalActionsDialog);
mController.init();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index f2f9656b..c35f8b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -34,6 +34,7 @@
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -46,6 +47,7 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.FeatureFlagUtils;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -418,7 +420,7 @@
public void secondaryClick() {}
@Override
- public void longClick() {}
+ public void longClick(@Nullable View view) {}
@Override
public void userSwitch(int currentUser) {}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 937ab1c..2d6ed7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -150,12 +150,12 @@
@Test
public void testClick_falsing() {
- mFalsingManager.setFalseRobustTap(true);
+ mFalsingManager.setFalseTap(true);
mTile.click();
mTestableLooper.processAllMessages();
assertThat(mTile.mClicked).isFalse();
- mFalsingManager.setFalseRobustTap(false);
+ mFalsingManager.setFalseTap(false);
mTile.click();
mTestableLooper.processAllMessages();
assertThat(mTile.mClicked).isTrue();
@@ -189,7 +189,7 @@
@Test
public void testLongClick_Metrics() {
- mTile.longClick();
+ mTile.longClick(null /* view */);
verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_LONG_PRESS)));
assertEquals(1, mUiEventLoggerFake.numLogs());
UiEventLoggerFake.FakeUiEvent event = mUiEventLoggerFake.get(0);
@@ -201,7 +201,7 @@
public void testLongClick_log() {
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
- mTile.longClick();
+ mTile.longClick(null /* view */);
verify(mQsLogger).logTileLongClick(SPEC, StatusBarState.SHADE, Tile.STATE_ACTIVE);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index f57283f..613f879 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -30,6 +30,8 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -117,10 +119,13 @@
@Mock
private FeatureFlags mFeatureFlags;
@Captor
+ ArgumentCaptor<Intent> mIntentCaptor;
+ @Captor
ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
@Captor
ArgumentCaptor<QuickAccessWalletClient.OnWalletCardsRetrievedCallback> mCallbackCaptor;
+ private Context mSpiedContext;
private TestableLooper mTestableLooper;
private QuickAccessWalletTile mTile;
@@ -129,8 +134,10 @@
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
+ mSpiedContext = spy(mContext);
- when(mHost.getContext()).thenReturn(mContext);
+ doNothing().when(mSpiedContext).startActivity(any(Intent.class));
+ when(mHost.getContext()).thenReturn(mSpiedContext);
when(mHost.getUiEventLogger()).thenReturn(mUiEventLogger);
when(mFeatureFlags.isQuickAccessWalletEnabled()).thenReturn(true);
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
@@ -179,16 +186,46 @@
}
@Test
- public void testHandleClick_openGPay() {
+ public void testHandleClick_noCards_hasIntent_openWalletApp() {
Intent intent = new Intent("WalletIntent");
when(mQuickAccessWalletClient.createWalletIntent()).thenReturn(intent);
+ setUpWalletCard(/* hasCard= */ false);
+
mTile.handleClick();
+ mTestableLooper.processAllMessages();
verify(mActivityStarter, times(1))
.postStartActivityDismissingKeyguard(eq(intent), anyInt());
}
@Test
+ public void testHandleClick_noCards_noIntent_doNothing() {
+ when(mQuickAccessWalletClient.createWalletIntent()).thenReturn(null);
+ setUpWalletCard(/* hasCard= */ false);
+
+ mTile.handleClick();
+ mTestableLooper.processAllMessages();
+
+ verifyZeroInteractions(mActivityStarter);
+ }
+
+ @Test
+ public void testHandleClick_hasCards_startWalletActivity() {
+ setUpWalletCard(/* hasCard= */ true);
+
+ mTile.handleClick();
+ mTestableLooper.processAllMessages();
+
+ verify(mSpiedContext).startActivity(mIntentCaptor.capture());
+
+ Intent nextStartedIntent = mIntentCaptor.getValue();
+ String walletClassName = "com.android.systemui.wallet.ui.WalletActivity";
+
+ assertNotNull(nextStartedIntent);
+ assertThat(nextStartedIntent.getComponent().getClassName()).isEqualTo(walletClassName);
+ }
+
+ @Test
public void testHandleUpdateState_updateLabelAndIcon() {
QSTile.State state = new QSTile.State();
QSTile.Icon icon = QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_wallet);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index eaef43d..35c92b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -108,6 +108,7 @@
when(mController.isRemoteInputActive(mEntry)).thenReturn(true);
mRemoteInputManager.onPerformRemoveNotification(mEntry, mEntry.getKey());
+ assertFalse(mEntry.mRemoteEditImeVisible);
verify(mController).removeRemoteInput(mEntry, null);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index e65db5e..45a7d0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -27,7 +27,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator
+import com.android.systemui.statusbar.notification.ExpandAnimationParameters
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -174,6 +174,13 @@
}
@Test
+ fun setQsPanelExpansion_appliesBlur() {
+ notificationShadeDepthController.qsPanelExpansion = 1f
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(blurUtils).applyBlur(any(), eq(maxBlur))
+ }
+
+ @Test
fun updateGlobalDialogVisibility_animatesBlur() {
notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root)
verify(globalActionsSpring).animateTo(eq(maxBlur / 2), eq(root))
@@ -215,7 +222,7 @@
fun updateBlurCallback_appLaunchAnimation_overridesZoom() {
`when`(shadeSpring.radius).thenReturn(maxBlur)
`when`(shadeAnimation.radius).thenReturn(maxBlur)
- val animProgress = ActivityLaunchAnimator.ExpandAnimationParameters()
+ val animProgress = ExpandAnimationParameters()
animProgress.linearProgress = 1f
notificationShadeDepthController.notificationLaunchAnimationParams = animProgress
notificationShadeDepthController.updateBlurCallback.doFrame(0)
@@ -264,7 +271,7 @@
@Test
fun setNotificationLaunchAnimationParams_schedulesFrame() {
- val animProgress = ActivityLaunchAnimator.ExpandAnimationParameters()
+ val animProgress = ExpandAnimationParameters()
animProgress.linearProgress = 0.5f
notificationShadeDepthController.notificationLaunchAnimationParams = animProgress
verify(choreographer).postFrameCallback(
@@ -273,7 +280,7 @@
@Test
fun setNotificationLaunchAnimationParams_whennNull_ignoresIfShadeHasNoBlur() {
- val animProgress = ActivityLaunchAnimator.ExpandAnimationParameters()
+ val animProgress = ExpandAnimationParameters()
animProgress.linearProgress = 0.5f
`when`(shadeSpring.radius).thenReturn(0)
`when`(shadeAnimation.radius).thenReturn(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
index 9ce7241..5e783a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
@@ -16,17 +16,17 @@
package com.android.systemui.statusbar.charging
+import android.content.Context
import android.testing.AndroidTestingRunner
import android.view.View
-import android.view.ViewGroupOverlay
-import android.view.ViewRootImpl
+import android.view.WindowManager
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.capture
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -34,7 +34,8 @@
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito.`when`
-import org.mockito.Mockito.never
+import org.mockito.Mockito.any
+import org.mockito.Mockito.eq
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -47,55 +48,45 @@
@Mock private lateinit var batteryController: BatteryController
@Mock private lateinit var featureFlags: FeatureFlags
@Mock private lateinit var configurationController: ConfigurationController
- @Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var rippleView: ChargingRippleView
- @Mock private lateinit var viewHost: View
- @Mock private lateinit var viewHostRootImpl: ViewRootImpl
- @Mock private lateinit var viewGroupOverlay: ViewGroupOverlay
+ @Mock private lateinit var windowManager: WindowManager
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- `when`(viewHost.viewRootImpl).thenReturn(viewHostRootImpl)
- `when`(viewHostRootImpl.view).thenReturn(viewHost)
- `when`(viewHost.overlay).thenReturn(viewGroupOverlay)
`when`(featureFlags.isChargingRippleEnabled).thenReturn(true)
- `when`(keyguardStateController.isShowing).thenReturn(true)
controller = WiredChargingRippleController(
commandRegistry, batteryController, configurationController,
- featureFlags, context, keyguardStateController)
+ featureFlags, context)
controller.rippleView = rippleView // Replace the real ripple view with a mock instance
- controller.setViewHost(viewHost)
+ context.addMockSystemService(Context.WINDOW_SERVICE, windowManager)
}
@Test
- fun testSetRippleViewAsOverlay() {
- val listenerCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
- verify(viewHost).addOnAttachStateChangeListener(listenerCaptor.capture())
-
- // Fake attach to window
- listenerCaptor.value.onViewAttachedToWindow(viewHost)
- verify(viewGroupOverlay).add(rippleView)
- }
-
- @Test
- fun testTriggerRipple() {
+ fun testTriggerRipple_UnlockedState() {
val captor = ArgumentCaptor
.forClass(BatteryController.BatteryStateChangeCallback::class.java)
verify(batteryController).addCallback(captor.capture())
- val unusedBatteryLevel = 0
+ // Verify ripple added to window manager.
captor.value.onBatteryLevelChanged(
- unusedBatteryLevel,
- false /* plugged in */,
- false /* charging */)
- verify(rippleView, never()).startRipple()
-
- captor.value.onBatteryLevelChanged(
- unusedBatteryLevel,
+ 0 /* unusedBatteryLevel */,
false /* plugged in */,
true /* charging */)
- verify(rippleView).startRipple()
+ val attachListenerCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
+ verify(rippleView).addOnAttachStateChangeListener(attachListenerCaptor.capture())
+ verify(windowManager).addView(eq(rippleView), any<WindowManager.LayoutParams>())
+
+ // Verify ripple started
+ val runnableCaptor =
+ ArgumentCaptor.forClass(Runnable::class.java)
+ attachListenerCaptor.value.onViewAttachedToWindow(rippleView)
+ verify(rippleView).startRipple(runnableCaptor.capture())
+
+ // Verify ripple removed
+ runnableCaptor.value.run()
+ verify(windowManager).removeView(rippleView)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java
deleted file mode 100644
index 2fa6cf0..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2018 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.statusbar.notification;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.RemoteAnimationAdapter;
-import android.view.View;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.phone.NotificationPanelViewController;
-import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
-import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class ActivityLaunchAnimatorTest extends SysuiTestCase {
-
- private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
- private ActivityLaunchAnimator mLaunchAnimator;
- @Mock
- private ActivityLaunchAnimator.Callback mCallback;
- @Mock
- private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
- @Mock
- private NotificationShadeWindowView mNotificationShadeWindowView;
- @Mock
- private NotificationListContainer mNotificationContainer;
- @Mock
- private ExpandableNotificationRow mRow;
- @Mock
- private NotificationShadeDepthController mNotificationShadeDepthController;
- @Mock
- private NotificationPanelViewController mNotificationPanelViewController;
- @Rule
- public MockitoRule rule = MockitoJUnit.rule();
-
- @Before
- public void setUp() throws Exception {
- when(mNotificationShadeWindowViewController.getView())
- .thenReturn(mNotificationShadeWindowView);
- when(mNotificationShadeWindowView.getResources()).thenReturn(mContext.getResources());
- when(mCallback.areLaunchAnimationsEnabled()).thenReturn(true);
- mLaunchAnimator = new ActivityLaunchAnimator(
- mNotificationShadeWindowViewController,
- mCallback,
- mNotificationPanelViewController,
- mNotificationShadeDepthController,
- mNotificationContainer,
- mExecutor);
- }
-
- @Test
- public void testReturnsNullIfNotEnabled() {
- when(mCallback.areLaunchAnimationsEnabled()).thenReturn(false);
- RemoteAnimationAdapter launchAnimation = mLaunchAnimator.getLaunchAnimation(mRow,
- false /* occluded */);
- Assert.assertTrue("The LaunchAnimator generated an animation even though animations are "
- + "disabled", launchAnimation == null);
- }
-
- @Test
- public void testNotWorkingWhenOccluded() {
- when(mCallback.areLaunchAnimationsEnabled()).thenReturn(false);
- RemoteAnimationAdapter launchAnimation = mLaunchAnimator.getLaunchAnimation(mRow,
- true /* occluded */);
- Assert.assertTrue("The LaunchAnimator generated an animation even though we're occluded",
- launchAnimation == null);
- }
-
- @Test
- public void testTimeoutCalled() {
- RemoteAnimationAdapter launchAnimation = mLaunchAnimator.getLaunchAnimation(mRow,
- false /* occluded */);
- Assert.assertTrue("No animation generated", launchAnimation != null);
- executePostsImmediately(mNotificationShadeWindowView);
- mLaunchAnimator.setLaunchResult(ActivityManager.START_SUCCESS,
- true /* wasIntentActivity */);
- verify(mCallback).onExpandAnimationTimedOut();
- }
-
- private void executePostsImmediately(View view) {
- doAnswer((i) -> {
- Runnable run = i.getArgument(0);
- run.run();
- return null;
- }).when(view).post(any());
- doAnswer((i) -> {
- Runnable run = i.getArgument(0);
- run.run();
- return null;
- }).when(view).postDelayed(any(), anyLong());
- }
-}
-
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 6a5e6e8..04ac154 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -82,6 +82,7 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
@@ -219,6 +220,8 @@
@Mock
private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@Mock
+ private NotificationShadeDepthController mNotificationShadeDepthController;
+ @Mock
private AuthController mAuthController;
@Mock
private ScrimController mScrimController;
@@ -333,6 +336,7 @@
mScrimController,
mUserManager,
mMediaDataManager,
+ mNotificationShadeDepthController,
mAmbientState,
mFeatureFlags);
mNotificationPanelViewController.initDependencies(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
index fcea17c..4b8eec4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
@@ -119,7 +119,7 @@
@Test
public void testSetForcePluginOpen_beforeStatusBarInitialization() {
- mNotificationShadeWindowController.setForcePluginOpen(true);
+ mNotificationShadeWindowController.setForcePluginOpen(true, this);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
index 4ed2746..b70c6dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
@@ -63,7 +63,8 @@
when(mResources.getDimension(R.dimen.double_tap_slop))
.thenReturn((float) ViewConfiguration.get(mContext).getScaledTouchSlop() - 1);
- mFalsingManager.setFalseRobustTap(true); // Test double tapping most of the time.
+ mFalsingManager.setSimpleTap(true);
+ mFalsingManager.setFalseTap(true); // Test double tapping most of the time.
mNotificationTapHelper = new NotificationTapHelper.Factory(mFalsingManager, mFakeExecutor)
.create(mActivationListener, mDoubleTapListener, mSlideBackListener);
@@ -158,7 +159,7 @@
1,
0);
- mFalsingManager.setFalseTap(true);
+ mFalsingManager.setSimpleTap(false);
mNotificationTapHelper.onTouchEvent(evDownA);
mNotificationTapHelper.onTouchEvent(evUpA);
verify(mActivationListener, never()).onActiveChanged(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 116e1b9..123e4ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -49,7 +49,6 @@
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -79,6 +78,7 @@
private ScrimController mScrimController;
private ScrimView mScrimBehind;
+ private ScrimView mNotificationsScrim;
private ScrimView mScrimInFront;
private ScrimView mScrimForBubble;
private ScrimState mScrimState;
@@ -104,8 +104,6 @@
@Mock
private DockManager mDockManager;
@Mock
- private BlurUtils mBlurUtils;
- @Mock
private ConfigurationController mConfigurationController;
@Mock
private FeatureFlags mFeatureFlags;
@@ -163,6 +161,7 @@
mScrimController.onPreDraw();
// Force finish all animations.
mLooper.processAllMessages();
+ endAnimation(mNotificationsScrim);
endAnimation(mScrimBehind);
endAnimation(mScrimInFront);
endAnimation(mScrimForBubble);
@@ -189,6 +188,7 @@
mScrimBehind = spy(new ScrimView(getContext()));
mScrimInFront = new ScrimView(getContext());
mScrimForBubble = new ScrimView(getContext());
+ mNotificationsScrim = new ScrimView(getContext());
mAlwaysOnEnabled = true;
mLooper = TestableLooper.get(this);
DejankUtils.setImmediate(true);
@@ -201,7 +201,6 @@
when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true);
- when(mBlurUtils.supportsBlursOnWindows()).thenReturn(true);
doAnswer((Answer<Void>) invocation -> {
mScrimState = invocation.getArgument(0);
@@ -222,10 +221,11 @@
mScrimController = new ScrimController(mLightBarController,
mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
- mDockManager, mBlurUtils, mConfigurationController, mFeatureFlags,
+ mDockManager, mConfigurationController, mFeatureFlags,
new FakeExecutor(new FakeSystemClock()));
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
- mScrimController.attachViews(mScrimBehind, mScrimInFront, mScrimForBubble);
+ mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront,
+ mScrimForBubble);
mScrimController.setAnimatorListener(mAnimatorListener);
mScrimController.setHasBackdrop(false);
@@ -264,7 +264,7 @@
TRANSPARENT /* bubble */);
assertScrimTint(false /* front */,
- false /* behind */,
+ true /* behind */,
false /* bubble */);
}
@@ -516,7 +516,7 @@
TRANSPARENT /* bubble */);
assertScrimTint(false /* front */,
- false /* behind */,
+ true /* behind */,
false /* bubble */);
// Back scrim should be visible after start dragging
@@ -586,7 +586,7 @@
@Test
public void qsExpansion() {
reset(mScrimBehind);
- mScrimController.setQsExpansion(1f);
+ mScrimController.setQsPosition(1f, 999 /* value doesn't matter */);
finishAnimationsImmediately();
assertScrimAlpha(TRANSPARENT, OPAQUE, TRANSPARENT);
@@ -636,7 +636,7 @@
// Make sure at the very end of the animation, we're reset to transparent
assertScrimTint(false /* front */,
- false /* behind */,
+ true /* behind */,
false /* bubble */);
}
@@ -947,7 +947,9 @@
if (scrim == mScrimInFront) {
return "front";
} else if (scrim == mScrimBehind) {
- return "back";
+ return "behind";
+ } else if (scrim == mNotificationsScrim) {
+ return "notifications";
} else if (scrim == mScrimForBubble) {
return "bubble";
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 68464ce..e34bc0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -35,7 +35,6 @@
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
-import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.RemoteException;
@@ -54,6 +53,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
@@ -63,9 +63,9 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
@@ -136,6 +136,8 @@
private OnUserInteractionCallback mOnUserInteractionCallback;
@Mock
private NotificationActivityStarter mNotificationActivityStarter;
+ @Mock
+ private ActivityLaunchAnimator mActivityLaunchAnimator;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private NotificationTestHelper mNotificationTestHelper;
@@ -213,11 +215,14 @@
mock(MetricsLogger.class),
mock(StatusBarNotificationActivityStarterLogger.class),
mOnUserInteractionCallback)
- .setStatusBar(mStatusBar)
- .setNotificationPresenter(mock(NotificationPresenter.class))
- .setNotificationPanelViewController(mock(NotificationPanelViewController.class))
- .setActivityLaunchAnimator(mock(ActivityLaunchAnimator.class))
- .build();
+ .setStatusBar(mStatusBar)
+ .setNotificationPresenter(mock(NotificationPresenter.class))
+ .setNotificationPanelViewController(
+ mock(NotificationPanelViewController.class))
+ .setActivityLaunchAnimator(mActivityLaunchAnimator)
+ .setNotificationAnimatorControllerProvider(
+ mock(NotificationLaunchAnimatorControllerProvider.class))
+ .build();
// set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg
doAnswer(mCallOnDismiss).when(mActivityStarter).dismissKeyguardThenExecute(
@@ -254,14 +259,7 @@
// Then
verify(mShadeController, atLeastOnce()).collapsePanel();
- verify(mContentIntent).sendAndReturnResult(
- any(Context.class),
- anyInt() /* code */,
- any() /* fillInIntent */,
- any() /* PendingIntent.OnFinished */,
- any() /* Handler */,
- any() /* requiredPermission */,
- any() /* Bundle options */);
+ verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(eq(null), any());
verify(mAssistManager).hideAssist();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index c0ebfad..8601de5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -47,7 +47,6 @@
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -125,7 +124,7 @@
mock(NotificationPanelViewController.class), mock(HeadsUpManagerPhone.class),
notificationShadeWindowView, stackScrollLayoutController,
mock(DozeScrimController.class), mock(ScrimController.class),
- mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
+ mock(NotificationShadeWindowController.class), mock(DynamicPrivacyController.class),
mock(KeyguardStateController.class),
mock(KeyguardIndicationController.class), mStatusBar,
mock(ShadeControllerImpl.class), mCommandQueue, mInitController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 5de62b9..3d07eb1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -703,6 +703,10 @@
// ============================= Smart Action tests ============================================
// =============================================================================================
+ private View anyView() {
+ return any();
+ }
+
@Test
public void testTapSmartAction_waitsForKeyguard() throws InterruptedException {
setSmartActions(TEST_ACTION_TITLES);
@@ -710,7 +714,7 @@
mView.getChildAt(2).performClick();
verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(),
- any());
+ anyView());
}
@Test
@@ -721,7 +725,8 @@
mView.getChildAt(2).performClick();
- verify(mActivityStarter, never()).startPendingIntentDismissingKeyguard(any(), any(), any());
+ verify(mActivityStarter, never()).startPendingIntentDismissingKeyguard(any(), any(),
+ anyView());
}
@Test
@@ -734,7 +739,7 @@
mView.getChildAt(2).performClick();
verify(mActivityStarter, times(1))
- .startPendingIntentDismissingKeyguard(any(), any(), any());
+ .startPendingIntentDismissingKeyguard(any(), any(), anyView());
}
@Test
@@ -746,7 +751,7 @@
mView.getChildAt(2).performClick();
verify(mActivityStarter, times(1))
- .startPendingIntentDismissingKeyguard(any(), any(), any());
+ .startPendingIntentDismissingKeyguard(any(), any(), anyView());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
index f85962b..653946e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
@@ -51,6 +51,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.google.common.util.concurrent.MoreExecutors;
@@ -85,6 +86,8 @@
ActivityStarter mActivityStarter;
@Mock
UserTracker mUserTracker;
+ @Mock
+ KeyguardStateController mKeyguardStateController;
@Captor
ArgumentCaptor<Intent> mIntentCaptor;
@Captor
@@ -106,6 +109,7 @@
when(mWalletClient.getShortcutShortLabel()).thenReturn(SHORTCUT_SHORT_LABEL);
when(mWalletClient.getServiceLabel()).thenReturn(SERVICE_LABEL);
when(mWalletClient.createWalletIntent()).thenReturn(mWalletIntent);
+ when(mKeyguardStateController.isUnlocked()).thenReturn(true);
mController = new WalletScreenController(
mContext,
mWalletView,
@@ -114,7 +118,7 @@
MoreExecutors.directExecutor(),
new Handler(mTestableLooper.getLooper()),
mUserTracker,
- /* isDeviceLocked= */false);
+ mKeyguardStateController);
}
@Test
@@ -206,6 +210,14 @@
}
@Test
+ public void onKeyguardFadingAwayChanged_queryCards() {
+ mController.onKeyguardFadingAwayChanged();
+
+ verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
+ assertEquals(mController, mCallbackCaptor.getValue());
+ }
+
+ @Test
public void onCardSelected() {
mController.onCardSelected(createCardViewInfo());
diff --git a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
index ea3e650..5f9aaae 100644
--- a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
+++ b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
@@ -158,24 +158,29 @@
final Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR, SEND_NOTIFICATION_DELAY_HOURS);
mAlarmManager.set(RTC_WAKEUP, cal.getTimeInMillis(),
- createPendingIntent(mContext, userId, ACTION_SEND_NOTIFICATION,
- service.flattenToShortString()));
+ createPendingIntent(mContext, userId, ACTION_SEND_NOTIFICATION, service));
}
private void cancelAlarm(int userId, ComponentName service) {
mAlarmManager.cancel(
- createPendingIntent(mContext, userId, ACTION_SEND_NOTIFICATION,
- service.flattenToShortString()));
+ createPendingIntent(mContext, userId, ACTION_SEND_NOTIFICATION, service));
}
protected static PendingIntent createPendingIntent(Context context, int userId, String action,
- String serviceComponentName) {
+ ComponentName serviceComponentName) {
+ return PendingIntent.getBroadcast(context, 0,
+ createIntent(context, userId, action, serviceComponentName),
+ PendingIntent.FLAG_IMMUTABLE);
+ }
+
+ protected static Intent createIntent(Context context, int userId, String action,
+ ComponentName serviceComponentName) {
final Intent intent = new Intent(action);
intent.setPackage(context.getPackageName())
- .setIdentifier(serviceComponentName)
+ .setIdentifier(serviceComponentName.flattenToShortString())
+ .putExtra(Intent.EXTRA_COMPONENT_NAME, serviceComponentName)
.putExtra(Intent.EXTRA_USER_ID, userId);
- return PendingIntent.getBroadcast(context, 0, intent,
- PendingIntent.FLAG_IMMUTABLE);
+ return intent;
}
/** A sub class to handle notifications and settings on the main thread. */
@@ -204,10 +209,9 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- final String service = intent.getIdentifier();
- final ComponentName componentName = ComponentName.unflattenFromString(service);
- if (TextUtils.isEmpty(action) || TextUtils.isEmpty(service)
- || componentName == null) {
+ final ComponentName componentName = intent.getParcelableExtra(
+ Intent.EXTRA_COMPONENT_NAME);
+ if (TextUtils.isEmpty(action) || componentName == null) {
return;
}
final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_SYSTEM);
@@ -215,7 +219,8 @@
trySendNotification(userId, componentName);
} else if (ACTION_A11Y_SETTINGS.equals(action)) {
launchSettings(userId, componentName);
- mNotificationManager.cancel(service, NOTE_A11Y_VIEW_AND_CONTROL_ACCESS);
+ mNotificationManager.cancel(componentName.flattenToShortString(),
+ NOTE_A11Y_VIEW_AND_CONTROL_ACCESS);
onNotificationCanceled(userId, componentName);
} else if (ACTION_DISMISS_NOTIFICATION.equals(action)) {
onNotificationCanceled(userId, componentName);
@@ -257,8 +262,7 @@
mContext.getPackageManager());
final int size = mContext.getResources().getDimensionPixelSize(
android.R.dimen.app_icon_size);
- sendNotification(userId, componentName.flattenToShortString(),
- displayName,
+ sendNotification(userId, componentName, displayName,
ImageUtils.buildScaledBitmap(drawable, size, size));
}
break;
@@ -289,7 +293,8 @@
}
}
- private void sendNotification(int userId, String serviceComponentName, CharSequence name,
+ private void sendNotification(int userId, ComponentName serviceComponentName,
+ CharSequence name,
Bitmap bitmap) {
final Notification.Builder notificationBuilder = new Notification.Builder(mContext,
SystemNotificationChannels.ACCESSIBILITY_SECURITY_POLICY);
@@ -315,7 +320,8 @@
if (bitmap != null) {
notificationBuilder.setLargeIcon(bitmap);
}
- mNotificationManager.notify(serviceComponentName, NOTE_A11Y_VIEW_AND_CONTROL_ACCESS,
+ mNotificationManager.notify(serviceComponentName.flattenToShortString(),
+ NOTE_A11Y_VIEW_AND_CONTROL_ACCESS,
notificationBuilder.build());
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 8040851..f9aecd7 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -119,6 +119,11 @@
}
@Override
+ public void onAccessibilityActionPerformed(int displayId) {
+ updateMagnificationButton(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ }
+
+ @Override
public void onTouchInteractionStart(int displayId, int mode) {
handleUserInteractionChanged(displayId, mode);
}
@@ -148,8 +153,13 @@
}
private void updateMagnificationButton(int displayId, int mode) {
- if (isActivated(displayId, mode) && mMagnificationCapabilities
- == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
+ final boolean isActivated = isActivated(displayId, mode);
+ final boolean showButton;
+ synchronized (mLock) {
+ showButton = isActivated && mMagnificationCapabilities
+ == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
+ }
+ if (showButton) {
getWindowMagnificationMgr().showMagnificationButton(displayId, mode);
} else {
getWindowMagnificationMgr().removeMagnificationButton(displayId);
@@ -430,13 +440,22 @@
private boolean isActivated(int displayId, int mode) {
boolean isActivated = false;
- if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
- && mFullScreenMagnificationController != null) {
- isActivated = mFullScreenMagnificationController.isMagnifying(displayId)
- || mFullScreenMagnificationController.isForceShowMagnifiableBounds(displayId);
- } else if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
- && mWindowMagnificationMgr != null) {
- isActivated = mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId);
+ if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
+ synchronized (mLock) {
+ if (mFullScreenMagnificationController == null) {
+ return false;
+ }
+ isActivated = mFullScreenMagnificationController.isMagnifying(displayId)
+ || mFullScreenMagnificationController.isForceShowMagnifiableBounds(
+ displayId);
+ }
+ } else if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
+ synchronized (mLock) {
+ if (mWindowMagnificationMgr == null) {
+ return false;
+ }
+ isActivated = mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId);
+ }
}
return isActivated;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index 86f61ee..938cb73 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -95,6 +95,13 @@
void onPerformScaleAction(int displayId, float scale);
/**
+ * Called when the accessibility action is performed.
+ *
+ * @param displayId The logical display id.
+ */
+ void onAccessibilityActionPerformed(int displayId);
+
+ /**
* Called when the state of the magnification activation is changed.
*
* @param displayId The logical display id.
@@ -536,9 +543,12 @@
@Override
public void onPerformScaleAction(int displayId, float scale) {
- synchronized (mLock) {
- mCallback.onPerformScaleAction(displayId, scale);
- }
+ mCallback.onPerformScaleAction(displayId, scale);
+ }
+
+ @Override
+ public void onAccessibilityActionPerformed(int displayId) {
+ mCallback.onAccessibilityActionPerformed(displayId);
}
@Override
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index e9b2ed3..55490ce 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -154,6 +154,8 @@
private static final long DEVICE_DISAPPEARED_TIMEOUT_MS = 10 * 1000;
private static final long DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS = 10 * 60 * 1000;
+ private static final long DEVICE_LISTENER_DIED_REBIND_TIMEOUT_MS = 10 * 1000;
+
private static final boolean DEBUG = false;
private static final String LOG_TAG = "CompanionDeviceManagerService";
@@ -1131,6 +1133,14 @@
// Service binding is managed manually based on corresponding device being nearby
return Long.MAX_VALUE;
}
+
+ @Override
+ public void binderDied() {
+ super.binderDied();
+
+ // Re-connect to the service if process gets killed
+ mMainHandler.postDelayed(this::connect, DEVICE_LISTENER_DIED_REBIND_TIMEOUT_MS);
+ }
};
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 7fc7933..5cbcacf 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -158,7 +158,6 @@
"android.hardware.power.stats-V1-java",
"android.hidl.manager-V1.2-java",
"capture_state_listener-aidl-java",
- "dnsresolver_aidl_interface-V8-java",
"icu4j_calendar_astronomer",
"netd-client",
"overlayable_policy_aidl-java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 185cdfc..922b21a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3789,6 +3789,10 @@
private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
try {
mNetd.networkDestroy(networkAgent.network.getNetId());
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Exception destroying network(networkDestroy): " + e);
+ }
+ try {
mDnsResolver.destroyNetworkCache(networkAgent.network.getNetId());
} catch (RemoteException | ServiceSpecificException e) {
loge("Exception destroying network: " + e);
@@ -5683,7 +5687,7 @@
+ mNetworkRequestForCallback.requestId
+ " " + mRequests
+ (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
- + "callback flags: " + mCallbackFlags;
+ + " callback flags: " + mCallbackFlags;
}
}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index c983600..7057b840 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -19,6 +19,7 @@
per-file *Alarm* = file:/apex/jobscheduler/OWNERS
per-file *AppOp* = file:/core/java/android/permission/OWNERS
per-file *Battery* = file:/BATTERY_STATS_OWNERS
+per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS
per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index fa3771a..6e7771d 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
-import android.os.FileUtils;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -46,6 +45,7 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
@@ -132,13 +132,13 @@
private static final String FLASH_LOCK_UNLOCKED = "0";
private final Context mContext;
+ private final String mDataBlockFile;
private final boolean mIsRunningDSU;
private final Object mLock = new Object();
private final CountDownLatch mInitDoneSignal = new CountDownLatch(1);
private int mAllowedUid = -1;
private long mBlockDeviceSize;
- private String mDataBlockFile;
@GuardedBy("mLock")
private boolean mIsWritable = true;
@@ -146,8 +146,12 @@
public PersistentDataBlockService(Context context) {
super(context);
mContext = context;
- mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
mIsRunningDSU = SystemProperties.getBoolean(GSI_RUNNING_PROP, false);
+ if (mIsRunningDSU) {
+ mDataBlockFile = GSI_SANDBOX;
+ } else {
+ mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
+ }
mBlockDeviceSize = -1; // Load lazily
}
@@ -262,7 +266,11 @@
private long getBlockDeviceSize() {
synchronized (mLock) {
if (mBlockDeviceSize == -1) {
- mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
+ if (mIsRunningDSU) {
+ mBlockDeviceSize = MAX_DATA_BLOCK_SIZE;
+ } else {
+ mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
+ }
}
}
@@ -292,40 +300,30 @@
return true;
}
- private FileOutputStream getBlockOutputStream() throws IOException {
- if (!mIsRunningDSU) {
- return new FileOutputStream(new File(mDataBlockFile));
- } else {
- File sandbox = new File(GSI_SANDBOX);
- File realpdb = new File(SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP));
- if (!sandbox.exists()) {
- FileUtils.copy(realpdb, sandbox);
- mDataBlockFile = GSI_SANDBOX;
- }
- Slog.i(TAG, "PersistentDataBlock copy-on-write");
- return new FileOutputStream(sandbox);
- }
+ private FileChannel getBlockOutputChannel() throws IOException {
+ return new RandomAccessFile(mDataBlockFile, "rw").getChannel();
}
private boolean computeAndWriteDigestLocked() {
byte[] digest = computeDigestLocked(null);
if (digest != null) {
- DataOutputStream outputStream;
+ FileChannel channel;
try {
- outputStream = new DataOutputStream(getBlockOutputStream());
+ channel = getBlockOutputChannel();
} catch (IOException e) {
Slog.e(TAG, "partition not available?", e);
return false;
}
try {
- outputStream.write(digest, 0, DIGEST_SIZE_BYTES);
- outputStream.flush();
+ ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES);
+ buf.put(digest);
+ buf.flip();
+ channel.write(buf);
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "failed to write block checksum", e);
return false;
- } finally {
- IoUtils.closeQuietly(outputStream);
}
return true;
} else {
@@ -376,25 +374,18 @@
}
private void formatPartitionLocked(boolean setOemUnlockEnabled) {
- DataOutputStream outputStream;
- try {
- outputStream = new DataOutputStream(getBlockOutputStream());
- } catch (IOException e) {
- Slog.e(TAG, "partition not available?", e);
- return;
- }
- byte[] data = new byte[DIGEST_SIZE_BYTES];
try {
- outputStream.write(data, 0, DIGEST_SIZE_BYTES);
- outputStream.writeInt(PARTITION_TYPE_MARKER);
- outputStream.writeInt(0); // data size
- outputStream.flush();
+ FileChannel channel = getBlockOutputChannel();
+ ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES + HEADER_SIZE);
+ buf.put(new byte[DIGEST_SIZE_BYTES]);
+ buf.putInt(PARTITION_TYPE_MARKER);
+ buf.putInt(0);
+ channel.write(buf);
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "failed to format block", e);
return;
- } finally {
- IoUtils.closeQuietly(outputStream);
}
doSetOemUnlockEnabledLocked(setOemUnlockEnabled);
@@ -402,16 +393,9 @@
}
private void doSetOemUnlockEnabledLocked(boolean enabled) {
- FileOutputStream outputStream;
- try {
- outputStream = getBlockOutputStream();
- } catch (IOException e) {
- Slog.e(TAG, "partition not available", e);
- return;
- }
try {
- FileChannel channel = outputStream.getChannel();
+ FileChannel channel = getBlockOutputChannel();
channel.position(getBlockDeviceSize() - 1);
@@ -419,13 +403,12 @@
data.put(enabled ? (byte) 1 : (byte) 0);
data.flip();
channel.write(data);
- outputStream.flush();
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "unable to access persistent partition", e);
return;
} finally {
SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
- IoUtils.closeQuietly(outputStream);
}
}
@@ -479,35 +462,32 @@
return (int) -maxBlockSize;
}
- DataOutputStream outputStream;
+ FileChannel channel;
try {
- outputStream = new DataOutputStream(getBlockOutputStream());
+ channel = getBlockOutputChannel();
} catch (IOException e) {
Slog.e(TAG, "partition not available?", e);
- return -1;
+ return -1;
}
- ByteBuffer headerAndData = ByteBuffer.allocate(data.length + HEADER_SIZE);
+ ByteBuffer headerAndData = ByteBuffer.allocate(
+ data.length + HEADER_SIZE + DIGEST_SIZE_BYTES);
+ headerAndData.put(new byte[DIGEST_SIZE_BYTES]);
headerAndData.putInt(PARTITION_TYPE_MARKER);
headerAndData.putInt(data.length);
headerAndData.put(data);
-
+ headerAndData.flip();
synchronized (mLock) {
if (!mIsWritable) {
- IoUtils.closeQuietly(outputStream);
return -1;
}
try {
- byte[] checksum = new byte[DIGEST_SIZE_BYTES];
- outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
- outputStream.write(headerAndData.array());
- outputStream.flush();
+ channel.write(headerAndData);
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "failed writing to the persistent data block", e);
return -1;
- } finally {
- IoUtils.closeQuietly(outputStream);
}
if (computeAndWriteDigestLocked()) {
@@ -567,17 +547,6 @@
public void wipe() {
enforceOemUnlockWritePermission();
- if (mIsRunningDSU) {
- File sandbox = new File(GSI_SANDBOX);
- if (sandbox.exists()) {
- if (sandbox.delete()) {
- mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
- } else {
- Slog.e(TAG, "Failed to wipe sandbox persistent data block");
- }
- }
- return;
- }
synchronized (mLock) {
int ret = nativeWipe(mDataBlockFile);
@@ -735,28 +704,18 @@
}
private void writeDataBuffer(long offset, ByteBuffer dataBuffer) {
- FileOutputStream outputStream;
- try {
- outputStream = getBlockOutputStream();
- } catch (IOException e) {
- Slog.e(TAG, "partition not available", e);
- return;
- }
synchronized (mLock) {
if (!mIsWritable) {
- IoUtils.closeQuietly(outputStream);
return;
}
try {
- FileChannel channel = outputStream.getChannel();
+ FileChannel channel = getBlockOutputChannel();
channel.position(offset);
channel.write(dataBuffer);
- outputStream.flush();
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "unable to access persistent partition", e);
return;
- } finally {
- IoUtils.closeQuietly(outputStream);
}
computeAndWriteDigestLocked();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index b485fe8..611fe7a 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -29,6 +29,8 @@
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -155,7 +157,6 @@
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
- int targetSdk;
boolean matchTelephonyCallbackEvent(int event) {
return (callback != null) && (this.eventList.contains(event));
@@ -228,6 +229,54 @@
TelecomManager.ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION, packageName,
userHandle));
}
+
+ /**
+ * To check the SDK version for
+ * {@link android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener} should add
+ * {@link android.Manifest.permission#READ_PHONE_STATE} since Android 12.
+ * @noinspection ConstantConditions
+ */
+ public boolean isActiveDataSubIdReadPhoneStateEnforcedInPlatformCompat(String packageName,
+ UserHandle userHandle) {
+ return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled(
+ REQUIRE_READ_PHONE_STATE_PERMISSION_FOR_ACTIVE_DATA_SUB_ID, packageName,
+ userHandle));
+ }
+
+ /**
+ * To check the SDK version for
+ * {@link android.telephony.TelephonyCallback.CellInfoListener} should add
+ * {@link android.Manifest.permission#READ_PHONE_STATE} since Android 12.
+ * @noinspection ConstantConditions
+ */
+ public boolean isCellInfoReadPhoneStateEnforcedInPlatformCompat(String packageName,
+ UserHandle userHandle) {
+ return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled(
+ REQUIRE_READ_PHONE_STATE_PERMISSION_FOR_CELL_INFO, packageName, userHandle));
+ }
+
+ /**
+ * To check the SDK version for
+ * {@link android.telephony.TelephonyCallback.DisplayInfoListener} should remove
+ * {@link android.Manifest.permission#READ_PHONE_STATE} since Android 12.
+ * @noinspection ConstantConditions
+ */
+ public boolean isDisplayInfoReadPhoneStateEnforcedInPlatformCompat(String packageName,
+ UserHandle userHandle) {
+ return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled(
+ REQUIRE_READ_PHONE_STATE_PERMISSION_FOR_DISPLAY_INFO, packageName, userHandle));
+ }
+
+ /**
+ * Support backward compatibility for {@link android.telephony.TelephonyDisplayInfo}.
+ *
+ * @noinspection ConstantConditions
+ */
+ public boolean isDisplayInfoNrAdvancedSupported(String packageName,
+ UserHandle userHandle) {
+ return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled(
+ DISPLAY_INFO_NR_ADVANCED_SUPPORTED, packageName, userHandle));
+ }
}
private final Context mContext;
@@ -346,6 +395,39 @@
*/
private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
mPreciseDataConnectionStates;
+ /**
+ * Support backward compatibility for {@link android.telephony.TelephonyDisplayInfo}.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long DISPLAY_INFO_NR_ADVANCED_SUPPORTED = 181658987L;
+
+ /**
+ * To check the SDK version for
+ * {@link android.telephony.TelephonyCallback.DisplayInfoListener} should remove
+ * {@link android.Manifest.permission#READ_PHONE_STATE} since Android 12.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long REQUIRE_READ_PHONE_STATE_PERMISSION_FOR_DISPLAY_INFO = 183164979L;
+
+ /**
+ * To check the SDK version for
+ * {@link android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener} should add
+ * {@link android.Manifest.permission#READ_PHONE_STATE} since Android 12.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long REQUIRE_READ_PHONE_STATE_PERMISSION_FOR_ACTIVE_DATA_SUB_ID
+ = 182478738L;
+
+ /**
+ * To check the SDK version for {@link android.telephony.TelephonyCallback.CellInfoListener}
+ * should add {@link android.Manifest.permission#READ_PHONE_STATE} since Android 12.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long REQUIRE_READ_PHONE_STATE_PERMISSION_FOR_CELL_INFO = 184323934L;
private static final Set<Integer> REQUIRE_PRECISE_PHONE_STATE_PERMISSION;
static {
@@ -379,13 +461,46 @@
|| events.contains(TelephonyCallback.EVENT_BARRING_INFO_CHANGED);
}
- private boolean isPhoneStatePermissionRequired(Set<Integer> events, int targetSdk) {
- return events.contains(TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
+ private boolean isPhoneStatePermissionRequired(Set<Integer> events, String callingPackage,
+ UserHandle userHandle) {
+ if (events.contains(TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
|| events.contains(TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
- || events.contains(TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
- || events.contains(TelephonyCallback.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)
- || (targetSdk <= android.os.Build.VERSION_CODES.R ? events.contains(
- TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED) : false);
+ || events.contains(TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)) {
+ return true;
+ }
+
+ // Only check READ_PHONE_STATE for CALL_STATE_CHANGED for Android 12 or above.
+ if ((events.contains(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED))
+ && mConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(
+ callingPackage, userHandle)) {
+ return true;
+ }
+
+ // Only check READ_PHONE_STATE for ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED for Android 12
+ // or above.
+ if (events.contains(TelephonyCallback.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)
+ && mConfigurationProvider.isActiveDataSubIdReadPhoneStateEnforcedInPlatformCompat(
+ callingPackage, userHandle)) {
+ return true;
+ }
+
+ // Only check READ_PHONE_STATE for CELL_INFO_CHANGED for Android 12 or above.
+ if (events.contains(TelephonyCallback.EVENT_CELL_INFO_CHANGED)
+ && mConfigurationProvider.isCellInfoReadPhoneStateEnforcedInPlatformCompat(
+ callingPackage, userHandle)) {
+ return true;
+ }
+
+ // Only check READ_PHONE_STATE for DISPLAY_INFO_CHANGED for Android 11 or older.
+ // READ_PHONE_STATE is not required anymore after Android 12.
+ if (events.contains(TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)
+ && !mConfigurationProvider.isDisplayInfoReadPhoneStateEnforcedInPlatformCompat(
+ callingPackage, userHandle)) {
+ return true;
+ }
+
+ return false;
}
private boolean isPrecisePhoneStatePermissionRequired(Set<Integer> events) {
@@ -902,12 +1017,11 @@
remove(callback.asBinder());
return;
}
- int callerTargetSdk = TelephonyPermissions.getTargetSdk(mContext, callingPackage);
+
// Checks permission and throws SecurityException for disallowed operations. For pre-M
// apps whose runtime permission has been revoked, we return immediately to skip sending
// events to the app without crashing it.
- if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId,
- "listen", callerTargetSdk)) {
+ if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId, "listen")) {
return;
}
@@ -940,7 +1054,6 @@
}
r.phoneId = phoneId;
r.eventList = events;
- r.targetSdk = callerTargetSdk;
if (DBG) {
log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
@@ -1773,7 +1886,8 @@
TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)
&& idMatchWithoutDefaultPhoneCheck(r.subId, subId)) {
try {
- if (r.targetSdk <= android.os.Build.VERSION_CODES.R) {
+ if (!mConfigurationProvider.isDisplayInfoNrAdvancedSupported(
+ r.callingPackage, Binder.getCallingUserHandle())) {
telephonyDisplayInfo =
getBackwardCompatibleTelephonyDisplayInfo(
telephonyDisplayInfo);
@@ -2922,7 +3036,7 @@
}
private boolean checkListenerPermission(Set<Integer> events, int subId, String callingPackage,
- @Nullable String callingFeatureId, String message, int targetSdk) {
+ @Nullable String callingFeatureId, String message) {
LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder =
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(callingPackage)
@@ -2958,26 +3072,13 @@
}
}
- if (isPhoneStatePermissionRequired(events, targetSdk)) {
+ if (isPhoneStatePermissionRequired(events, callingPackage, Binder.getCallingUserHandle())) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
mContext, subId, callingPackage, callingFeatureId, message)) {
isPermissionCheckSuccessful = false;
}
}
- // Only check READ_PHONE_STATE for CALL_STATE_CHANGED for API 31+.
- if (mConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(callingPackage,
- Binder.getCallingUserHandle())) {
- if (events.contains(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED)
- || events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED)) {
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mContext, subId, callingPackage, callingFeatureId, message)) {
- throw new SecurityException("CALL_STATE_CHANGED event requires "
- + "READ_PHONE_STATE");
- }
- }
- }
-
if (isPrecisePhoneStatePermissionRequired(events)) {
// check if calling app has either permission READ_PRECISE_PHONE_STATE
// or with carrier privileges
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c1ab6cc..c7f2f43 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -78,6 +78,7 @@
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.ForegroundServiceDidNotStartInTimeException;
import android.app.ForegroundServiceStartNotAllowedException;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
@@ -4988,9 +4989,10 @@
}
void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) {
- mAm.crashApplication(app.uid, app.getPid(), app.info.packageName, app.userId,
+ mAm.crashApplicationWithType(app.uid, app.getPid(), app.info.packageName, app.userId,
"Context.startForegroundService() did not then call Service.startForeground(): "
- + serviceRecord, false /*force*/);
+ + serviceRecord, false /*force*/,
+ ForegroundServiceDidNotStartInTimeException.TYPE_ID);
}
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7dc39b3..23dda78 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -179,6 +179,7 @@
import android.app.ProcessMemoryState;
import android.app.ProfilerInfo;
import android.app.PropertyInvalidatedCache;
+import android.app.RemoteServiceException;
import android.app.SyncNotedAppOp;
import android.app.WaitResult;
import android.app.backup.BackupManager.OperationType;
@@ -233,6 +234,7 @@
import android.graphics.Rect;
import android.hardware.display.DisplayManagerInternal;
import android.media.audiofx.AudioEffect;
+import android.net.ConnectivityManager;
import android.net.Proxy;
import android.net.Uri;
import android.os.AppZygote;
@@ -2935,6 +2937,13 @@
@Override
public void crashApplication(int uid, int initialPid, String packageName, int userId,
String message, boolean force) {
+ crashApplicationWithType(uid, initialPid, packageName, userId, message, force,
+ RemoteServiceException.TYPE_ID);
+ }
+
+ @Override
+ public void crashApplicationWithType(int uid, int initialPid, String packageName, int userId,
+ String message, boolean force, int exceptionTypeId) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: crashApplication() from pid="
@@ -2947,7 +2956,7 @@
synchronized(this) {
mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId,
- message, force);
+ message, force, exceptionTypeId);
}
}
@@ -3481,9 +3490,9 @@
// Clear its scheduled jobs
JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
- // Clearing data is akin to uninstalling. The app is force stopped before we
- // get to this point, so the reason won't be checked by the app.
- js.cancelJobsForUid(appInfo.uid, JobParameters.STOP_REASON_USER, "clear data");
+ // Clearing data is a user-initiated action.
+ js.cancelJobsForUid(appInfo.uid, JobParameters.STOP_REASON_USER,
+ JobParameters.DEBUG_REASON_DATA_CLEARED, "clear data");
// Clear its pending alarms
AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class);
@@ -12936,7 +12945,7 @@
}
mBatteryStatsService.noteCurrentTimeChanged();
break;
- case Intent.ACTION_CLEAR_DNS_CACHE:
+ case ConnectivityManager.ACTION_CLEAR_DNS_CACHE:
mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
break;
case Proxy.PROXY_CHANGE_ACTION:
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 3602f44..5a59eabd 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -486,7 +486,7 @@
* @param message
*/
void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId,
- String message, boolean force) {
+ String message, boolean force, int exceptionTypeId) {
ProcessRecord proc = null;
// Figure out which process to kill. We don't trust that initialPid
@@ -518,7 +518,7 @@
return;
}
- proc.scheduleCrashLocked(message);
+ proc.scheduleCrashLocked(message, exceptionTypeId);
if (force) {
// If the app is responsive, the scheduled crash will happen as expected
// and then the delayed summary kill will be a no-op.
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index c8721cc..960cc42 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1328,6 +1328,9 @@
|| uidRec.getSetProcState() == PROCESS_STATE_NONEXISTENT) {
uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED;
}
+ if (uidRec.getSetCapability() != uidRec.getCurCapability()) {
+ uidChange |= UidRecord.CHANGE_CAPABILITY;
+ }
uidRec.setSetProcState(uidRec.getCurProcState());
uidRec.setSetCapability(uidRec.getCurCapability());
uidRec.setSetAllowListed(uidRec.isCurAllowListed());
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index ed136af..9e94d4a 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -26,6 +26,7 @@
import android.app.ApplicationExitInfo.Reason;
import android.app.ApplicationExitInfo.SubReason;
import android.app.IApplicationThread;
+import android.app.RemoteServiceException;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProcessInfo;
import android.content.pm.VersionedPackage;
@@ -949,6 +950,21 @@
@GuardedBy("mService")
void scheduleCrashLocked(String message) {
+ scheduleCrashLocked(message, RemoteServiceException.TYPE_ID);
+ }
+
+ /**
+ * Let an app process throw an exception on a binder thread, which typically crashes the
+ * process, unless it has an unhandled exception handler.
+ *
+ * See {@link ActivityThread#throwRemoteServiceException}.
+ *
+ * @param message exception message
+ * @param exceptionTypeId ID defined in {@link android.app.RemoteServiceException} or one
+ * of its subclasses.
+ */
+ @GuardedBy("mService")
+ void scheduleCrashLocked(String message, int exceptionTypeId) {
// Checking killedbyAm should keep it from showing the crash dialog if the process
// was already dead for a good / normal reason.
if (!mKilledByAm) {
@@ -959,7 +975,7 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- mThread.scheduleCrash(message);
+ mThread.scheduleCrash(message, exceptionTypeId);
} catch (RemoteException e) {
// If it's already dead our work is done. If it's wedged just kill it.
// We won't get the crash dialog or the error reporting.
diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java
index df65ee6..c1bfe25 100644
--- a/services/core/java/com/android/server/am/UidObserverController.java
+++ b/services/core/java/com/android/server/am/UidObserverController.java
@@ -147,6 +147,9 @@
if ((currentChange & UidRecord.CHANGE_GONE) != 0) {
currentChange &= ~(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_CACHED);
}
+ if ((pendingChange & UidRecord.CHANGE_CAPABILITY) != 0) {
+ currentChange |= UidRecord.CHANGE_CAPABILITY;
+ }
return currentChange;
}
@@ -285,12 +288,9 @@
reg.mLastProcStates.delete(item.uid);
}
} else {
+ boolean doReport = false;
if ((reg.mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
- if (DEBUG_UID_OBSERVERS) {
- Slog.i(TAG_UID_OBSERVERS, "UID CHANGED uid=" + item.uid
- + ": " + item.procState + ": " + item.capability);
- }
- boolean doReport = true;
+ doReport = true;
if (reg.mCutpoint >= ActivityManager.MIN_PROCESS_STATE) {
final int lastState = reg.mLastProcStates.get(item.uid,
ActivityManager.PROCESS_STATE_UNKNOWN);
@@ -302,13 +302,20 @@
doReport = item.procState != PROCESS_STATE_NONEXISTENT;
}
}
- if (doReport) {
- if (reg.mLastProcStates != null) {
- reg.mLastProcStates.put(item.uid, item.procState);
- }
- observer.onUidStateChanged(item.uid, item.procState,
- item.procStateSeq, item.capability);
+ }
+ if ((reg.mWhich & ActivityManager.UID_OBSERVER_CAPABILITY) != 0) {
+ doReport |= (change & UidRecord.CHANGE_CAPABILITY) != 0;
+ }
+ if (doReport) {
+ if (DEBUG_UID_OBSERVERS) {
+ Slog.i(TAG_UID_OBSERVERS, "UID CHANGED uid=" + item.uid
+ + ": " + item.procState + ": " + item.capability);
}
+ if (reg.mLastProcStates != null) {
+ reg.mLastProcStates.put(item.uid, item.procState);
+ }
+ observer.onUidStateChanged(item.uid, item.procState,
+ item.procStateSeq, item.capability);
}
}
final int duration = (int) (SystemClock.uptimeMillis() - start);
@@ -428,12 +435,14 @@
ActivityManager.UID_OBSERVER_ACTIVE,
ActivityManager.UID_OBSERVER_GONE,
ActivityManager.UID_OBSERVER_PROCSTATE,
+ ActivityManager.UID_OBSERVER_CAPABILITY,
};
private static final int[] PROTO_ENUMS = new int[]{
ActivityManagerProto.UID_OBSERVER_FLAG_IDLE,
ActivityManagerProto.UID_OBSERVER_FLAG_ACTIVE,
ActivityManagerProto.UID_OBSERVER_FLAG_GONE,
ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE,
+ ActivityManagerProto.UID_OBSERVER_FLAG_CAPABILITY,
};
UidObserverRegistration(int uid, @NonNull String pkg, int which, int cutpoint) {
@@ -462,6 +471,9 @@
if ((mWhich & ActivityManager.UID_OBSERVER_GONE) != 0) {
pw.print(" GONE");
}
+ if ((mWhich & ActivityManager.UID_OBSERVER_CAPABILITY) != 0) {
+ pw.print(" CAP");
+ }
if ((mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
pw.print(" STATE");
pw.print(" (cut=");
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 2fb662f..4ba59fa 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -122,6 +122,7 @@
static final int CHANGE_ACTIVE = 1<<2;
static final int CHANGE_CACHED = 1<<3;
static final int CHANGE_UNCACHED = 1<<4;
+ static final int CHANGE_CAPABILITY = 1<<5;
// Keep the enum lists in sync
private static int[] ORIG_ENUMS = new int[] {
@@ -130,6 +131,7 @@
CHANGE_ACTIVE,
CHANGE_CACHED,
CHANGE_UNCACHED,
+ CHANGE_CAPABILITY,
};
private static int[] PROTO_ENUMS = new int[] {
UidRecordProto.CHANGE_GONE,
@@ -137,6 +139,7 @@
UidRecordProto.CHANGE_ACTIVE,
UidRecordProto.CHANGE_CACHED,
UidRecordProto.CHANGE_UNCACHED,
+ UidRecordProto.CHANGE_CAPABILITY,
};
// UidObserverController is the only thing that should modify this.
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 143a1cf..a5d0e72 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -93,7 +93,6 @@
import android.util.EventLog;
import android.util.IntArray;
import android.util.Pair;
-import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
@@ -110,6 +109,7 @@
import com.android.server.am.UserState.KeyEvictedCallback;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
+import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerService;
@@ -510,7 +510,7 @@
elapsedTimeMs);
final long maxElapsedTimeMs = 120_000;
if (elapsedTimeMs > maxElapsedTimeMs) {
- Slog.wtf("SystemServerTiming",
+ Slogf.wtf("SystemServerTiming",
"finishUserBoot took too long. elapsedTimeMs=" + elapsedTimeMs);
}
}
@@ -533,12 +533,12 @@
final UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
if (parent != null
&& isUserRunning(parent.id, ActivityManager.FLAG_AND_UNLOCKED)) {
- Slog.d(TAG, "User " + userId + " (parent " + parent.id
+ Slogf.d(TAG, "User " + userId + " (parent " + parent.id
+ "): attempting unlock because parent is unlocked");
maybeUnlockUser(userId);
} else {
String parentId = (parent == null) ? "<null>" : String.valueOf(parent.id);
- Slog.d(TAG, "User " + userId + " (parent " + parentId
+ Slogf.d(TAG, "User " + userId + " (parent " + parentId
+ "): delaying unlock because parent is locked");
}
} else {
@@ -587,7 +587,7 @@
// Call onBeforeUnlockUser on a worker thread that allows disk I/O
FgThread.getHandler().post(() -> {
if (!StorageManager.isUserKeyUnlocked(userId)) {
- Slog.w(TAG, "User key got locked unexpectedly, leaving user locked.");
+ Slogf.w(TAG, "User key got locked unexpectedly, leaving user locked.");
return;
}
mInjector.getUserManager().onBeforeUnlockUser(userId);
@@ -716,7 +716,7 @@
Runnable initializeUser = () -> mInjector.getUserManager().makeInitialized(userInfo.id);
if (!userInfo.isInitialized()) {
- Slog.d(TAG, "Initializing user #" + userId);
+ Slogf.d(TAG, "Initializing user #" + userId);
if (userInfo.preCreated) {
initializeUser.run();
} else if (userId != UserHandle.USER_SYSTEM) {
@@ -739,7 +739,7 @@
}
if (userInfo.preCreated) {
- Slog.i(TAG, "Stopping pre-created user " + userInfo.toFullString());
+ Slogf.i(TAG, "Stopping pre-created user " + userInfo.toFullString());
// Pre-created user was started right after creation so services could properly
// intialize it; it should be stopped right away as it's not really a "real" user.
stopUser(userInfo.id, /* force= */ true, /* allowDelayedLocking= */ false,
@@ -752,7 +752,7 @@
mHandler.obtainMessage(USER_UNLOCKED_MSG, userId, 0).sendToTarget();
- Slog.i(TAG, "Posting BOOT_COMPLETED user #" + userId);
+ Slogf.i(TAG, "Posting BOOT_COMPLETED user #" + userId);
// Do not report secondary users, runtime restarts or first boot/upgrade
if (userId == UserHandle.USER_SYSTEM
&& !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
@@ -777,7 +777,7 @@
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser)
throws RemoteException {
- Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u"
+ Slogf.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u"
+ userId);
mBootCompleted = true;
}
@@ -863,11 +863,12 @@
for (int i = 0; i < usersToStop.length; i++) {
int relatedUserId = usersToStop[i];
if ((UserHandle.USER_SYSTEM == relatedUserId) || isCurrentUserLU(relatedUserId)) {
- if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked cannot stop related user "
- + relatedUserId);
+ if (DEBUG_MU) {
+ Slogf.i(TAG, "stopUsersLocked cannot stop related user " + relatedUserId);
+ }
// We still need to stop the requested user if it's a force stop.
if (force) {
- Slog.i(TAG,
+ Slogf.i(TAG,
"Force stop user " + userId + ". Related users will not be stopped");
stopSingleUserLU(userId, allowDelayedLocking, stopUserCallback,
keyEvictedCallback);
@@ -876,7 +877,7 @@
return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
}
}
- if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked usersToStop=" + Arrays.toString(usersToStop));
+ if (DEBUG_MU) Slogf.i(TAG, "stopUsersLocked usersToStop=" + Arrays.toString(usersToStop));
for (int userIdToStop : usersToStop) {
stopSingleUserLU(userIdToStop, allowDelayedLocking,
userIdToStop == userId ? stopUserCallback : null,
@@ -906,7 +907,7 @@
private void stopSingleUserLU(final int userId, boolean allowDelayedLocking,
final IStopUserCallback stopUserCallback,
KeyEvictedCallback keyEvictedCallback) {
- if (DEBUG_MU) Slog.i(TAG, "stopSingleUserLocked userId=" + userId);
+ if (DEBUG_MU) Slogf.i(TAG, "stopSingleUserLocked userId=" + userId);
final UserState uss = mStartedUsers.get(userId);
if (uss == null) { // User is not started
// If mDelayUserDataLocking is set and allowDelayedLocking is not set, we need to lock
@@ -917,7 +918,7 @@
// and no further action is necessary.
if (mDelayUserDataLocking) {
if (allowDelayedLocking && keyEvictedCallback != null) {
- Slog.wtf(TAG, "allowDelayedLocking set with KeyEvictedCallback, ignore it"
+ Slogf.wtf(TAG, "allowDelayedLocking set with KeyEvictedCallback, ignore it"
+ " and lock user:" + userId, new RuntimeException());
allowDelayedLocking = false;
}
@@ -1043,7 +1044,7 @@
void finishUserStopped(UserState uss, boolean allowDelayedLocking) {
final int userId = uss.mHandle.getIdentifier();
if (DEBUG_MU) {
- Slog.i(TAG, "finishUserStopped(%d): allowDelayedLocking=%b", userId,
+ Slogf.i(TAG, "finishUserStopped(%d): allowDelayedLocking=%b", userId,
allowDelayedLocking);
}
@@ -1067,7 +1068,7 @@
mUserLru.remove(Integer.valueOf(userId));
updateStartedUserArrayLU();
if (allowDelayedLocking && !keyEvictedCallbacks.isEmpty()) {
- Slog.wtf(TAG,
+ Slogf.wtf(TAG,
"Delayed locking enabled while KeyEvictedCallbacks not empty, userId:"
+ userId + " callbacks:" + keyEvictedCallbacks);
allowDelayedLocking = false;
@@ -1118,7 +1119,7 @@
FgThread.getHandler().post(() -> {
synchronized (mLock) {
if (mStartedUsers.get(userId) != null) {
- Slog.w(TAG, "User was restarted, skipping key eviction");
+ Slogf.w(TAG, "User was restarted, skipping key eviction");
return;
}
}
@@ -1156,10 +1157,10 @@
if (totalUnlockedUsers > mMaxRunningUsers) { // should lock a user
userIdToLock = mLastActiveUsers.get(mLastActiveUsers.size() - 1);
mLastActiveUsers.remove(mLastActiveUsers.size() - 1);
- Slog.i(TAG, "finishUserStopped, stopping user:" + userId
+ Slogf.i(TAG, "finishUserStopped, stopping user:" + userId
+ " lock user:" + userIdToLock);
} else {
- Slog.i(TAG, "finishUserStopped, user:" + userId + ", skip locking");
+ Slogf.i(TAG, "finishUserStopped, user:" + userId + ", skip locking");
// do not lock
userIdToLock = UserHandle.USER_NULL;
}
@@ -1196,7 +1197,7 @@
}
private void forceStopUser(@UserIdInt int userId, String reason) {
- if (DEBUG_MU) Slog.i(TAG, "forceStopUser(%d): %s", userId, reason);
+ if (DEBUG_MU) Slogf.i(TAG, "forceStopUser(%d): %s", userId, reason);
mInjector.activityManagerForceStopPackage(userId, reason);
if (mInjector.getUserManager().isPreCreated(userId)) {
// Don't fire intent for precreated.
@@ -1227,7 +1228,7 @@
* Stops the guest or ephemeral user if it has gone to the background.
*/
private void stopGuestOrEphemeralUserIfBackground(int oldUserId) {
- if (DEBUG_MU) Slog.i(TAG, "Stop guest or ephemeral user if background: " + oldUserId);
+ if (DEBUG_MU) Slogf.i(TAG, "Stop guest or ephemeral user if background: " + oldUserId);
synchronized(mLock) {
UserState oldUss = mStartedUsers.get(oldUserId);
if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId || oldUss == null
@@ -1265,7 +1266,7 @@
void startProfiles() {
int currentUserId = getCurrentUserId();
- if (DEBUG_MU) Slog.i(TAG, "startProfilesLocked");
+ if (DEBUG_MU) Slogf.i(TAG, "startProfilesLocked");
List<UserInfo> profiles = mInjector.getUserManager().getProfiles(
currentUserId, false /* enabledOnly */);
List<UserInfo> profilesToStart = new ArrayList<>(profiles.size());
@@ -1281,7 +1282,7 @@
startUser(profilesToStart.get(i).id, /* foreground= */ false);
}
if (i < profilesToStartSize) {
- Slog.w(TAG, "More profiles than MAX_RUNNING_USERS");
+ Slogf.w(TAG, "More profiles than MAX_RUNNING_USERS");
}
}
@@ -1309,7 +1310,7 @@
}
if (!userInfo.isEnabled()) {
- Slog.w(TAG, "Cannot start disabled profile #" + userId);
+ Slogf.w(TAG, "Cannot start disabled profile #" + userId);
return false;
}
@@ -1375,7 +1376,9 @@
private boolean startUserInternal(@UserIdInt int userId, boolean foreground,
@Nullable IProgressListener unlockListener, @NonNull TimingsTraceAndSlog t) {
- if (DEBUG_MU) Slog.i(TAG, "Starting user %d%s", userId, foreground ? " in foreground" : "");
+ if (DEBUG_MU) {
+ Slogf.i(TAG, "Starting user %d%s", userId, foreground ? " in foreground" : "");
+ }
EventLog.writeEvent(EventLogTags.UC_START_USER_INTERNAL, userId);
final int callingUid = Binder.getCallingUid();
@@ -1387,7 +1390,7 @@
if (oldUserId == userId) {
final UserState state = getStartedUserState(userId);
if (state == null) {
- Slog.wtf(TAG, "Current user has no UserState");
+ Slogf.wtf(TAG, "Current user has no UserState");
// continue starting.
} else {
if (userId == UserHandle.USER_SYSTEM && state.state == STATE_BOOTING) {
@@ -1417,16 +1420,16 @@
t.traceEnd();
if (userInfo == null) {
- Slog.w(TAG, "No user info for user #" + userId);
+ Slogf.w(TAG, "No user info for user #" + userId);
return false;
}
if (foreground && userInfo.isProfile()) {
- Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
+ Slogf.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
return false;
}
if (foreground && userInfo.preCreated) {
- Slog.w(TAG, "Cannot start pre-created user #" + userId + " as foreground");
+ Slogf.w(TAG, "Cannot start pre-created user #" + userId + " as foreground");
return false;
}
@@ -1454,7 +1457,7 @@
needStart = true;
updateUmState = true;
} else if (uss.state == UserState.STATE_SHUTDOWN && !isCallingOnHandlerThread()) {
- Slog.i(TAG, "User #" + userId
+ Slogf.i(TAG, "User #" + userId
+ " is shutting down - will start after full stop");
mHandler.post(() -> startUser(userId, foreground, unlockListener));
t.traceEnd(); // updateStartedUserArrayStarting
@@ -1663,7 +1666,7 @@
// We always want to unlock user storage, even user is not started yet
storageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
} catch (RemoteException | RuntimeException e) {
- Slog.w(TAG, "Failed to unlock: " + e.getMessage());
+ Slogf.w(TAG, "Failed to unlock: " + e.getMessage());
}
}
synchronized (mLock) {
@@ -1699,7 +1702,7 @@
for (int testUserId : userIds) {
final UserInfo parent = mInjector.getUserManager().getProfileParent(testUserId);
if (parent != null && parent.id == userId && testUserId != userId) {
- Slog.d(TAG, "User " + testUserId + " (parent " + parent.id
+ Slogf.d(TAG, "User " + testUserId + " (parent " + parent.id
+ "): attempting unlock because parent was just unlocked");
maybeUnlockUser(testUserId);
}
@@ -1714,25 +1717,25 @@
int currentUserId = getCurrentUserId();
UserInfo targetUserInfo = getUserInfo(targetUserId);
if (targetUserId == currentUserId) {
- Slog.i(TAG, "user #" + targetUserId + " is already the current user");
+ Slogf.i(TAG, "user #" + targetUserId + " is already the current user");
return true;
}
if (targetUserInfo == null) {
- Slog.w(TAG, "No user info for user #" + targetUserId);
+ Slogf.w(TAG, "No user info for user #" + targetUserId);
return false;
}
if (!targetUserInfo.supportsSwitchTo()) {
- Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
+ Slogf.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
return false;
}
if (targetUserInfo.isProfile()) {
- Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
+ Slogf.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
return false;
}
boolean userSwitchUiEnabled;
synchronized (mLock) {
if (!mInitialized) {
- Slog.e(TAG, "Cannot switch to User #" + targetUserId
+ Slogf.e(TAG, "Cannot switch to User #" + targetUserId
+ ": UserController not ready yet");
return false;
}
@@ -1809,13 +1812,13 @@
boolean disallowRunInBg = hasRestriction || shouldStopBackgroundUsersOnSwitch();
if (!disallowRunInBg) {
if (DEBUG_MU) {
- Slog.i(TAG, "stopBackgroundUsersIfEnforced() NOT stopping %d and related users",
- oldUserId);
+ Slogf.i(TAG, "stopBackgroundUsersIfEnforced() NOT stopping %d and related "
+ + "users", oldUserId);
}
return;
}
if (DEBUG_MU) {
- Slog.i(TAG, "stopBackgroundUsersIfEnforced() stopping %d and related users",
+ Slogf.i(TAG, "stopBackgroundUsersIfEnforced() stopping %d and related users",
oldUserId);
}
stopUsersLU(oldUserId, /* force= */ false, /* allowDelayedLocking= */ true,
@@ -1825,7 +1828,7 @@
private void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
synchronized (mLock) {
- Slog.e(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
+ Slogf.e(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
mTimeoutUserSwitchCallbacks = mCurWaitingUserSwitchCallbacks;
mHandler.removeMessages(USER_SWITCH_CALLBACKS_TIMEOUT_MSG);
sendContinueUserSwitchLU(uss, oldUserId, newUserId);
@@ -1838,7 +1841,7 @@
private void timeoutUserSwitchCallbacks(int oldUserId, int newUserId) {
synchronized (mLock) {
if (mTimeoutUserSwitchCallbacks != null && !mTimeoutUserSwitchCallbacks.isEmpty()) {
- Slog.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId
+ Slogf.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId
+ ". Observers that didn't respond: " + mTimeoutUserSwitchCallbacks);
mTimeoutUserSwitchCallbacks = null;
}
@@ -1870,10 +1873,10 @@
synchronized (mLock) {
long delay = SystemClock.elapsedRealtime() - dispatchStartedTime;
if (delay > USER_SWITCH_TIMEOUT_MS) {
- Slog.e(TAG, "User switch timeout: observer " + name
+ Slogf.e(TAG, "User switch timeout: observer " + name
+ " sent result after " + delay + " ms");
} else if (delay > USER_SWITCH_WARNING_TIMEOUT_MS) {
- Slog.w(TAG, "User switch slowed down by observer " + name
+ Slogf.w(TAG, "User switch slowed down by observer " + name
+ ": result sent after " + delay + " ms");
}
@@ -2091,7 +2094,7 @@
}
}
String msg = builder.toString();
- Slog.w(TAG, msg);
+ Slogf.w(TAG, msg);
throw new SecurityException(msg);
}
}
@@ -2318,7 +2321,7 @@
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + INTERACT_ACROSS_USERS;
- Slog.w(TAG, msg);
+ Slogf.w(TAG, msg);
throw new SecurityException(msg);
}
}
@@ -2421,7 +2424,7 @@
+ "() from pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + permission;
- Slog.w(TAG, msg);
+ Slogf.w(TAG, msg);
throw new SecurityException(msg);
}
}
@@ -2732,7 +2735,7 @@
* journey so no need to create a new journey for user start.
*/
if (DEBUG_MU) {
- Slog.d(TAG, journey + " not logged as it is expected to be part of "
+ Slogf.d(TAG, journey + " not logged as it is expected to be part of "
+ userJourneySession.mJourney);
}
return;
@@ -2755,7 +2758,7 @@
}
if (DEBUG_MU) {
- Slog.d(TAG,
+ Slogf.d(TAG,
"Starting a new journey: " + journey + " with session id: " + newSessionId);
}
@@ -2787,7 +2790,7 @@
synchronized (mUserIdToUserJourneyMap) {
final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(userId);
if (userJourneySession == null || userJourneySession.mSessionId == INVALID_SESSION_ID) {
- Slog.w(TAG, "UserLifecycleEvent " + event
+ Slogf.w(TAG, "UserLifecycleEvent " + event
+ " received without an active userJourneySession.");
return;
}
@@ -2870,13 +2873,13 @@
private volatile long mUnlockStarted;
@Override
public void onStarted(int id, Bundle extras) throws RemoteException {
- Slog.d(TAG, "Started unlocking user " + id);
+ Slogf.d(TAG, "Started unlocking user " + id);
mUnlockStarted = SystemClock.uptimeMillis();
}
@Override
public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
- Slog.d(TAG, "Unlocking user " + id + " progress " + progress);
+ Slogf.d(TAG, "Unlocking user " + id + " progress " + progress);
}
@Override
@@ -3061,7 +3064,7 @@
// config_customUserSwitchUi is set to true on Automotive as CarSystemUI is
// responsible to show the UI; OEMs should not change that, but if they do, we
// should at least warn the user...
- Slog.w(TAG, "Showing user switch dialog on UserController, it could cause a race "
+ Slogf.w(TAG, "Showing user switch dialog on UserController, it could cause a race "
+ "condition if it's shown by CarSystemUI as well");
}
final Dialog d = new UserSwitchingDialog(mService, mService.mContext, fromUser,
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 2bc81cb..d25896c6 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -31,6 +31,7 @@
import android.app.UriGrantsManager;
import android.content.ClipData;
import android.content.ClipDescription;
+import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -220,8 +221,6 @@
SystemProperties.getBoolean("ro.boot.qemu", false);
// DeviceConfig properties
- private static final String PROPERTY_SHOW_ACCESS_NOTIFICATIONS = "show_access_notifications";
- private static final boolean DEFAULT_SHOW_ACCESS_NOTIFICATIONS = true;
private static final String PROPERTY_MAX_CLASSIFICATION_LENGTH = "max_classification_length";
private static final int DEFAULT_MAX_CLASSIFICATION_LENGTH = 400;
@@ -242,7 +241,8 @@
private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
@GuardedBy("mLock")
- private boolean mShowAccessNotifications = DEFAULT_SHOW_ACCESS_NOTIFICATIONS;
+ private boolean mShowAccessNotifications =
+ ClipboardManager.DEVICE_CONFIG_DEFAULT_SHOW_ACCESS_NOTIFICATIONS;
@GuardedBy("mLock")
private int mMaxClassificationLength = DEFAULT_MAX_CLASSIFICATION_LENGTH;
@@ -310,8 +310,10 @@
private void updateConfig() {
synchronized (mLock) {
- mShowAccessNotifications = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CLIPBOARD,
- PROPERTY_SHOW_ACCESS_NOTIFICATIONS, DEFAULT_SHOW_ACCESS_NOTIFICATIONS);
+ mShowAccessNotifications = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CLIPBOARD,
+ ClipboardManager.DEVICE_CONFIG_SHOW_ACCESS_NOTIFICATIONS,
+ ClipboardManager.DEVICE_CONFIG_DEFAULT_SHOW_ACCESS_NOTIFICATIONS);
mMaxClassificationLength = DeviceConfig.getInt(DeviceConfig.NAMESPACE_CLIPBOARD,
PROPERTY_MAX_CLASSIFICATION_LENGTH, DEFAULT_MAX_CLASSIFICATION_LENGTH);
}
@@ -1056,11 +1058,9 @@
if (clipboard.primaryClip == null) {
return;
}
- if (!mShowAccessNotifications) {
- return;
- }
if (Settings.Secure.getInt(getContext().getContentResolver(),
- Settings.Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS, 1) == 0) {
+ Settings.Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS,
+ (mShowAccessNotifications ? 1 : 0)) == 0) {
return;
}
// Don't notify if the app accessing the clipboard is the same as the current owner.
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index ffeb77d..cf4fe1e 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -420,7 +420,7 @@
/*
* Tell the VMs to toss their DNS caches
*/
- final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
+ final Intent intent = new Intent(ConnectivityManager.ACTION_CLEAR_DNS_CACHE);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
/*
* Connectivity events can happen before boot has completed ...
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 1786a51..614e488 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -268,10 +268,6 @@
private final SyncLogger mLogger;
- // NOTE: this is a temporary allow-list for testing purposes; it will be removed before release.
- private final String[] mEjSyncAllowedPackages = new String[]{
- "com.google.android.google", "com.android.frameworks.servicestests"};
-
private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
for (JobInfo job: pendingJobs) {
if (job.getId() == jobId) {
@@ -991,14 +987,6 @@
}
}
- final boolean scheduleAsEj =
- extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
- // NOTE: this is a temporary check for internal testing - to be removed before release.
- if (scheduleAsEj && !ArrayUtils.contains(mEjSyncAllowedPackages, callingPackage)) {
- throw new IllegalArgumentException(
- callingPackage + " is not allowed to schedule a sync as an EJ yet.");
- }
-
for (AccountAndUser account : accounts) {
// If userId is specified, do not sync accounts of other users
if (userId >= UserHandle.USER_SYSTEM && account.userId >= UserHandle.USER_SYSTEM
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 10f6948f..919d25c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -258,18 +258,6 @@
return super.handleUserControlPressed(message);
}
- @Override
- protected void wakeUpIfActiveSource() {
- if (!isActiveSource()) {
- return;
- }
- // Wake up the device if the power is in standby mode, or its screen is off -
- // which can happen if the device is holding a partial lock.
- if (mService.isPowerStandbyOrTransient() || !mService.getPowerManager().isScreenOn()) {
- mService.wakeUp();
- }
- }
-
@ServiceThreadOnly
@Constants.HandleMessageResult
protected int handleSetMenuLanguage(HdmiCecMessage message) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 979a1d4..c001c40 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -292,7 +292,6 @@
// Only source devices that react to routing control messages should implement
// this method (e.g. a TV with built in switch).
- // TODO(): decide which type will handle the routing when multi device type is supported
protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
// do nothing
}
@@ -372,7 +371,7 @@
if (!isActiveSource()) {
return;
}
- // Wake up the device
+ // Wake up the device. This will also exit dream mode.
mService.wakeUp();
return;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 03fb3a4..acfeb6c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -713,7 +713,9 @@
assertRunOnServiceThread();
if (!mService.isPowerStandbyOrTransient()) {
addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
- if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
+ if (!isDirectConnectAddress(avr.getPhysicalAddress())) {
+ startArcAction(false);
+ } else if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
&& !hasAction(SetArcTransmissionStateAction.class)) {
startArcAction(true);
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 71a5d1c..6b28fbc 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.READ_CONTACTS;
+import static android.Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.UserHandle.USER_ALL;
@@ -160,6 +161,7 @@
import java.util.Objects;
import java.util.Random;
import java.util.Set;
+import java.util.StringJoiner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -1074,6 +1076,10 @@
mContext.enforceCallingOrSelfPermission(BIOMETRIC_PERMISSION, "LockSettingsBiometric");
}
+ private boolean hasPermission(String permission) {
+ return mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
+ }
+
@Override
public boolean hasSecureLockScreen() {
return mHasSecureLockScreen;
@@ -1567,42 +1573,52 @@
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature");
}
- checkWritePermission(userId);
- enforceFrpResolved();
+ if (!hasPermission(PERMISSION) && !hasPermission(SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS)) {
+ throw new SecurityException(
+ "setLockCredential requires SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS or "
+ + PERMISSION);
+ }
- // When changing credential for profiles with unified challenge, some callers
- // will pass in empty credential while others will pass in the credential of
- // the parent user. setLockCredentialInternal() handles the formal case (empty
- // credential) correctly but not the latter. As a stopgap fix, convert the latter
- // case to the formal. The long-term fix would be fixing LSS such that it should
- // accept only the parent user credential on its public API interfaces, swap it
- // with the profile's random credential at that API boundary (i.e. here) and make
- // sure LSS internally does not special case profile with unififed challenge: b/80170828.
- if (!savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
- // Verify the parent credential again, to make sure we have a fresh enough
- // auth token such that getDecryptedPasswordForTiedProfile() inside
- // setLockCredentialInternal() can function correctly.
- verifyCredential(savedCredential, mUserManager.getProfileParent(userId).id,
- 0 /* flags */);
- savedCredential.zeroize();
- savedCredential = LockscreenCredential.createNone();
- }
- synchronized (mSeparateChallengeLock) {
- if (!setLockCredentialInternal(credential, savedCredential,
- userId, /* isLockTiedToParent= */ false)) {
- scheduleGc();
- return false;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ enforceFrpResolved();
+ // When changing credential for profiles with unified challenge, some callers
+ // will pass in empty credential while others will pass in the credential of
+ // the parent user. setLockCredentialInternal() handles the formal case (empty
+ // credential) correctly but not the latter. As a stopgap fix, convert the latter
+ // case to the formal. The long-term fix would be fixing LSS such that it should
+ // accept only the parent user credential on its public API interfaces, swap it
+ // with the profile's random credential at that API boundary (i.e. here) and make
+ // sure LSS internally does not special case profile with unififed challenge: b/80170828
+ if (!savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
+ // Verify the parent credential again, to make sure we have a fresh enough
+ // auth token such that getDecryptedPasswordForTiedProfile() inside
+ // setLockCredentialInternal() can function correctly.
+ verifyCredential(savedCredential, mUserManager.getProfileParent(userId).id,
+ 0 /* flags */);
+ savedCredential.zeroize();
+ savedCredential = LockscreenCredential.createNone();
}
- setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
- notifyPasswordChanged(userId);
+ synchronized (mSeparateChallengeLock) {
+ if (!setLockCredentialInternal(credential, savedCredential,
+ userId, /* isLockTiedToParent= */ false)) {
+ scheduleGc();
+ return false;
+ }
+ setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
+ notifyPasswordChanged(userId);
+ }
+ if (mUserManager.getUserInfo(userId).isManagedProfile()) {
+ // Make sure the profile doesn't get locked straight after setting work challenge.
+ setDeviceUnlockedForUser(userId);
+ }
+ notifySeparateProfileChallengeChanged(userId);
+ onPostPasswordChanged(credential, userId);
+ scheduleGc();
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- if (mUserManager.getUserInfo(userId).isManagedProfile()) {
- // Make sure the profile doesn't get locked straight after setting work challenge.
- setDeviceUnlockedForUser(userId);
- }
- notifySeparateProfileChallengeChanged(userId);
- scheduleGc();
- return true;
}
/**
@@ -1703,10 +1719,157 @@
return true;
}
+ private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) {
+ updateEncryptionPasswordIfNeeded(newCredential, userHandle);
+ if (newCredential.isPattern()) {
+ setBoolean(LockPatternUtils.PATTERN_EVER_CHOSEN_KEY, true, userHandle);
+ }
+ updatePasswordHistory(newCredential, userHandle);
+ mContext.getSystemService(TrustManager.class).reportEnabledTrustAgentsChanged(userHandle);
+ }
+
+ /**
+ * Update device encryption password if calling user is USER_SYSTEM and device supports
+ * encryption.
+ */
+ private void updateEncryptionPasswordIfNeeded(LockscreenCredential credential, int userHandle) {
+ // Update the device encryption password.
+ if (userHandle != UserHandle.USER_SYSTEM || !isDeviceEncryptionEnabled()) {
+ return;
+ }
+ if (!shouldEncryptWithCredentials()) {
+ updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+ return;
+ }
+ if (credential.isNone()) {
+ // Set the encryption password to default.
+ setCredentialRequiredToDecrypt(false);
+ }
+ updateEncryptionPassword(credential.getStorageCryptType(), credential.getCredential());
+ }
+
+ /**
+ * Store the hash of the *current* password in the password history list, if device policy
+ * enforces password history requirement.
+ */
+ private void updatePasswordHistory(LockscreenCredential password, int userHandle) {
+ if (password.isNone()) {
+ return;
+ }
+ if (password.isPattern()) {
+ // Do not keep track of historical patterns
+ return;
+ }
+ // Add the password to the password history. We assume all
+ // password hashes have the same length for simplicity of implementation.
+ String passwordHistory = getString(
+ LockPatternUtils.PASSWORD_HISTORY_KEY, /* defaultValue= */ null, userHandle);
+ if (passwordHistory == null) {
+ passwordHistory = "";
+ }
+ int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
+ if (passwordHistoryLength == 0) {
+ passwordHistory = "";
+ } else {
+ final byte[] hashFactor = getHashFactor(password, userHandle);
+ final byte[] salt = getSalt(userHandle).getBytes();
+ String hash = password.passwordToHistoryHash(hashFactor, salt);
+ if (hash == null) {
+ Slog.e(TAG, "Compute new style password hash failed, fallback to legacy style");
+ hash = password.legacyPasswordToHash(salt);
+ }
+ if (TextUtils.isEmpty(passwordHistory)) {
+ passwordHistory = hash;
+ } else {
+ String[] history = passwordHistory.split(
+ LockPatternUtils.PASSWORD_HISTORY_DELIMITER);
+ StringJoiner joiner = new StringJoiner(LockPatternUtils.PASSWORD_HISTORY_DELIMITER);
+ joiner.add(hash);
+ for (int i = 0; i < passwordHistoryLength - 1 && i < history.length; i++) {
+ joiner.add(history[i]);
+ }
+ passwordHistory = joiner.toString();
+ }
+ }
+ setString(LockPatternUtils.PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
+ }
+
+ private String getSalt(int userId) {
+ long salt = getLong(LockPatternUtils.LOCK_PASSWORD_SALT_KEY, 0, userId);
+ if (salt == 0) {
+ try {
+ salt = SecureRandom.getInstance("SHA1PRNG").nextLong();
+ setLong(LockPatternUtils.LOCK_PASSWORD_SALT_KEY, salt, userId);
+ Slog.v(TAG, "Initialized lock password salt for user: " + userId);
+ } catch (NoSuchAlgorithmException e) {
+ // Throw an exception rather than storing a password we'll never be able to recover
+ throw new IllegalStateException("Couldn't get SecureRandom number", e);
+ }
+ }
+ return Long.toHexString(salt);
+ }
+
+ private int getRequestedPasswordHistoryLength(int userId) {
+ return mInjector.getDevicePolicyManager().getPasswordHistoryLength(null, userId);
+ }
+
+ private static boolean isDeviceEncryptionEnabled() {
+ return StorageManager.isEncrypted();
+ }
+
+ private boolean shouldEncryptWithCredentials() {
+ return isCredentialRequiredToDecrypt() && !isDoNotAskCredentialsOnBootSet();
+ }
+
+ private boolean isDoNotAskCredentialsOnBootSet() {
+ return mInjector.getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
+ }
+
+ private boolean isCredentialRequiredToDecrypt() {
+ final int value = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, -1);
+ return value != 0;
+ }
+
private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse);
}
+ private void setCredentialRequiredToDecrypt(boolean required) {
+ if (isDeviceEncryptionEnabled()) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
+ }
+ }
+
+ /** Update the encryption password if it is enabled **/
+ @Override
+ public void updateEncryptionPassword(final int type, final byte[] password) {
+ if (!hasSecureLockScreen() && password != null && password.length != 0) {
+ throw new UnsupportedOperationException(
+ "This operation requires the lock screen feature.");
+ }
+ if (!isDeviceEncryptionEnabled()) {
+ return;
+ }
+ final IBinder service = ServiceManager.getService("mount");
+ if (service == null) {
+ Slog.e(TAG, "Could not find the mount service to update the encryption password");
+ return;
+ }
+
+ // TODO(b/120484642): This is a location where we still use a String for vold
+ String passwordString = password != null ? new String(password) : null;
+ mHandler.post(() -> {
+ IStorageManager storageManager = mInjector.getStorageManager();
+ try {
+ storageManager.changeEncryptionPassword(type, passwordString);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error changing encryption password", e);
+ }
+ });
+ }
+
@VisibleForTesting /** Note: this method is overridden in unit tests */
protected void tieProfileLockToParent(int userId, LockscreenCredential password) {
if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
@@ -1952,10 +2115,16 @@
@Nullable
public VerifyCredentialResponse verifyCredential(LockscreenCredential credential,
int userId, int flags) {
- checkPasswordReadPermission();
+ if (!hasPermission(PERMISSION) && !hasPermission(SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS)) {
+ throw new SecurityException(
+ "verifyCredential requires SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS or "
+ + PERMISSION);
+ }
+ final long identity = Binder.clearCallingIdentity();
try {
return doVerifyCredential(credential, userId, null /* progressCallback */, flags);
} finally {
+ Binder.restoreCallingIdentity(identity);
scheduleGc();
}
}
@@ -3436,8 +3605,12 @@
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
- return LockSettingsService.this.setLockCredentialWithToken(
- credential, tokenHandle, token, userId);
+ if (!LockSettingsService.this.setLockCredentialWithToken(
+ credential, tokenHandle, token, userId)) {
+ return false;
+ }
+ onPostPasswordChanged(credential, userId);
+ return true;
}
@Override
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 5286bce..ba1e23c 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,7 +16,9 @@
package com.android.server.media;
-import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+import static android.content.Intent.ACTION_SCREEN_OFF;
+import static android.content.Intent.ACTION_SCREEN_ON;
import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
import static android.media.MediaRouter2Utils.getOriginalId;
import static android.media.MediaRouter2Utils.getProviderId;
@@ -26,7 +28,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.IMediaRouter2;
import android.media.IMediaRouter2Manager;
@@ -41,6 +46,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -62,6 +68,7 @@
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
/**
* Implements features related to {@link android.media.MediaRouter2} and
@@ -74,12 +81,13 @@
// TODO: (In Android S or later) if we add callback methods for generic failures
// in MediaRouter2, remove this constant and replace the usages with the real request IDs.
private static final long DUMMY_REQUEST_ID = -1;
- private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND;
+ private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND_SERVICE;
private final Context mContext;
private final Object mLock = new Object();
final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
final ActivityManager mActivityManager;
+ final PowerManager mPowerManager;
@GuardedBy("mLock")
private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
@@ -100,11 +108,32 @@
}
};
+ private final BroadcastReceiver mScreenOnOffReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mLock) {
+ final int count = mUserRecords.size();
+ for (int i = 0; i < count; i++) {
+ UserHandler userHandler = mUserRecords.valueAt(i).mHandler;
+ userHandler.sendMessage(PooledLambda.obtainMessage(
+ UserHandler::updateDiscoveryPreferenceOnHandler, userHandler));
+ }
+ }
+ }
+ };
+
MediaRouter2ServiceImpl(Context context) {
mContext = context;
mActivityManager = mContext.getSystemService(ActivityManager.class);
mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener,
PACKAGE_IMPORTANCE_FOR_DISCOVERY);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+
+ IntentFilter screenOnOffIntentFilter = new IntentFilter();
+ screenOnOffIntentFilter.addAction(ACTION_SCREEN_ON);
+ screenOnOffIntentFilter.addAction(ACTION_SCREEN_OFF);
+
+ mContext.registerReceiver(mScreenOnOffReceiver, screenOnOffIntentFilter);
}
////////////////////////////////////////////////////////////////
@@ -2121,19 +2150,26 @@
if (service == null) {
return;
}
- List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>();
+ List<RouteDiscoveryPreference> discoveryPreferences = Collections.emptyList();
List<RouterRecord> routerRecords = getRouterRecords();
List<ManagerRecord> managerRecords = getManagerRecords();
- boolean isAnyManagerScanning =
- managerRecords.stream().anyMatch(manager -> manager.mIsScanning
- && service.mActivityManager.getPackageImportance(manager.mPackageName)
- <= PACKAGE_IMPORTANCE_FOR_DISCOVERY);
- for (RouterRecord routerRecord : routerRecords) {
- if (isAnyManagerScanning
- || service.mActivityManager.getPackageImportance(routerRecord.mPackageName)
- <= PACKAGE_IMPORTANCE_FOR_DISCOVERY) {
- discoveryPreferences.add(routerRecord.mDiscoveryPreference);
+ if (service.mPowerManager.isInteractive()) {
+ boolean isManagerScanning = managerRecords.stream().anyMatch(manager ->
+ manager.mIsScanning && service.mActivityManager
+ .getPackageImportance(manager.mPackageName)
+ <= PACKAGE_IMPORTANCE_FOR_DISCOVERY);
+
+ if (isManagerScanning) {
+ discoveryPreferences = routerRecords.stream()
+ .map(record -> record.mDiscoveryPreference)
+ .collect(Collectors.toList());
+ } else {
+ discoveryPreferences = routerRecords.stream().filter(record ->
+ service.mActivityManager.getPackageImportance(record.mPackageName)
+ <= PACKAGE_IMPORTANCE_FOR_DISCOVERY)
+ .map(record -> record.mDiscoveryPreference)
+ .collect(Collectors.toList());
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 352eac3..05922b3 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -926,10 +926,11 @@
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
try {
- // TODO: There shouldn't be a need to receive callback for all changes.
- mActivityManager.registerUidObserver(mUidObserver,
- ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE,
- ActivityManager.PROCESS_STATE_UNKNOWN, "android");
+ final int changes = ActivityManager.UID_OBSERVER_PROCSTATE
+ | ActivityManager.UID_OBSERVER_GONE
+ | ActivityManager.UID_OBSERVER_CAPABILITY;
+ mActivityManager.registerUidObserver(mUidObserver, changes,
+ NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE, "android");
mNetworkManager.registerObserver(mAlertObserver);
} catch (RemoteException e) {
// ignored; both services live in system_server
@@ -5889,7 +5890,8 @@
return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
}
- private class UidBlockedState {
+ @VisibleForTesting
+ static final class UidBlockedState {
public int blockedReasons;
public int allowedReasons;
public int effectiveBlockedReasons;
@@ -5901,19 +5903,29 @@
}
void updateEffectiveBlockedReasons() {
- effectiveBlockedReasons = blockedReasons;
+ if (LOGV && blockedReasons == BLOCKED_REASON_NONE) {
+ Log.v(TAG, "updateEffectiveBlockedReasons(): no blocked reasons");
+ }
+ effectiveBlockedReasons = getEffectiveBlockedReasons(blockedReasons, allowedReasons);
+ if (LOGV) {
+ Log.v(TAG, "updateEffectiveBlockedReasons()"
+ + ": blockedReasons=" + Integer.toBinaryString(blockedReasons)
+ + ", effectiveReasons=" + Integer.toBinaryString(effectiveBlockedReasons));
+ }
+ }
+
+ @VisibleForTesting
+ static int getEffectiveBlockedReasons(int blockedReasons, int allowedReasons) {
+ int effectiveBlockedReasons = blockedReasons;
// If the uid is not subject to any blocked reasons, then return early
if (blockedReasons == BLOCKED_REASON_NONE) {
- if (LOGV) {
- Log.v(TAG, "updateEffectiveBlockedReasons(): no blocked reasons");
- }
- return;
+ return effectiveBlockedReasons;
}
if ((allowedReasons & ALLOWED_REASON_SYSTEM) != 0) {
- effectiveBlockedReasons = (blockedReasons & ALLOWED_METERED_REASON_MASK);
+ effectiveBlockedReasons &= ALLOWED_METERED_REASON_MASK;
}
if ((allowedReasons & ALLOWED_METERED_REASON_SYSTEM) != 0) {
- effectiveBlockedReasons = (blockedReasons & ~ALLOWED_METERED_REASON_MASK);
+ effectiveBlockedReasons &= ~ALLOWED_METERED_REASON_MASK;
}
if ((allowedReasons & ALLOWED_REASON_FOREGROUND) != 0) {
effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
@@ -5939,11 +5951,7 @@
if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) {
effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER;
}
- if (LOGV) {
- Log.v(TAG, "updateEffectiveBlockedReasons()"
- + ": blockedReasons=" + Integer.toBinaryString(blockedReasons)
- + ", effectiveReasons=" + Integer.toBinaryString(effectiveBlockedReasons));
- }
+ return effectiveBlockedReasons;
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6dcf39b..2f4cbd5 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -685,6 +685,21 @@
}
}
}
+
+ // Remove notifications with the specified user & channel ID.
+ public void removeChannelNotifications(String pkg, @UserIdInt int userId,
+ String channelId) {
+ for (int i = 0; i < mBuffer.size(); i++) {
+ final Pair<StatusBarNotification, Integer> pair = mBuffer.get(i);
+ if (pair.first != null
+ && userId == pair.first.getNormalizedUserId()
+ && pkg != null && pkg.equals(pair.first.getPackageName())
+ && pair.first.getNotification() != null
+ && Objects.equals(channelId, pair.first.getNotification().getChannelId())) {
+ mBuffer.remove(i);
+ }
+ }
+ }
}
void loadDefaultApprovedServices(int userId) {
@@ -3623,6 +3638,8 @@
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
callingUser, REASON_CHANNEL_REMOVED, null);
mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
+ // Remove from both recent notification archive and notification history
+ mArchive.removeChannelNotifications(pkg, callingUser, channelId);
mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
mListeners.notifyNotificationChannelChanged(pkg,
UserHandle.getUserHandleForUid(callingUid),
@@ -8179,8 +8196,10 @@
summaries.remove(r.getSbn().getPackageName());
}
- // Save it for users of getHistoricalNotifications()
- mArchive.record(r.getSbn(), reason);
+ // Save it for users of getHistoricalNotifications(), unless the whole channel was deleted
+ if (reason != REASON_CHANNEL_REMOVED) {
+ mArchive.record(r.getSbn(), reason);
+ }
final long now = System.currentTimeMillis();
final LogMaker logMaker = r.getItemLogMaker()
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index f5d6489..1050835 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -27,6 +27,7 @@
import android.service.notification.IConditionProvider;
import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
+import android.util.Log;
import android.util.Slog;
import java.io.PrintWriter;
@@ -122,8 +123,11 @@
public static void traceSetNotificationPolicy(String pkg, int targetSdk,
NotificationManager.Policy policy) {
- append(TYPE_SET_NOTIFICATION_POLICY, "pkg=" + pkg + " targetSdk=" + targetSdk
- + " NotificationPolicy=" + policy.toString());
+ String policyLog = "pkg=" + pkg + " targetSdk=" + targetSdk
+ + " NotificationPolicy=" + policy.toString();
+ append(TYPE_SET_NOTIFICATION_POLICY, policyLog);
+ // TODO(b/180205791): remove when we can better surface apps that are changing policy
+ Log.d(TAG, "Zen Policy Changed: " + policyLog);
}
public static void traceSubscribe(Uri uri, IConditionProvider provider, RemoteException e) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 18c689f..fcee63c 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -586,19 +586,6 @@
}
private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
- if (isNew) {
- rule.id = ZenModeConfig.newRuleId();
- rule.creationTime = System.currentTimeMillis();
- rule.component = automaticZenRule.getOwner();
- rule.configurationActivity = automaticZenRule.getConfigurationActivity();
- rule.pkg = (rule.component != null)
- ? rule.component.getPackageName()
- : rule.configurationActivity.getPackageName();
- }
-
- if (rule.enabled != automaticZenRule.isEnabled()) {
- rule.snoozing = false;
- }
rule.name = automaticZenRule.getName();
rule.condition = null;
rule.conditionId = automaticZenRule.getConditionId();
@@ -607,6 +594,20 @@
rule.zenPolicy = automaticZenRule.getZenPolicy();
rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
+ rule.configurationActivity = automaticZenRule.getConfigurationActivity();
+
+ if (isNew) {
+ rule.id = ZenModeConfig.newRuleId();
+ rule.creationTime = System.currentTimeMillis();
+ rule.component = automaticZenRule.getOwner();
+ rule.pkg = (rule.component != null)
+ ? rule.component.getPackageName()
+ : rule.configurationActivity.getPackageName();
+ }
+
+ if (rule.enabled != automaticZenRule.isEnabled()) {
+ rule.snoozing = false;
+ }
}
protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index c236b4d..fa126a4 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -267,7 +267,7 @@
mArtStatsLogger,
sessionId,
compilerFilter,
- sharedGid,
+ pkg.getUid(),
packageStats.getCompileTime(path),
dexMetadataPath,
options.getCompilationReason(),
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4eafe51..e532790 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -948,14 +948,14 @@
== PackageManager.PERMISSION_GRANTED);
final int targetPackageUid = mPm.getPackageUid(packageName, 0, userId);
final boolean isUpdate = targetPackageUid != -1;
- final InstallSourceInfo installSourceInfo = isUpdate
+ final InstallSourceInfo existingInstallSourceInfo = isUpdate
? mPm.getInstallSourceInfo(packageName)
: null;
- final String installerPackageName = installSourceInfo != null
- ? installSourceInfo.getInstallingPackageName()
+ final String existingInstallerPackageName = existingInstallSourceInfo != null
+ ? existingInstallSourceInfo.getInstallingPackageName()
: null;
final boolean isInstallerOfRecord = isUpdate
- && Objects.equals(installerPackageName, getInstallerPackageName());
+ && Objects.equals(existingInstallerPackageName, getInstallerPackageName());
final boolean isSelfUpdate = targetPackageUid == mInstallerUid;
final boolean isPermissionGranted = isInstallPermissionGranted
|| (isUpdatePermissionGranted && isUpdate)
@@ -972,7 +972,7 @@
return USER_ACTION_NOT_NEEDED;
}
- if (mPm.isInstallDisabledForPackage(installerPackageName, mInstallerUid, userId)) {
+ if (mPm.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid, userId)) {
// show the installer to account for device poslicy or unknown sources use cases
return USER_ACTION_REQUIRED;
}
@@ -4157,7 +4157,7 @@
if (stageDir != null && !params.isStaged) {
try {
if (incrementalFileStorages != null) {
- incrementalFileStorages.cleanUp();
+ incrementalFileStorages.cleanUpAndMarkComplete();
}
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
@@ -4183,7 +4183,7 @@
}
try {
if (incrementalFileStorages != null) {
- incrementalFileStorages.cleanUp();
+ incrementalFileStorages.cleanUpAndMarkComplete();
}
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2dcc8d9..9477464 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5966,7 +5966,8 @@
backgroundHandler,
SYSTEM_PARTITIONS,
(i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
- (i, pm) -> PermissionManagerService.create(context),
+ (i, pm) -> PermissionManagerService.create(context,
+ i.getSystemConfig().getAvailableFeatures()),
(i, pm) -> new UserManagerService(context, pm,
new UserDataPreparer(installer, installLock, context, onlyCore),
lock),
@@ -12271,19 +12272,18 @@
public ArraySet<String> getOptimizablePackages() {
ArraySet<String> pkgs = new ArraySet<>();
- final boolean hibernationEnabled = AppHibernationService.isAppHibernationEnabled();
- AppHibernationManagerInternal appHibernationManager =
- mInjector.getLocalService(AppHibernationManagerInternal.class);
synchronized (mLock) {
for (AndroidPackage p : mPackages.values()) {
- // Checking hibernation state is an inexpensive call.
- boolean isHibernating = hibernationEnabled
- && appHibernationManager.isHibernatingGlobally(p.getPackageName());
- if (PackageDexOptimizer.canOptimizePackage(p) && !isHibernating) {
+ if (PackageDexOptimizer.canOptimizePackage(p)) {
pkgs.add(p.getPackageName());
}
}
}
+ if (AppHibernationService.isAppHibernationEnabled()) {
+ AppHibernationManagerInternal appHibernationManager =
+ mInjector.getLocalService(AppHibernationManagerInternal.class);
+ pkgs.removeIf(pkgName -> appHibernationManager.isHibernatingGlobally(pkgName));
+ }
return pkgs;
}
@@ -21456,6 +21456,8 @@
synchronized (mLock) {
if (outInfo != null) {
outInfo.uid = ps.appId;
+ outInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(ps,
+ allUserHandles, mSettings.getPackagesLocked());
}
}
@@ -23464,10 +23466,12 @@
}
}
if (shouldUnhibernate) {
- AppHibernationManagerInternal ah =
- mInjector.getLocalService(AppHibernationManagerInternal.class);
- ah.setHibernatingForUser(packageName, userId, false);
- ah.setHibernatingGlobally(packageName, false);
+ mHandler.post(() -> {
+ AppHibernationManagerInternal ah =
+ mInjector.getLocalService(AppHibernationManagerInternal.class);
+ ah.setHibernatingForUser(packageName, userId, false);
+ ah.setHibernatingGlobally(packageName, false);
+ });
}
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index ef37201..091d820 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -127,18 +127,12 @@
private static final Map<String, Integer> ISA_MAP = new HashMap();
static {
- COMPILE_FILTER_MAP.put("arm", ArtStatsLog.
- ART_DATUM_REPORTED__ISA__ART_ISA_ARM);
- COMPILE_FILTER_MAP.put("arm64", ArtStatsLog.
- ART_DATUM_REPORTED__ISA__ART_ISA_ARM64);
- COMPILE_FILTER_MAP.put("x86", ArtStatsLog.
- ART_DATUM_REPORTED__ISA__ART_ISA_X86);
- COMPILE_FILTER_MAP.put("x86_64", ArtStatsLog.
- ART_DATUM_REPORTED__ISA__ART_ISA_X86_64);
- COMPILE_FILTER_MAP.put("mips", ArtStatsLog.
- ART_DATUM_REPORTED__ISA__ART_ISA_MIPS);
- COMPILE_FILTER_MAP.put("mips64", ArtStatsLog.
- ART_DATUM_REPORTED__ISA__ART_ISA_MIPS64);
+ ISA_MAP.put("arm", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM);
+ ISA_MAP.put("arm64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM64);
+ ISA_MAP.put("x86", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86);
+ ISA_MAP.put("x86_64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86_64);
+ ISA_MAP.put("mips", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_MIPS);
+ ISA_MAP.put("mips64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_MIPS64);
}
public static void writeStatsLog(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 310ef23..2d1178a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -69,8 +69,10 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
+import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PermissionGroupInfoFlags;
import android.content.pm.PackageManager.PermissionInfoFlags;
@@ -85,7 +87,6 @@
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.metrics.LogMaker;
import android.os.AsyncTask;
-import android.content.AttributionSource;
import android.os.Binder;
import android.os.Build;
import android.os.Debug;
@@ -177,6 +178,10 @@
private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60);
+ // For automotive products, CarService enforces allow-listing of the privileged permissions
+ // com.android.car is the package name which declares auto specific permissions
+ private static final String CAR_PACKAGE_NAME = "com.android.car";
+
/** Cap the size of permission trees that 3rd party apps can define; in characters of text */
private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768;
/** Empty array to avoid allocations */
@@ -210,6 +215,10 @@
STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
}
+ /** Set of source package names for Privileged Permission Allowlist */
+ private final ArraySet<String> mPrivilegedPermissionAllowlistSourcePackageNames =
+ new ArraySet<>();
+
/** Lock to protect internal data access */
private final Object mLock = new Object();
@@ -356,7 +365,8 @@
}
};
- PermissionManagerService(@NonNull Context context) {
+ PermissionManagerService(@NonNull Context context,
+ @NonNull ArrayMap<String, FeatureInfo> availableFeatures) {
// The package info cache is the cache for package and permission information.
// Disable the package info and package permission caches locally but leave the
// checkPermission cache active.
@@ -368,6 +378,13 @@
mUserManagerInt = LocalServices.getService(UserManagerInternal.class);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
+ mPrivilegedPermissionAllowlistSourcePackageNames.add(PLATFORM_PACKAGE_NAME);
+ // PackageManager.hasSystemFeature() is not used here because PackageManagerService
+ // isn't ready yet.
+ if (availableFeatures.containsKey(PackageManager.FEATURE_AUTOMOTIVE)) {
+ mPrivilegedPermissionAllowlistSourcePackageNames.add(CAR_PACKAGE_NAME);
+ }
+
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
@@ -422,7 +439,8 @@
* lock created by the permission manager itself.
*/
@NonNull
- public static PermissionManagerServiceInternal create(@NonNull Context context) {
+ public static PermissionManagerServiceInternal create(@NonNull Context context,
+ ArrayMap<String, FeatureInfo> availableFeatures) {
final PermissionManagerServiceInternal permMgrInt =
LocalServices.getService(PermissionManagerServiceInternal.class);
if (permMgrInt != null) {
@@ -431,7 +449,7 @@
PermissionManagerService permissionService =
(PermissionManagerService) ServiceManager.getService("permissionmgr");
if (permissionService == null) {
- permissionService = new PermissionManagerService(context);
+ permissionService = new PermissionManagerService(context, availableFeatures);
ServiceManager.addService("permissionmgr", permissionService);
}
return LocalServices.getService(PermissionManagerServiceInternal.class);
@@ -3318,7 +3336,8 @@
if (!pkg.isPrivileged()) {
return true;
}
- if (!Objects.equals(permission.getPackageName(), PLATFORM_PACKAGE_NAME)) {
+ if (!mPrivilegedPermissionAllowlistSourcePackageNames
+ .contains(permission.getPackageName())) {
return true;
}
final String permissionName = permission.getName();
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index fa27b4b4..25709d4 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -21,11 +21,22 @@
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal;
import android.app.SyncNotedAppOp;
+import android.app.role.RoleManager;
import android.content.AttributionSource;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.location.LocationManagerInternal;
+import android.net.Uri;
import android.os.IBinder;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.HeptFunction;
@@ -35,6 +46,8 @@
import com.android.internal.util.function.TriFunction;
import com.android.server.LocalServices;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -42,9 +55,21 @@
* This class defines policy for special behaviors around app ops.
*/
public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegate {
+ private static final String LOG_TAG = AppOpsPolicy.class.getName();
+
+ private static final String ACTIVITY_RECOGNITION_TAGS =
+ "android:activity_recognition_allow_listed_tags";
+ private static final String ACTIVITY_RECOGNITION_TAGS_SEPARATOR = ";";
+
@NonNull
private final Object mLock = new Object();
+ @NonNull
+ private final Context mContext;
+
+ @NonNull
+ private final RoleManager mRoleManager;
+
/**
* The locking policy around the location tags is a bit special. Since we want to
* avoid grabbing the lock on every op note we are taking the approach where the
@@ -60,48 +85,57 @@
private final ConcurrentHashMap<Integer, ArrayMap<String, ArraySet<String>>> mLocationTags =
new ConcurrentHashMap<>();
- public AppOpsPolicy() {
+ @GuardedBy("mLock - writes only - see above")
+ @NonNull
+ private final ConcurrentHashMap<Integer, ArrayMap<String, ArraySet<String>>>
+ mActivityRecognitionTags = new ConcurrentHashMap<>();
+
+ public AppOpsPolicy(@NonNull Context context) {
+ mContext = context;
+ mRoleManager = mContext.getSystemService(RoleManager.class);
+
final LocationManagerInternal locationManagerInternal = LocalServices.getService(
LocationManagerInternal.class);
locationManagerInternal.setOnProviderLocationTagsChangeListener((providerTagInfo) -> {
synchronized (mLock) {
- final int uid = providerTagInfo.getUid();
- // We make a copy of the per UID state to limit our mutation to one
- // operation in the underlying concurrent data structure.
- ArrayMap<String, ArraySet<String>> uidTags = mLocationTags.get(uid);
- if (uidTags != null) {
- uidTags = new ArrayMap<>(uidTags);
- }
-
- final String packageName = providerTagInfo.getPackageName();
- ArraySet<String> packageTags = (uidTags != null) ? uidTags.get(packageName) : null;
- if (packageTags != null) {
- packageTags = new ArraySet<>(packageTags);
- }
-
- final Set<String> providerTags = providerTagInfo.getTags();
- if (providerTags != null && !providerTags.isEmpty()) {
- if (packageTags != null) {
- packageTags.clear();
- packageTags.addAll(providerTags);
- } else {
- packageTags = new ArraySet<>(providerTags);
- }
- if (uidTags == null) {
- uidTags = new ArrayMap<>();
- }
- uidTags.put(packageName, packageTags);
- mLocationTags.put(uid, uidTags);
- } else if (uidTags != null) {
- uidTags.remove(packageName);
- if (!uidTags.isEmpty()) {
- mLocationTags.put(uid, uidTags);
- } else {
- mLocationTags.remove(uid);
- }
- }
+ updateAllowListedTagsForPackageLocked(providerTagInfo.getUid(),
+ providerTagInfo.getPackageName(), providerTagInfo.getTags(),
+ mLocationTags);
}
});
+
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ intentFilter.addDataScheme("package");
+
+ context.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final Uri uri = intent.getData();
+ if (uri == null) {
+ return;
+ }
+ final String packageName = uri.getSchemeSpecificPart();
+ if (TextUtils.isEmpty(packageName)) {
+ return;
+ }
+ final List<String> activityRecognizers = mRoleManager.getRoleHolders(
+ RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER);
+ if (activityRecognizers.contains(packageName)) {
+ updateActivityRecognizerTags(packageName);
+ }
+ }
+ }, UserHandle.SYSTEM, intentFilter, null, null);
+
+ mRoleManager.addOnRoleHoldersChangedListenerAsUser(context.getMainExecutor(),
+ (String roleName, UserHandle user) -> {
+ if (RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER.equals(roleName)) {
+ initializeActivityRecognizersTags();
+ }
+ }, UserHandle.SYSTEM);
+
+ initializeActivityRecognizersTags();
}
@Override
@@ -121,7 +155,7 @@
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable
String message, boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer,
String, String, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
- return superImpl.apply(resolveOpCode(code, uid, packageName, attributionTag), uid,
+ return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag), uid,
packageName, attributionTag, shouldCollectAsyncNotedOp,
message, shouldCollectMessage);
}
@@ -132,7 +166,7 @@
boolean shouldCollectMessage, boolean skipProxyOperation, @NonNull HexFunction<Integer,
AttributionSource, Boolean, String, Boolean, Boolean,
SyncNotedAppOp> superImpl) {
- return superImpl.apply(resolveOpCode(code, attributionSource.getUid(),
+ return superImpl.apply(resolveDatasourceOp(code, attributionSource.getUid(),
attributionSource.getPackageName(), attributionSource.getAttributionTag()),
attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
skipProxyOperation);
@@ -144,7 +178,7 @@
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
boolean skipProxyOperation, @NonNull OctFunction<IBinder, Integer, AttributionSource,
Boolean, Boolean, String, Boolean, Boolean, SyncNotedAppOp> superImpl) {
- return superImpl.apply(token, resolveOpCode(code, attributionSource.getUid(),
+ return superImpl.apply(token, resolveDatasourceOp(code, attributionSource.getUid(),
attributionSource.getPackageName(), attributionSource.getAttributionTag()),
attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message,
shouldCollectMessage, skipProxyOperation);
@@ -154,36 +188,129 @@
public void finishProxyOperation(IBinder clientId, int code,
@NonNull AttributionSource attributionSource,
@NonNull TriFunction<IBinder, Integer, AttributionSource, Void> superImpl) {
- superImpl.apply(clientId, resolveOpCode(code, attributionSource.getUid(),
+ superImpl.apply(clientId, resolveDatasourceOp(code, attributionSource.getUid(),
attributionSource.getPackageName(), attributionSource.getAttributionTag()),
attributionSource);
}
- private int resolveOpCode(int code, int uid, @NonNull String packageName,
+ private int resolveDatasourceOp(int code, int uid, @NonNull String packageName,
@Nullable String attributionTag) {
- if (isHandledOp(code) && attributionTag != null) {
- // Only a single lookup from the underlying concurrent data structure
- final ArrayMap<String, ArraySet<String>> uidTags = mLocationTags.get(uid);
- if (uidTags != null) {
- final ArraySet<String> packageTags = uidTags.get(packageName);
- if (packageTags != null && packageTags.contains(attributionTag)) {
- return resolveHandledOp(code);
+ if (attributionTag == null) {
+ return code;
+ }
+ int resolvedCode = resolveLocationOp(code);
+ if (resolvedCode != code) {
+ if (isDatasourceAttributionTag(uid, packageName, attributionTag,
+ mLocationTags)) {
+ return resolvedCode;
+ }
+ } else {
+ resolvedCode = resolveArOp(code);
+ if (resolvedCode != code) {
+ if (isDatasourceAttributionTag(uid, packageName, attributionTag,
+ mActivityRecognitionTags)) {
+ return resolvedCode;
}
}
}
return code;
}
- private static boolean isHandledOp(int code) {
- switch (code) {
- case AppOpsManager.OP_FINE_LOCATION:
- case AppOpsManager.OP_COARSE_LOCATION:
+ private void initializeActivityRecognizersTags() {
+ final List<String> activityRecognizers = mRoleManager.getRoleHolders(
+ RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER);
+ final int recognizerCount = activityRecognizers.size();
+ if (recognizerCount > 0) {
+ for (int i = 0; i < recognizerCount; i++) {
+ final String activityRecognizer = activityRecognizers.get(i);
+ updateActivityRecognizerTags(activityRecognizer);
+ }
+ } else {
+ clearActivityRecognitionTags();
+ }
+ }
+
+ private void clearActivityRecognitionTags() {
+ synchronized (mLock) {
+ mActivityRecognitionTags.clear();
+ }
+ }
+
+ private void updateActivityRecognizerTags(@NonNull String activityRecognizer) {
+ try {
+ final ApplicationInfo recognizerAppInfo = mContext.getPackageManager()
+ .getApplicationInfoAsUser(activityRecognizer, PackageManager.GET_META_DATA,
+ UserHandle.USER_SYSTEM);
+ if (recognizerAppInfo.metaData == null) {
+ return;
+ }
+ final String tagsList = recognizerAppInfo.metaData.getString(ACTIVITY_RECOGNITION_TAGS);
+ if (tagsList != null) {
+ final String[] tags = tagsList.split(ACTIVITY_RECOGNITION_TAGS_SEPARATOR);
+ synchronized (mLock) {
+ updateAllowListedTagsForPackageLocked(recognizerAppInfo.uid,
+ recognizerAppInfo.packageName, new ArraySet<>(tags),
+ mActivityRecognitionTags);
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.wtf(LOG_TAG, "Missing " + RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER
+ + " role holder package " + activityRecognizer);
+ }
+ }
+
+ private static void updateAllowListedTagsForPackageLocked(int uid, String packageName,
+ Set<String> allowListedTags, ConcurrentHashMap<Integer, ArrayMap<String,
+ ArraySet<String>>> datastore) {
+ // We make a copy of the per UID state to limit our mutation to one
+ // operation in the underlying concurrent data structure.
+ ArrayMap<String, ArraySet<String>> uidTags = datastore.get(uid);
+ if (uidTags != null) {
+ uidTags = new ArrayMap<>(uidTags);
+ }
+
+ ArraySet<String> packageTags = (uidTags != null) ? uidTags.get(packageName) : null;
+ if (packageTags != null) {
+ packageTags = new ArraySet<>(packageTags);
+ }
+
+ if (allowListedTags != null && !allowListedTags.isEmpty()) {
+ if (packageTags != null) {
+ packageTags.clear();
+ packageTags.addAll(allowListedTags);
+ } else {
+ packageTags = new ArraySet<>(allowListedTags);
+ }
+ if (uidTags == null) {
+ uidTags = new ArrayMap<>();
+ }
+ uidTags.put(packageName, packageTags);
+ datastore.put(uid, uidTags);
+ } else if (uidTags != null) {
+ uidTags.remove(packageName);
+ if (!uidTags.isEmpty()) {
+ datastore.put(uid, uidTags);
+ } else {
+ datastore.remove(uid);
+ }
+ }
+ }
+
+ private static boolean isDatasourceAttributionTag(int uid, @NonNull String packageName,
+ @NonNull String attributionTag, @NonNull Map<Integer, ArrayMap<String,
+ ArraySet<String>>> mappedOps) {
+ // Only a single lookup from the underlying concurrent data structure
+ final ArrayMap<String, ArraySet<String>> uidTags = mappedOps.get(uid);
+ if (uidTags != null) {
+ final ArraySet<String> packageTags = uidTags.get(packageName);
+ if (packageTags != null && packageTags.contains(attributionTag)) {
return true;
+ }
}
return false;
}
- private static int resolveHandledOp(int code) {
+ private static int resolveLocationOp(int code) {
switch (code) {
case AppOpsManager.OP_FINE_LOCATION:
return AppOpsManager.OP_FINE_LOCATION_SOURCE;
@@ -192,4 +319,11 @@
}
return code;
}
+
+ private static int resolveArOp(int code) {
+ if (code == AppOpsManager.OP_ACTIVITY_RECOGNITION) {
+ return AppOpsManager.OP_ACTIVITY_RECOGNITION_SOURCE;
+ }
+ return code;
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java
index 52ff48b..d91e9c2 100644
--- a/services/core/java/com/android/server/timedetector/ServerFlags.java
+++ b/services/core/java/com/android/server/timedetector/ServerFlags.java
@@ -28,6 +28,8 @@
import com.android.server.timezonedetector.ConfigurationChangeListener;
import com.android.server.timezonedetector.ServiceConfigAccessor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.time.Duration;
import java.util.Map;
import java.util.Objects;
@@ -53,14 +55,15 @@
*/
@StringDef(prefix = "KEY_", value = {
KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
- KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
- KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+ KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
+ KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
})
+ @Retention(RetentionPolicy.SOURCE)
@interface DeviceConfigKey {}
/**
@@ -75,19 +78,19 @@
/**
* The key for the server flag that can override the device config for whether the primary
- * location time zone provider is enabled or disabled.
+ * location time zone provider is enabled, disabled, or (for testing) in simulation mode.
*/
@DeviceConfigKey
- public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE =
- "primary_location_time_zone_provider_enabled_override";
+ public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
+ "primary_location_time_zone_provider_mode_override";
/**
* The key for the server flag that can override the device config for whether the secondary
- * location time zone provider is enabled or disabled.
+ * location time zone provider is enabled or disabled, or (for testing) in simulation mode.
*/
@DeviceConfigKey
- public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE =
- "secondary_location_time_zone_provider_enabled_override";
+ public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE =
+ "secondary_location_time_zone_provider_mode_override";
/**
* The key for the minimum delay after location time zone detection has been enabled before the
@@ -196,6 +199,16 @@
}
/**
+ * Returns an optional string value from {@link DeviceConfig} from the system_time
+ * namespace, returns {@link Optional#empty()} if there is no explicit value set.
+ */
+ @NonNull
+ public Optional<String> getOptionalString(@DeviceConfigKey String key) {
+ String value = DeviceConfig.getProperty(NAMESPACE_SYSTEM_TIME, key);
+ return Optional.ofNullable(value);
+ }
+
+ /**
* Returns an optional boolean value from {@link DeviceConfig} from the system_time
* namespace, returns {@link Optional#empty()} if there is no explicit value set.
*/
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
index 222e852..50d37f4 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -17,6 +17,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringDef;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -27,6 +28,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.server.timedetector.ServerFlags;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.time.Duration;
import java.util.Collections;
import java.util.Objects;
@@ -40,13 +45,38 @@
*/
public final class ServiceConfigAccessor {
+ @StringDef(prefix = "PROVIDER_MODE_",
+ value = { PROVIDER_MODE_SIMULATED, PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED})
+ @Retention(RetentionPolicy.SOURCE)
+ @Target(ElementType.TYPE_USE)
+ @interface ProviderMode {}
+
+ /**
+ * The "simulated" provider mode.
+ * For use with {@link #getPrimaryLocationTimeZoneProviderMode()} and {@link
+ * #getSecondaryLocationTimeZoneProviderMode()}.
+ */
+ public static final @ProviderMode String PROVIDER_MODE_SIMULATED = "simulated";
+
+ /**
+ * The "disabled" provider mode. For use with {@link #getPrimaryLocationTimeZoneProviderMode()}
+ * and {@link #getSecondaryLocationTimeZoneProviderMode()}.
+ */
+ public static final @ProviderMode String PROVIDER_MODE_DISABLED = "disabled";
+
+ /**
+ * The "enabled" provider mode. For use with {@link #getPrimaryLocationTimeZoneProviderMode()}
+ * and {@link #getSecondaryLocationTimeZoneProviderMode()}.
+ */
+ public static final @ProviderMode String PROVIDER_MODE_ENABLED = "enabled";
+
private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet(
new ArraySet<>(new String[] {
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
- ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
- ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+ ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
+ ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS
@@ -139,14 +169,28 @@
/**
* Returns {@code true} if the location-based time zone detection feature is supported on the
- * device. This can be used during feature testing on builds that are capable of location time
- * zone detection to enable / disable the feature for some users.
+ * device.
*/
public boolean isGeoTimeZoneDetectionFeatureSupported() {
+ // For the feature to be enabled it must:
+ // 1) Be turned on in config.
+ // 2) Not be turned off via a server flag.
+ // 3) There must be at least one location time zone provider enabled / configured.
return mGeoDetectionFeatureSupportedInConfig
- && isGeoTimeZoneDetectionFeatureSupportedInternal();
+ && isGeoTimeZoneDetectionFeatureSupportedInternal()
+ && atLeastOneProviderIsEnabled();
}
+ private boolean atLeastOneProviderIsEnabled() {
+ return !(Objects.equals(getPrimaryLocationTimeZoneProviderMode(), PROVIDER_MODE_DISABLED)
+ && Objects.equals(getSecondaryLocationTimeZoneProviderMode(),
+ PROVIDER_MODE_DISABLED));
+ }
+
+ /**
+ * Returns {@code true} if the location-based time zone detection feature is not explicitly
+ * disabled by a server flag.
+ */
private boolean isGeoTimeZoneDetectionFeatureSupportedInternal() {
final boolean defaultEnabled = true;
return mServerFlags.getBoolean(
@@ -154,42 +198,49 @@
defaultEnabled);
}
+ @NonNull
+ public String getPrimaryLocationTimeZoneProviderPackageName() {
+ return mContext.getResources().getString(
+ R.string.config_primaryLocationTimeZoneProviderPackageName);
+ }
+
+ @NonNull
+ public String getSecondaryLocationTimeZoneProviderPackageName() {
+ return mContext.getResources().getString(
+ R.string.config_secondaryLocationTimeZoneProviderPackageName);
+ }
+
/**
* Returns {@code true} if the primary location time zone provider can be used.
*/
- public boolean isPrimaryLocationTimeZoneProviderEnabled() {
- return getPrimaryLocationTimeZoneProviderEnabledOverride()
- .orElse(isPrimaryLocationTimeZoneProviderEnabledInConfig());
- }
-
- private boolean isPrimaryLocationTimeZoneProviderEnabledInConfig() {
- int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
- return getConfigBoolean(providerEnabledConfigId);
+ @NonNull
+ public @ProviderMode String getPrimaryLocationTimeZoneProviderMode() {
+ return mServerFlags.getOptionalString(
+ ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE)
+ .orElse(getPrimaryLocationTimeZoneProviderModeFromConfig());
}
@NonNull
- private Optional<Boolean> getPrimaryLocationTimeZoneProviderEnabledOverride() {
- return mServerFlags.getOptionalBoolean(
- ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE);
+ private @ProviderMode String getPrimaryLocationTimeZoneProviderModeFromConfig() {
+ int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
+ return getConfigBoolean(providerEnabledConfigId)
+ ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED;
}
/**
- * Returns {@code true} if the secondary location time zone provider can be used.
+ * Returns the mode for the secondary location time zone provider can be used.
*/
- public boolean isSecondaryLocationTimeZoneProviderEnabled() {
- return getSecondaryLocationTimeZoneProviderEnabledOverride()
- .orElse(isSecondaryLocationTimeZoneProviderEnabledInConfig());
- }
-
- private boolean isSecondaryLocationTimeZoneProviderEnabledInConfig() {
- int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
- return getConfigBoolean(providerEnabledConfigId);
+ public @ProviderMode String getSecondaryLocationTimeZoneProviderMode() {
+ return mServerFlags.getOptionalString(
+ ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE)
+ .orElse(getSecondaryLocationTimeZoneProviderModeFromConfig());
}
@NonNull
- private Optional<Boolean> getSecondaryLocationTimeZoneProviderEnabledOverride() {
- return mServerFlags.getOptionalBoolean(
- ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE);
+ private @ProviderMode String getSecondaryLocationTimeZoneProviderModeFromConfig() {
+ int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
+ return getConfigBoolean(providerEnabledConfigId)
+ ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED;
}
/**
diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
index fb2a184..d2190fd 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
@@ -30,6 +30,7 @@
import static com.android.server.timezonedetector.location.TimeZoneProviderEvent.EVENT_TYPE_UNCERTAIN;
import android.annotation.DurationMillisLong;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteCallback;
@@ -604,14 +605,14 @@
* known provider, then the command is logged and discarded.
*/
void handleProviderTestCommand(
- @NonNull String providerName, @NonNull TestCommand testCommand,
+ @IntRange(from = 0, to = 1) int providerIndex, @NonNull TestCommand testCommand,
@Nullable RemoteCallback callback) {
mThreadingDomain.assertCurrentThread();
- LocationTimeZoneProvider targetProvider = getLocationTimeZoneProvider(providerName);
+ LocationTimeZoneProvider targetProvider = getLocationTimeZoneProvider(providerIndex);
if (targetProvider == null) {
warnLog("Unable to process test command:"
- + " providerName=" + providerName + ", testCommand=" + testCommand);
+ + " providerIndex=" + providerIndex + ", testCommand=" + testCommand);
return;
}
@@ -620,7 +621,7 @@
targetProvider.handleTestCommand(testCommand, callback);
} catch (Exception e) {
warnLog("Unable to process test command:"
- + " providerName=" + providerName + ", testCommand=" + testCommand, e);
+ + " providerIndex=" + providerIndex + ", testCommand=" + testCommand, e);
}
}
}
@@ -658,14 +659,15 @@
}
@Nullable
- private LocationTimeZoneProvider getLocationTimeZoneProvider(@NonNull String providerName) {
+ private LocationTimeZoneProvider getLocationTimeZoneProvider(
+ @IntRange(from = 0, to = 1) int providerIndex) {
LocationTimeZoneProvider targetProvider;
- if (Objects.equals(mPrimaryProvider.getName(), providerName)) {
+ if (providerIndex == 0) {
targetProvider = mPrimaryProvider;
- } else if (Objects.equals(mSecondaryProvider.getName(), providerName)) {
+ } else if (providerIndex == 1) {
targetProvider = mSecondaryProvider;
} else {
- warnLog("Bad providerName=" + providerName);
+ warnLog("Bad providerIndex=" + providerIndex);
targetProvider = null;
}
return targetProvider;
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
index ca4a640..d8d44d4 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
@@ -16,13 +16,12 @@
package com.android.server.timezonedetector.location;
-import static android.app.time.LocationTimeZoneManager.PRIMARY_PROVIDER_NAME;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DISABLED;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
-import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_DISABLED;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_SIMULATED;
+
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -37,12 +36,12 @@
import android.util.Log;
import android.util.Slog;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.SystemService;
+import com.android.server.timezonedetector.Dumpable;
import com.android.server.timezonedetector.ServiceConfigAccessor;
import com.android.server.timezonedetector.TimeZoneDetectorInternal;
import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger;
@@ -77,15 +76,7 @@
* bound (ensuring no real location events will be received) and simulated events / behaviors
* can be injected via the command line.
*
- * <p>To enter simulation mode for a provider, use {@code adb shell cmd location_time_zone_manager
- * set_provider_mode_override <provider name> simulated} and restart the service with {@code
- * adb shell cmd location_time_zone_manager stop} and {@code adb shell cmd
- * location_time_zone_manager start}.
- *
- * <p>e.g. {@code adb shell cmd location_time_zone_manager set_provider_mode_override primary
- * simulated}.
- *
- * <p>See {@code adb shell cmd location_time_zone_manager help}" for more options.
+ * <p>See {@code adb shell cmd location_time_zone_manager help}" for details and more options.
*/
public class LocationTimeZoneManagerService extends Binder {
@@ -139,11 +130,15 @@
private static final String ATTRIBUTION_TAG = "LocationTimeZoneService";
- private static final String PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
- TimeZoneProviderService.PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE;
- private static final String SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
- TimeZoneProviderService.SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE;
+ @GuardedBy("mSharedLock")
+ private final ProviderConfig mPrimaryProviderConfig = new ProviderConfig(
+ 0 /* index */, "primary",
+ TimeZoneProviderService.PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE);
+ @GuardedBy("mSharedLock")
+ private final ProviderConfig mSecondaryProviderConfig = new ProviderConfig(
+ 1 /* index */, "secondary",
+ TimeZoneProviderService.SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE);
@NonNull private final Context mContext;
@@ -173,14 +168,6 @@
@GuardedBy("mSharedLock")
private ControllerEnvironmentImpl mEnvironment;
- @GuardedBy("mSharedLock")
- @NonNull
- private String mPrimaryProviderModeOverride = PROVIDER_MODE_OVERRIDE_NONE;
-
- @GuardedBy("mSharedLock")
- @NonNull
- private String mSecondaryProviderModeOverride = PROVIDER_MODE_OVERRIDE_NONE;
-
LocationTimeZoneManagerService(Context context) {
mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mHandler = FgThread.getHandler();
@@ -208,9 +195,14 @@
mThreadingDomain.assertCurrentThread();
synchronized (mSharedLock) {
- // Stop and start the service, waiting until completion.
- stopOnDomainThread();
- startOnDomainThread();
+ // Avoid starting the service if it is currently stopped. This is required because
+ // server flags are used by tests to set behavior with the service stopped, and we don't
+ // want the service being restarted after each flag is set.
+ if (mLocationTimeZoneDetectorController != null) {
+ // Stop and start the service, waiting until completion.
+ stopOnDomainThread();
+ startOnDomainThread();
+ }
}
}
@@ -265,8 +257,8 @@
}
if (mLocationTimeZoneDetectorController == null) {
- LocationTimeZoneProvider primary = createPrimaryProvider();
- LocationTimeZoneProvider secondary = createSecondaryProvider();
+ LocationTimeZoneProvider primary = mPrimaryProviderConfig.createProvider();
+ LocationTimeZoneProvider secondary = mSecondaryProviderConfig.createProvider();
ControllerImpl controller =
new ControllerImpl(mThreadingDomain, primary, secondary);
@@ -281,88 +273,6 @@
}
}
- @NonNull
- private LocationTimeZoneProvider createPrimaryProvider() {
- LocationTimeZoneProviderProxy proxy;
- if (isProviderInSimulationMode(PRIMARY_PROVIDER_NAME)) {
- proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else if (!isProviderEnabled(PRIMARY_PROVIDER_NAME)) {
- proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else {
- proxy = new RealLocationTimeZoneProviderProxy(
- mContext,
- mHandler,
- mThreadingDomain,
- PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
- R.bool.config_enablePrimaryLocationTimeZoneOverlay,
- R.string.config_primaryLocationTimeZoneProviderPackageName
- );
- }
- ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(0);
- return new BinderLocationTimeZoneProvider(
- providerMetricsLogger, mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
- }
-
- @NonNull
- private LocationTimeZoneProvider createSecondaryProvider() {
- LocationTimeZoneProviderProxy proxy;
- if (isProviderInSimulationMode(SECONDARY_PROVIDER_NAME)) {
- proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else if (!isProviderEnabled(SECONDARY_PROVIDER_NAME)) {
- proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else {
- proxy = new RealLocationTimeZoneProviderProxy(
- mContext,
- mHandler,
- mThreadingDomain,
- SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
- R.bool.config_enableSecondaryLocationTimeZoneOverlay,
- R.string.config_secondaryLocationTimeZoneProviderPackageName
- );
- }
- ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(1);
- return new BinderLocationTimeZoneProvider(
- providerMetricsLogger, mThreadingDomain, SECONDARY_PROVIDER_NAME, proxy);
- }
-
- /** Used for bug triage and in tests to simulate provider events. */
- private boolean isProviderInSimulationMode(@NonNull String providerName) {
- return isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_SIMULATED);
- }
-
- /** Used for bug triage, and by tests and experiments to remove a provider. */
- private boolean isProviderEnabled(@NonNull String providerName) {
- if (isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED)) {
- return false;
- }
-
- switch (providerName) {
- case PRIMARY_PROVIDER_NAME: {
- return mServiceConfigAccessor.isPrimaryLocationTimeZoneProviderEnabled();
- }
- case SECONDARY_PROVIDER_NAME: {
- return mServiceConfigAccessor.isSecondaryLocationTimeZoneProviderEnabled();
- }
- default: {
- throw new IllegalArgumentException(providerName);
- }
- }
- }
-
- private boolean isProviderModeOverrideSet(@NonNull String providerName, @NonNull String mode) {
- switch (providerName) {
- case PRIMARY_PROVIDER_NAME: {
- return Objects.equals(mPrimaryProviderModeOverride, mode);
- }
- case SECONDARY_PROVIDER_NAME: {
- return Objects.equals(mSecondaryProviderModeOverride, mode);
- }
- default: {
- throw new IllegalArgumentException(providerName);
- }
- }
- }
-
/**
* Stops the service for tests and other rare cases. To avoid tests needing to sleep, this
* method will not return until all the system server components have stopped.
@@ -398,33 +308,6 @@
}
/** Sets this service into provider state recording mode for tests. */
- void setProviderModeOverride(@NonNull String providerName, @NonNull String mode) {
- enforceManageTimeZoneDetectorPermission();
-
- Preconditions.checkArgument(
- PRIMARY_PROVIDER_NAME.equals(providerName)
- || SECONDARY_PROVIDER_NAME.equals(providerName));
- Preconditions.checkArgument(PROVIDER_MODE_OVERRIDE_DISABLED.equals(mode)
- || PROVIDER_MODE_OVERRIDE_SIMULATED.equals(mode)
- || PROVIDER_MODE_OVERRIDE_NONE.equals(mode));
-
- mThreadingDomain.postAndWait(() -> {
- synchronized (mSharedLock) {
- switch (providerName) {
- case PRIMARY_PROVIDER_NAME: {
- mPrimaryProviderModeOverride = mode;
- break;
- }
- case SECONDARY_PROVIDER_NAME: {
- mSecondaryProviderModeOverride = mode;
- break;
- }
- }
- }
- }, BLOCKING_OP_WAIT_DURATION_MILLIS);
- }
-
- /** Sets this service into provider state recording mode for tests. */
void setProviderStateRecordingEnabled(boolean enabled) {
enforceManageTimeZoneDetectorPermission();
@@ -437,8 +320,11 @@
}, BLOCKING_OP_WAIT_DURATION_MILLIS);
}
- /** Returns a snapshot of the current controller state for tests. */
- @NonNull
+ /**
+ * Returns a snapshot of the current controller state for tests. Returns {@code null} if the
+ * service is stopped.
+ */
+ @Nullable
LocationTimeZoneManagerServiceState getStateForTests() {
enforceManageTimeZoneDetectorPermission();
@@ -462,8 +348,8 @@
* Passes a {@link TestCommand} to the specified provider and waits for the response.
*/
@NonNull
- Bundle handleProviderTestCommand(
- @NonNull String providerName, @NonNull TestCommand testCommand) {
+ Bundle handleProviderTestCommand(@IntRange(from = 0, to = 1) int providerIndex,
+ @NonNull TestCommand testCommand) {
enforceManageTimeZoneDetectorPermission();
// Because this method blocks and posts work to the threading domain thread, it would cause
@@ -484,7 +370,7 @@
return;
}
mLocationTimeZoneDetectorController.handleProviderTestCommand(
- providerName, testCommand, remoteCallback);
+ providerIndex, testCommand, remoteCallback);
}
});
@@ -510,6 +396,17 @@
synchronized (mSharedLock) {
ipw.println("LocationTimeZoneManagerService:");
ipw.increaseIndent();
+
+ ipw.println("Primary provider config:");
+ ipw.increaseIndent();
+ mPrimaryProviderConfig.dump(ipw, args);
+ ipw.decreaseIndent();
+
+ ipw.println("Secondary provider config:");
+ ipw.increaseIndent();
+ mSecondaryProviderConfig.dump(ipw, args);
+ ipw.decreaseIndent();
+
if (mLocationTimeZoneDetectorController == null) {
ipw.println("{Stopped}");
} else {
@@ -546,4 +443,75 @@
android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION,
"manage time and time zone detection");
}
+
+ /** An inner class for managing a provider's config. */
+ private final class ProviderConfig implements Dumpable {
+ @IntRange(from = 0, to = 1) private final int mIndex;
+ @NonNull private final String mName;
+ @NonNull private final String mServiceAction;
+
+ ProviderConfig(@IntRange(from = 0, to = 1) int index, @NonNull String name,
+ @NonNull String serviceAction) {
+ Preconditions.checkArgument(index >= 0 && index <= 1);
+ mIndex = index;
+ mName = Objects.requireNonNull(name);
+ mServiceAction = Objects.requireNonNull(serviceAction);
+ }
+
+ @NonNull
+ LocationTimeZoneProvider createProvider() {
+ LocationTimeZoneProviderProxy proxy = createProxy();
+ ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(mIndex);
+ return new BinderLocationTimeZoneProvider(
+ providerMetricsLogger, mThreadingDomain, mName, proxy);
+ }
+
+ @GuardedBy("mSharedLock")
+ @Override
+ public void dump(IndentingPrintWriter ipw, String[] args) {
+ ipw.printf("getMode()=%s\n", getMode());
+ ipw.printf("getPackageName()=%s\n", getPackageName());
+ }
+
+ @NonNull
+ private LocationTimeZoneProviderProxy createProxy() {
+ String mode = getMode();
+ if (Objects.equals(mode, PROVIDER_MODE_SIMULATED)) {
+ return new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
+ } else if (Objects.equals(mode, PROVIDER_MODE_DISABLED)) {
+ return new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
+ } else {
+ // mode == PROVIDER_MODE_OVERRIDE_ENABLED (or unknown).
+ return createRealProxy();
+ }
+ }
+
+ /** Returns the mode of the provider. */
+ @NonNull
+ private String getMode() {
+ if (mIndex == 0) {
+ return mServiceConfigAccessor.getPrimaryLocationTimeZoneProviderMode();
+ } else {
+ return mServiceConfigAccessor.getSecondaryLocationTimeZoneProviderMode();
+ }
+ }
+
+ @NonNull
+ private RealLocationTimeZoneProviderProxy createRealProxy() {
+ String providerServiceAction = mServiceAction;
+ String providerPackageName = getPackageName();
+ return new RealLocationTimeZoneProviderProxy(
+ mContext, mHandler, mThreadingDomain, providerServiceAction,
+ providerPackageName);
+ }
+
+ @NonNull
+ private String getPackageName() {
+ if (mIndex == 0) {
+ return mServiceConfigAccessor.getPrimaryLocationTimeZoneProviderPackageName();
+ } else {
+ return mServiceConfigAccessor.getSecondaryLocationTimeZoneProviderPackageName();
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
index bdf4a70..c6df624 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
@@ -16,19 +16,25 @@
package com.android.server.timezonedetector.location;
import static android.app.time.LocationTimeZoneManager.DUMP_STATE_OPTION_PROTO;
-import static android.app.time.LocationTimeZoneManager.PRIMARY_PROVIDER_NAME;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DISABLED;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
-import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
-import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_DUMP_STATE;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_RECORD_PROVIDER_STATES;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND;
-import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_START;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_STOP;
+import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS;
+import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS;
+import static com.android.server.timedetector.ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE;
+import static com.android.server.timedetector.ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_DISABLED;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_ENABLED;
+import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_SIMULATED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
@@ -53,16 +59,12 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/** Implements the shell command interface for {@link LocationTimeZoneManagerService}. */
class LocationTimeZoneManagerShellCommand extends ShellCommand {
- private static final List<String> VALID_PROVIDER_NAMES =
- Arrays.asList(PRIMARY_PROVIDER_NAME, SECONDARY_PROVIDER_NAME);
-
private final LocationTimeZoneManagerService mService;
LocationTimeZoneManagerShellCommand(LocationTimeZoneManagerService service) {
@@ -82,9 +84,6 @@
case SHELL_COMMAND_STOP: {
return runStop();
}
- case SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE: {
- return runSetProviderModeOverride();
- }
case SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND: {
return runSendProviderTestCommand();
}
@@ -110,10 +109,6 @@
pw.println(" Starts the location_time_zone_manager, creating time zone providers.");
pw.printf(" %s\n", SHELL_COMMAND_STOP);
pw.println(" Stops the location_time_zone_manager, destroying time zone providers.");
- pw.printf(" %s <provider name> <mode>\n", SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE);
- pw.println(" Sets a provider into a test mode next time the service started.");
- pw.printf(" Values: %s|%s|%s\n", PROVIDER_MODE_OVERRIDE_NONE,
- PROVIDER_MODE_OVERRIDE_DISABLED, PROVIDER_MODE_OVERRIDE_SIMULATED);
pw.printf(" %s (true|false)\n", SHELL_COMMAND_RECORD_PROVIDER_STATES);
pw.printf(" Enables / disables provider state recording mode. See also %s. The default"
+ " state is always \"false\".\n", SHELL_COMMAND_DUMP_STATE);
@@ -126,11 +121,11 @@
pw.println(" Dumps Location Time Zone Manager state for tests as text or binary proto"
+ " form.");
pw.println(" See the LocationTimeZoneManagerServiceStateProto definition for details.");
- pw.printf(" %s <provider name> <test command>\n",
+ pw.printf(" %s <provider index> <test command>\n",
SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND);
pw.println(" Passes a test command to the named provider.");
pw.println();
- pw.printf("<provider name> = One of %s\n", VALID_PROVIDER_NAMES);
+ pw.println("<provider index> = 0 (primary), 1 (secondary)");
pw.println();
pw.printf("%s details:\n", SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND);
pw.println();
@@ -146,6 +141,47 @@
pw.println();
pw.println("Test commands cannot currently be passed to real provider implementations.");
pw.println();
+ pw.printf("This service is also affected by the following device_config flags in the"
+ + " %s namespace:\n", NAMESPACE_SYSTEM_TIME);
+ pw.printf(" %s - [default=true], only observed if the feature is enabled in config,"
+ + "set this to false to disable the feature\n",
+ KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED);
+ pw.printf(" %s - [default=false]. Only used if the device does not have an explicit"
+ + " 'location time zone detection enabled' setting configured [*].\n",
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT);
+ pw.printf(" %s - [default=<unset>]. Used to override the device's 'location time zone"
+ + " detection enabled' setting [*]\n",
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE);
+ pw.printf(" %s - Overrides the mode of the primary provider. Values=%s|%s|%s\n",
+ KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
+ PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED, PROVIDER_MODE_SIMULATED);
+ pw.printf(" %s - Overrides the mode of the secondary provider. Values=%s|%s|%s\n",
+ KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE,
+ PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED, PROVIDER_MODE_SIMULATED);
+ pw.printf(" %s - \n",
+ KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE);
+ pw.printf(" %s - Sets the amount of time the service waits when uncertain before making"
+ + " an 'uncertain' suggestion to the time zone detector.\n",
+ KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS);
+ pw.printf(" %s - Sets the initialization time passed to the location time zone providers"
+ + "\n",
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS);
+ pw.printf(" %s - Sets the amount of extra time added to the location time zone providers"
+ + " initialization time\n",
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS);
+ pw.println();
+ pw.println("[*] The user must still have location = on / auto time zone detection = on");
+ pw.println();
+ pw.printf("Typically, use '%s' to stop the service before setting individual"
+ + " flags and '%s' after to restart it.\n",
+ SHELL_COMMAND_STOP, SHELL_COMMAND_START);
+ pw.println();
+ pw.println("Example:");
+ pw.printf(" $ adb shell cmd device_config put %s %s %s\n",
+ NAMESPACE_SYSTEM_TIME, KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
+ "true");
+ pw.println("See adb shell cmd device_config for more information.");
+ pw.println();
}
private int runStart() {
@@ -172,21 +208,6 @@
return 0;
}
- private int runSetProviderModeOverride() {
- PrintWriter outPrintWriter = getOutPrintWriter();
- try {
- String providerName = getNextArgRequired();
- String modeOverride = getNextArgRequired();
- outPrintWriter.println("Setting provider mode override for " + providerName
- + " to " + modeOverride);
- mService.setProviderModeOverride(providerName, modeOverride);
- } catch (RuntimeException e) {
- reportError(e);
- return 1;
- }
- return 0;
- }
-
private int runRecordProviderStates() {
PrintWriter outPrintWriter = getOutPrintWriter();
boolean enabled;
@@ -217,6 +238,11 @@
return 1;
}
+ if (state == null) {
+ // Controller is stopped.
+ return 0;
+ }
+
DualDumpOutputStream outputStream;
boolean useProto = Objects.equals(DUMP_STATE_OPTION_PROTO, getNextOption());
if (useProto) {
@@ -288,10 +314,10 @@
private int runSendProviderTestCommand() {
PrintWriter outPrintWriter = getOutPrintWriter();
- String providerName;
+ int providerIndex;
TestCommand testCommand;
try {
- providerName = validateProviderName(getNextArgRequired());
+ providerIndex = parseProviderIndex(getNextArgRequired());
testCommand = createTestCommandFromNextShellArg();
} catch (RuntimeException e) {
reportError(e);
@@ -299,9 +325,9 @@
}
outPrintWriter.println("Injecting testCommand=" + testCommand
- + " to providerName=" + providerName);
+ + " to providerIndex=" + providerIndex);
try {
- Bundle result = mService.handleProviderTestCommand(providerName, testCommand);
+ Bundle result = mService.handleProviderTestCommand(providerIndex, testCommand);
outPrintWriter.println(result);
} catch (RuntimeException e) {
reportError(e);
@@ -321,11 +347,11 @@
e.printStackTrace(errPrintWriter);
}
- @NonNull
- static String validateProviderName(@NonNull String value) {
- if (!VALID_PROVIDER_NAMES.contains(value)) {
- throw new IllegalArgumentException("Unknown provider name=" + value);
+ private static int parseProviderIndex(@NonNull String providerIndexString) {
+ int providerIndex = Integer.parseInt(providerIndexString);
+ if (providerIndex < 0 || providerIndex > 1) {
+ throw new IllegalArgumentException(providerIndexString);
}
- return value;
+ return providerIndex;
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
index 6c3f016..b5ac712 100644
--- a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
@@ -62,15 +62,17 @@
RealLocationTimeZoneProviderProxy(
@NonNull Context context, @NonNull Handler handler,
@NonNull ThreadingDomain threadingDomain, @NonNull String action,
- int enableOverlayResId, int nonOverlayPackageResId) {
+ @NonNull String providerPackageName) {
super(context, threadingDomain);
mManagerProxy = null;
mRequest = TimeZoneProviderRequest.createStopUpdatesRequest();
+
+ Objects.requireNonNull(providerPackageName);
mServiceWatcher = ServiceWatcher.create(context,
handler,
"RealLocationTimeZoneProviderProxy",
- new CurrentUserServiceSupplier(context, action, enableOverlayResId,
- nonOverlayPackageResId, BIND_TIME_ZONE_PROVIDER_SERVICE,
+ new CurrentUserServiceSupplier(context, action,
+ providerPackageName, BIND_TIME_ZONE_PROVIDER_SERVICE,
INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE),
this);
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 9f25daf..15f5765 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -95,8 +95,8 @@
"libaudioclient",
"libbase",
"libappfuse",
- "libbinder",
"libbinder_ndk",
+ "libbinder",
"libcutils",
"libcrypto",
"liblog",
@@ -105,6 +105,7 @@
"libhardware_legacy",
"libhidlbase",
"libmeminfo",
+ "libmemtrackproxy",
"libmtp",
"libnativehelper",
"libnativewindow",
@@ -154,6 +155,7 @@
"android.hardware.input.classifier@1.0",
"android.hardware.ir@1.0",
"android.hardware.light@2.0",
+ "android.hardware.memtrack-V1-ndk_platform",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"android.hardware.power-V1-cpp",
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 6cb4a63..fe728ab 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -24,11 +24,13 @@
#include <nativehelper/JNIHelp.h>
#include <android/binder_manager.h>
+#include <android/binder_stability.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <binder/IServiceManager.h>
#include <hidl/HidlTransportSupport.h>
#include <incremental_service.h>
+#include <memtrackproxy/MemtrackProxy.h>
#include <schedulerservice/SchedulingPolicyService.h>
#include <sensorservice/SensorService.h>
#include <sensorservicehidl/SensorManager.h>
@@ -83,6 +85,21 @@
}
}
+static void android_server_SystemServer_startMemtrackProxyService(JNIEnv* env,
+ jobject /* clazz */) {
+ using aidl::android::hardware::memtrack::MemtrackProxy;
+
+ const char* memtrackProxyService = "memtrack.proxy";
+
+ std::shared_ptr<MemtrackProxy> memtrack_proxy = ndk::SharedRefBase::make<MemtrackProxy>();
+ auto binder = memtrack_proxy->asBinder();
+
+ AIBinder_forceDowngradeToLocalStability(binder.get());
+
+ const binder_exception_t err = AServiceManager_addService(binder.get(), memtrackProxyService);
+ LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register %s: %d", memtrackProxyService, err);
+}
+
static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /* clazz */) {
using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
@@ -144,6 +161,8 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{"startSensorService", "()V", (void*)android_server_SystemServer_startSensorService},
+ {"startMemtrackProxyService", "()V",
+ (void*)android_server_SystemServer_startMemtrackProxyService},
{"startHidlServices", "()V", (void*)android_server_SystemServer_startHidlServices},
{"initZygoteChildHeapProfiling", "()V",
(void*)android_server_SystemServer_initZygoteChildHeapProfiling},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index a419bf8..fb0265e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -41,13 +41,13 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
-import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.UserRestrictionsUtils;
+import com.android.server.utils.Slogf;
import org.xmlpull.v1.XmlPullParserException;
@@ -469,7 +469,7 @@
try {
trustAgentInfo.options.saveToXml(out);
} catch (XmlPullParserException e) {
- Slog.e(LOG_TAG, e, "Failed to save TrustAgent options");
+ Slogf.e(LOG_TAG, e, "Failed to save TrustAgent options");
}
out.endTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS);
}
@@ -651,7 +651,7 @@
String tag = parser.getName();
if (TAG_POLICIES.equals(tag)) {
if (shouldOverridePolicies) {
- Slog.d(LOG_TAG, "Overriding device admin policies from XML.");
+ Slogf.d(LOG_TAG, "Overriding device admin policies from XML.");
info.readPoliciesFromXml(parser);
}
} else if (TAG_PASSWORD_QUALITY.equals(tag)) {
@@ -747,14 +747,14 @@
if (type == TypedXmlPullParser.TEXT) {
shortSupportMessage = parser.getText();
} else {
- Slog.w(LOG_TAG, "Missing text when loading short support message");
+ Slogf.w(LOG_TAG, "Missing text when loading short support message");
}
} else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) {
type = parser.next();
if (type == TypedXmlPullParser.TEXT) {
longSupportMessage = parser.getText();
} else {
- Slog.w(LOG_TAG, "Missing text when loading long support message");
+ Slogf.w(LOG_TAG, "Missing text when loading long support message");
}
} else if (TAG_PARENT_ADMIN.equals(tag)) {
Preconditions.checkState(!isParent);
@@ -767,7 +767,7 @@
if (type == TypedXmlPullParser.TEXT) {
organizationName = parser.getText();
} else {
- Slog.w(LOG_TAG, "Missing text when loading organization name");
+ Slogf.w(LOG_TAG, "Missing text when loading organization name");
}
} else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) {
isLogoutEnabled = parser.getAttributeBoolean(null, ATTR_VALUE, false);
@@ -776,14 +776,14 @@
if (type == TypedXmlPullParser.TEXT) {
startUserSessionMessage = parser.getText();
} else {
- Slog.w(LOG_TAG, "Missing text when loading start session message");
+ Slogf.w(LOG_TAG, "Missing text when loading start session message");
}
} else if (TAG_END_USER_SESSION_MESSAGE.equals(tag)) {
type = parser.next();
if (type == TypedXmlPullParser.TEXT) {
endUserSessionMessage = parser.getText();
} else {
- Slog.w(LOG_TAG, "Missing text when loading end session message");
+ Slogf.w(LOG_TAG, "Missing text when loading end session message");
}
} else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES.equals(tag)) {
mCrossProfileCalendarPackages = readPackageList(parser, tag);
@@ -822,14 +822,14 @@
if (type == TypedXmlPullParser.TEXT) {
mOrganizationId = parser.getText();
} else {
- Slog.w(LOG_TAG, "Missing Organization ID.");
+ Slogf.w(LOG_TAG, "Missing Organization ID.");
}
} else if (TAG_ENROLLMENT_SPECIFIC_ID.equals(tag)) {
type = parser.next();
if (type == TypedXmlPullParser.TEXT) {
mEnrollmentSpecificId = parser.getText();
} else {
- Slog.w(LOG_TAG, "Missing Enrollment-specific ID.");
+ Slogf.w(LOG_TAG, "Missing Enrollment-specific ID.");
}
} else if (TAG_ADMIN_CAN_GRANT_SENSORS_PERMISSIONS.equals(tag)) {
mAdminCanGrantSensorsPermissions = parser.getAttributeBoolean(null, ATTR_VALUE,
@@ -838,7 +838,7 @@
mUsbDataSignalingEnabled = parser.getAttributeBoolean(null, ATTR_VALUE,
USB_DATA_SIGNALING_ENABLED_DEFAULT);
} else {
- Slog.w(LOG_TAG, "Unknown admin tag: %s", tag);
+ Slogf.w(LOG_TAG, "Unknown admin tag: %s", tag);
XmlUtils.skipCurrentTag(parser);
}
}
@@ -860,10 +860,10 @@
if (packageName != null) {
result.add(packageName);
} else {
- Slog.w(LOG_TAG, "Package name missing under %s", outerTag);
+ Slogf.w(LOG_TAG, "Package name missing under %s", outerTag);
}
} else {
- Slog.w(LOG_TAG, "Unknown tag under %s: ", tag, outerTag);
+ Slogf.w(LOG_TAG, "Unknown tag under %s: ", tag, outerTag);
}
}
return result;
@@ -884,7 +884,7 @@
if (tag.equals(tagDAM)) {
result.add(parser.getAttributeValue(null, ATTR_VALUE));
} else {
- Slog.e(LOG_TAG, "Expected tag %s but found %s", tag, tagDAM);
+ Slogf.e(LOG_TAG, "Expected tag %s but found %s", tag, tagDAM);
}
}
}
@@ -906,7 +906,7 @@
final TrustAgentInfo trustAgentInfo = getTrustAgentInfo(parser, tag);
result.put(component, trustAgentInfo);
} else {
- Slog.w(LOG_TAG, "Unknown tag under %s: %s", tag, tagDAM);
+ Slogf.w(LOG_TAG, "Unknown tag under %s: %s", tag, tagDAM);
}
}
return result;
@@ -926,7 +926,7 @@
if (TAG_TRUST_AGENT_COMPONENT_OPTIONS.equals(tagDAM)) {
result.options = PersistableBundle.restoreFromXml(parser);
} else {
- Slog.w(LOG_TAG, "Unknown tag under %s: %s", tag, tagDAM);
+ Slogf.w(LOG_TAG, "Unknown tag under %s: %s", tag, tagDAM);
}
}
return result;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
index 8027e5b..cc385c7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
@@ -35,11 +35,11 @@
import android.security.Credentials;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
-import android.util.Slog;
import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.server.utils.Slogf;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -79,16 +79,16 @@
X509Certificate cert = parseCert(certBuffer);
pemCert = Credentials.convertToPem(cert);
} catch (CertificateException | IOException ce) {
- Slog.e(LOG_TAG, "Problem converting cert", ce);
+ Slogf.e(LOG_TAG, "Problem converting cert", ce);
return null;
}
try (KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(userHandle)) {
return keyChainConnection.getService().installCaCertificate(pemCert);
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "installCaCertsToKeyChain(): ", e);
+ Slogf.e(LOG_TAG, "installCaCertsToKeyChain(): ", e);
} catch (InterruptedException e1) {
- Slog.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
+ Slogf.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
Thread.currentThread().interrupt();
}
return null;
@@ -100,9 +100,9 @@
keyChainConnection.getService().deleteCaCertificate(aliases[i]);
}
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "from CaCertUninstaller: ", e);
+ Slogf.e(LOG_TAG, "from CaCertUninstaller: ", e);
} catch (InterruptedException ie) {
- Slog.w(LOG_TAG, "CaCertUninstaller: ", ie);
+ Slogf.w(LOG_TAG, "CaCertUninstaller: ", ie);
Thread.currentThread().interrupt();
}
}
@@ -147,7 +147,7 @@
try {
installedCerts = getInstalledCaCertificates(userHandle);
} catch (RemoteException | RuntimeException e) {
- Slog.e(LOG_TAG, e, "Could not retrieve certificates from KeyChain service for user %d",
+ Slogf.e(LOG_TAG, e, "Could not retrieve certificates from KeyChain service for user %d",
userId);
return;
}
@@ -170,7 +170,7 @@
try {
userContext = mInjector.createContextAsUser(userHandle);
} catch (PackageManager.NameNotFoundException e) {
- Slog.e(LOG_TAG, e, "Create context as %s failed", userHandle);
+ Slogf.e(LOG_TAG, e, "Create context as %s failed", userHandle);
return null;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
index 00e0292..8f0af91 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
@@ -27,13 +27,13 @@
import android.os.Handler;
import android.os.IBinder;
import android.util.IndentingPrintWriter;
-import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.server.am.PersistentConnection;
import com.android.server.appbinding.AppBindingUtils;
+import com.android.server.utils.Slogf;
/**
* Manages connections to persistent services in owner packages.
@@ -114,7 +114,8 @@
final ServiceInfo service = findService(packageName, userId);
if (service == null) {
if (DEBUG) {
- Slog.d(TAG, "Owner package %s on u%d has no service.", packageName, userId);
+ Slogf.d(TAG, "Owner package %s on u%d has no service.", packageName,
+ userId);
}
disconnectServiceOnUserLocked(userId, actionForLog);
return;
@@ -127,14 +128,14 @@
// would have died at this point due to a package update. So we disconnect
// anyway and re-connect.
if (DEBUG) {
- Slog.d("Disconnecting from existing service connection.", packageName,
+ Slogf.d("Disconnecting from existing service connection.", packageName,
userId);
}
disconnectServiceOnUserLocked(userId, actionForLog);
}
if (DEBUG) {
- Slog.d("Owner package %s on u%d has service %s for %s", packageName, userId,
+ Slogf.d("Owner package %s on u%d has service %s for %s", packageName, userId,
service.getComponentName().flattenToShortString(), actionForLog);
}
@@ -168,7 +169,7 @@
final DevicePolicyServiceConnection conn = mConnections.get(userId);
if (conn != null) {
if (DEBUG) {
- Slog.d(TAG, "Stopping service for u%d if already running for %s.", userId,
+ Slogf.d(TAG, "Stopping service for u%d if already running for %s.", userId,
actionForLog);
}
conn.unbind();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
index 2825eea..6de341d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
@@ -17,7 +17,8 @@
import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
-import android.util.Slog;
+
+import com.android.server.utils.Slogf;
import java.util.concurrent.TimeUnit;
@@ -99,7 +100,7 @@
} catch (IllegalArgumentException e) {
// Failed to parse the settings string, log this and move on
// with defaults.
- Slog.e(TAG, "Bad device policy settings: %s", settings);
+ Slogf.e(TAG, "Bad device policy settings: %s", settings);
}
long dasDiedServiceReconnectBackoffSec = parser.getLong(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 52cdce6..26c442d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -27,13 +27,13 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.IndentingPrintWriter;
-import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
+import com.android.server.utils.Slogf;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -183,7 +183,7 @@
try {
chooseForWrite = file.chooseForWrite();
if (VERBOSE_LOG) {
- Slog.v(TAG, "Storing data for user %d on %s ", policyData.mUserId, chooseForWrite);
+ Slogf.v(TAG, "Storing data for user %d on %s ", policyData.mUserId, chooseForWrite);
}
stream = new FileOutputStream(chooseForWrite, false);
TypedXmlSerializer out = Xml.resolveSerializer(stream);
@@ -195,7 +195,7 @@
policyData.mRestrictionsProvider.flattenToString());
}
if (policyData.mUserSetupComplete) {
- if (VERBOSE_LOG) Slog.v(TAG, "setting %s to true", ATTR_SETUP_COMPLETE);
+ if (VERBOSE_LOG) Slogf.v(TAG, "setting %s to true", ATTR_SETUP_COMPLETE);
out.attributeBoolean(null, ATTR_SETUP_COMPLETE, true);
}
if (policyData.mPaired) {
@@ -216,7 +216,7 @@
if (policyData.mFactoryResetFlags != 0) {
if (VERBOSE_LOG) {
- Slog.v(TAG, "Storing factory reset flags for user %d: %s", policyData.mUserId,
+ Slogf.v(TAG, "Storing factory reset flags for user %d: %s", policyData.mUserId,
factoryResetFlagsToString(policyData.mFactoryResetFlags));
}
out.attributeInt(null, ATTR_FACTORY_RESET_FLAGS, policyData.mFactoryResetFlags);
@@ -382,7 +382,7 @@
file.commit();
return true;
} catch (XmlPullParserException | IOException e) {
- Slog.w(TAG, e, "failed writing file %s", chooseForWrite);
+ Slogf.w(TAG, e, "failed writing file %s", chooseForWrite);
try {
if (stream != null) {
stream.close();
@@ -404,7 +404,7 @@
ComponentName ownerComponent) {
FileInputStream stream = null;
File file = journaledFile.chooseForRead();
- if (VERBOSE_LOG) Slog.v(TAG, "Loading data for user %d from %s", policy.mUserId, file);
+ if (VERBOSE_LOG) Slogf.v(TAG, "Loading data for user %d from %s", policy.mUserId, file);
boolean needsRewrite = false;
try {
stream = new FileInputStream(file);
@@ -428,7 +428,7 @@
}
String userSetupComplete = parser.getAttributeValue(null, ATTR_SETUP_COMPLETE);
if (Boolean.toString(true).equals(userSetupComplete)) {
- if (VERBOSE_LOG) Slog.v(TAG, "setting mUserSetupComplete to true");
+ if (VERBOSE_LOG) Slogf.v(TAG, "setting mUserSetupComplete to true");
policy.mUserSetupComplete = true;
}
String paired = parser.getAttributeValue(null, ATTR_DEVICE_PAIRED);
@@ -452,7 +452,7 @@
policy.mFactoryResetFlags = parser.getAttributeInt(null, ATTR_FACTORY_RESET_FLAGS, 0);
if (VERBOSE_LOG) {
- Slog.v(TAG, "Restored factory reset flags for user %d: %s", policy.mUserId,
+ Slogf.v(TAG, "Restored factory reset flags for user %d: %s", policy.mUserId,
factoryResetFlagsToString(policy.mFactoryResetFlags));
}
policy.mFactoryResetReason = parser.getAttributeValue(null, ATTR_FACTORY_RESET_REASON);
@@ -486,7 +486,7 @@
policy.mAdminMap.put(ap.info.getComponent(), ap);
}
} catch (RuntimeException e) {
- Slog.w(TAG, e, "Failed loading admin %s", name);
+ Slogf.w(TAG, e, "Failed loading admin %s", name);
}
} else if ("delegation".equals(tag)) {
// Parse delegation info.
@@ -558,7 +558,7 @@
policy.mAppsSuspended =
parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else {
- Slog.w(TAG, "Unknown tag: %s", tag);
+ Slogf.w(TAG, "Unknown tag: %s", tag);
XmlUtils.skipCurrentTag(parser);
}
}
@@ -566,7 +566,7 @@
// Don't be noisy, this is normal if we haven't defined any policies.
} catch (NullPointerException | NumberFormatException | XmlPullParserException | IOException
| IndexOutOfBoundsException e) {
- Slog.w(TAG, e, "failed parsing %s", file);
+ Slogf.w(TAG, e, "failed parsing %s", file);
}
try {
if (stream != null) {
@@ -590,7 +590,7 @@
}
}
if (!haveOwner) {
- Slog.w(TAG, "Previous password owner %s no longer active; disabling",
+ Slogf.w(TAG, "Previous password owner %s no longer active; disabling",
mPasswordOwner);
mPasswordOwner = -1;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 00a1786d..8e361eb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -283,7 +283,6 @@
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Pair;
-import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -333,6 +332,7 @@
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.uri.NeededUriGrants;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.utils.Slogf;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.google.android.collect.Sets;
@@ -734,7 +734,7 @@
if (Thread.holdsLock(mLockDoNoUseDirectly)) {
return;
}
- Slog.wtfStack(LOG_TAG, "Not holding DPMS lock.");
+ Slogf.wtfStack(LOG_TAG, "Not holding DPMS lock.");
}
@VisibleForTesting
@@ -843,7 +843,7 @@
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "Sending password expiration notifications for action "
+ Slogf.v(LOG_TAG, "Sending password expiration notifications for action "
+ action + " for user " + userHandle);
}
mHandler.post(new Runnable() {
@@ -887,7 +887,7 @@
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
sendDeviceOwnerUserCommand(DeviceAdminReceiver.ACTION_USER_STOPPED, userHandle);
if (isManagedProfile(userHandle)) {
- Slog.d(LOG_TAG, "Managed profile was stopped");
+ Slogf.d(LOG_TAG, "Managed profile was stopped");
updatePersonalAppsSuspension(userHandle, false /* unlocked */);
}
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
@@ -897,7 +897,7 @@
maybeSendAdminEnabledBroadcastLocked(userHandle);
}
if (isManagedProfile(userHandle)) {
- Slog.d(LOG_TAG, "Managed profile became unlocked");
+ Slogf.d(LOG_TAG, "Managed profile became unlocked");
final boolean suspended =
updatePersonalAppsSuspension(userHandle, true /* unlocked */);
triggerPolicyComplianceCheckIfNeeded(userHandle, suspended);
@@ -929,15 +929,15 @@
updatePersonalAppsSuspension(userId, mUserManager.isUserUnlocked(userId));
}
} else if (ACTION_PROFILE_OFF_DEADLINE.equals(action)) {
- Slog.i(LOG_TAG, "Profile off deadline alarm was triggered");
+ Slogf.i(LOG_TAG, "Profile off deadline alarm was triggered");
final int userId = getManagedUserId(UserHandle.USER_SYSTEM);
if (userId >= 0) {
updatePersonalAppsSuspension(userId, mUserManager.isUserUnlocked(userId));
} else {
- Slog.wtf(LOG_TAG, "Got deadline alarm for nonexistent profile");
+ Slogf.wtf(LOG_TAG, "Got deadline alarm for nonexistent profile");
}
} else if (ACTION_TURN_PROFILE_ON_NOTIFICATION.equals(action)) {
- Slog.i(LOG_TAG, "requesting to turn on the profile: " + userHandle);
+ Slogf.i(LOG_TAG, "requesting to turn on the profile: " + userHandle);
mUserManager.requestQuietModeEnabled(false, UserHandle.of(userHandle));
}
}
@@ -986,7 +986,7 @@
// Always reset filters on the parent user, which handles cross profile intent
// filters between the parent and its profiles.
- Slog.i(LOG_TAG, "Resetting cross-profile intent filters on restriction "
+ Slogf.i(LOG_TAG, "Resetting cross-profile intent filters on restriction "
+ "change");
mDpms.resetDefaultCrossProfileIntentFilters(parentId);
mContext.sendBroadcastAsUser(new Intent(
@@ -1007,7 +1007,7 @@
private void handlePackagesChanged(@Nullable String packageName, int userHandle) {
boolean removedAdmin = false;
if (VERBOSE_LOG) {
- Slog.d(LOG_TAG, "Handling package changes package " + packageName
+ Slogf.d(LOG_TAG, "Handling package changes package " + packageName
+ " for user " + userHandle);
}
DevicePolicyData policy = getUserData(userHandle);
@@ -1077,7 +1077,7 @@
service.removeCredentialManagementApp();
}
} catch (RemoteException | InterruptedException | IllegalStateException e) {
- Slog.e(LOG_TAG, "Unable to remove the credential management app");
+ Slogf.e(LOG_TAG, "Unable to remove the credential management app");
}
});
}
@@ -1103,7 +1103,7 @@
// Check if package is considered not suspendable?
if (mInjector.getPackageManager(userHandle)
.getUnsuspendablePackages(packagesToSuspend).length != 0) {
- Slog.i(LOG_TAG, "Newly installed package is unsuspendable: " + packageName);
+ Slogf.i(LOG_TAG, "Newly installed package is unsuspendable: " + packageName);
return;
}
try {
@@ -1127,7 +1127,7 @@
* Used by {@code setDevicePolicySafetyChecker()} above and {@link OneTimeSafetyChecker}.
*/
void setDevicePolicySafetyCheckerUnchecked(DevicePolicySafetyChecker safetyChecker) {
- Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as %s", safetyChecker);
+ Slogf.i(LOG_TAG, "Setting DevicePolicySafetyChecker as %s", safetyChecker);
mSafetyChecker = safetyChecker;
mInjector.setDevicePolicySafetyChecker(safetyChecker);
}
@@ -1170,7 +1170,7 @@
@OperationSafetyReason int reason) {
Preconditions.checkCallAuthorization(
hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
- Slog.i(LOG_TAG, "setNextOperationSafety(%s, %s)",
+ Slogf.i(LOG_TAG, "setNextOperationSafety(%s, %s)",
DevicePolicyManager.operationToString(operation),
DevicePolicyManager.operationSafetyReasonToString(reason));
mSafetyChecker = new OneTimeSafetyChecker(this, operation, reason);
@@ -1179,7 +1179,7 @@
@Override
public boolean isSafeOperation(@OperationSafetyReason int reason) {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "checking isSafeOperation(%s) using mSafetyChecker %s",
+ Slogf.v(LOG_TAG, "checking isSafeOperation(%s) using mSafetyChecker %s",
DevicePolicyManager.operationSafetyReasonToString(reason), mSafetyChecker);
}
return mSafetyChecker == null ? true : mSafetyChecker.isSafeOperation(reason);
@@ -1758,7 +1758,7 @@
void removeUserData(int userHandle) {
synchronized (getLockObject()) {
if (userHandle == UserHandle.USER_SYSTEM) {
- Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
+ Slogf.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
return;
}
updatePasswordQualityCacheForUserGroup(userHandle);
@@ -1774,7 +1774,7 @@
File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle),
DEVICE_POLICIES_XML);
policyFile.delete();
- Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
+ Slogf.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
}
}
@@ -1872,64 +1872,64 @@
*/
@GuardedBy("getLockObject()")
private void migrateToProfileOnOrganizationOwnedDeviceIfCompLocked() {
- if (VERBOSE_LOG) Slog.d(LOG_TAG, "Checking whether we need to migrate COMP ");
+ if (VERBOSE_LOG) Slogf.d(LOG_TAG, "Checking whether we need to migrate COMP ");
final int doUserId = mOwners.getDeviceOwnerUserId();
if (doUserId == UserHandle.USER_NULL) {
- if (VERBOSE_LOG) Slog.d(LOG_TAG, "No DO found, skipping migration.");
+ if (VERBOSE_LOG) Slogf.d(LOG_TAG, "No DO found, skipping migration.");
return;
}
final List<UserInfo> profiles = mUserManager.getProfiles(doUserId);
if (profiles.size() != 2) {
if (profiles.size() == 1) {
- if (VERBOSE_LOG) Slog.d(LOG_TAG, "Profile not found, skipping migration.");
+ if (VERBOSE_LOG) Slogf.d(LOG_TAG, "Profile not found, skipping migration.");
} else {
- Slog.wtf(LOG_TAG, "Found " + profiles.size() + " profiles, skipping migration");
+ Slogf.wtf(LOG_TAG, "Found " + profiles.size() + " profiles, skipping migration");
}
return;
}
final int poUserId = getManagedUserId(doUserId);
if (poUserId < 0) {
- Slog.wtf(LOG_TAG, "Found DO and a profile, but it is not managed, skipping migration");
+ Slogf.wtf(LOG_TAG, "Found DO and a profile, but it is not managed, skipping migration");
return;
}
final ActiveAdmin doAdmin = getDeviceOwnerAdminLocked();
final ActiveAdmin poAdmin = getProfileOwnerAdminLocked(poUserId);
if (doAdmin == null || poAdmin == null) {
- Slog.wtf(LOG_TAG, "Failed to get either PO or DO admin, aborting migration.");
+ Slogf.wtf(LOG_TAG, "Failed to get either PO or DO admin, aborting migration.");
return;
}
final ComponentName doAdminComponent = mOwners.getDeviceOwnerComponent();
final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(poUserId);
if (doAdminComponent == null || poAdminComponent == null) {
- Slog.wtf(LOG_TAG, "Cannot find PO or DO component name, aborting migration.");
+ Slogf.wtf(LOG_TAG, "Cannot find PO or DO component name, aborting migration.");
return;
}
if (!doAdminComponent.getPackageName().equals(poAdminComponent.getPackageName())) {
- Slog.e(LOG_TAG, "DO and PO are different packages, aborting migration.");
+ Slogf.e(LOG_TAG, "DO and PO are different packages, aborting migration.");
return;
}
- Slog.i(LOG_TAG, "Migrating COMP to PO on a corp owned device; primary user: %d; "
+ Slogf.i(LOG_TAG, "Migrating COMP to PO on a corp owned device; primary user: %d; "
+ "profile: %d", doUserId, poUserId);
- Slog.i(LOG_TAG, "Giving the PO additional power...");
+ Slogf.i(LOG_TAG, "Giving the PO additional power...");
markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId);
- Slog.i(LOG_TAG, "Migrating DO policies to PO...");
+ Slogf.i(LOG_TAG, "Migrating DO policies to PO...");
moveDoPoliciesToProfileParentAdminLocked(doAdmin, poAdmin.getParentActiveAdmin());
migratePersonalAppSuspensionLocked(doUserId, poUserId, poAdmin);
saveSettingsLocked(poUserId);
- Slog.i(LOG_TAG, "Clearing the DO...");
+ Slogf.i(LOG_TAG, "Clearing the DO...");
final ComponentName doAdminReceiver = doAdmin.info.getComponent();
clearDeviceOwnerLocked(doAdmin, doUserId);
- Slog.i(LOG_TAG, "Removing admin artifacts...");
+ Slogf.i(LOG_TAG, "Removing admin artifacts...");
removeAdminArtifacts(doAdminReceiver, doUserId);
- Slog.i(LOG_TAG, "Uninstalling the DO...");
+ Slogf.i(LOG_TAG, "Uninstalling the DO...");
uninstallOrDisablePackage(doAdminComponent.getPackageName(), doUserId);
- Slog.i(LOG_TAG, "Migration complete.");
+ Slogf.i(LOG_TAG, "Migration complete.");
// Note: KeyChain keys are not removed and will remain accessible for the apps that have
// been given grants to use them.
@@ -1945,16 +1945,16 @@
int doUserId, int poUserId, ActiveAdmin poAdmin) {
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
if (!pmi.isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, doUserId)) {
- Slog.i(LOG_TAG, "DO is not suspending any apps.");
+ Slogf.i(LOG_TAG, "DO is not suspending any apps.");
return;
}
if (getTargetSdk(poAdmin.info.getPackageName(), poUserId) >= Build.VERSION_CODES.R) {
- Slog.i(LOG_TAG, "PO is targeting R+, keeping personal apps suspended.");
+ Slogf.i(LOG_TAG, "PO is targeting R+, keeping personal apps suspended.");
getUserData(doUserId).mAppsSuspended = true;
poAdmin.mSuspendPersonalApps = true;
} else {
- Slog.i(LOG_TAG, "PO isn't targeting R+, unsuspending personal apps.");
+ Slogf.i(LOG_TAG, "PO isn't targeting R+, unsuspending personal apps.");
pmi.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, doUserId);
}
}
@@ -1969,11 +1969,11 @@
return;
}
if (appInfo == null) {
- Slog.wtf(LOG_TAG, "Failed to get package info for " + packageName);
+ Slogf.wtf(LOG_TAG, "Failed to get package info for " + packageName);
return;
}
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- Slog.i(LOG_TAG, "Package %s is pre-installed, marking disabled until used",
+ Slogf.i(LOG_TAG, "Package %s is pre-installed, marking disabled until used",
packageName);
mContext.getPackageManager().setApplicationEnabledSetting(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, /* flags= */ 0);
@@ -1987,9 +1987,9 @@
final int status = intent.getIntExtra(
PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
- Slog.i(LOG_TAG, "Package %s uninstalled for user %d", packageName, userId);
+ Slogf.i(LOG_TAG, "Package %s uninstalled for user %d", packageName, userId);
} else {
- Slog.e(LOG_TAG, "Failed to uninstall %s; status: %d", packageName, status);
+ Slogf.e(LOG_TAG, "Failed to uninstall %s; status: %d", packageName, status);
}
}
};
@@ -2057,7 +2057,7 @@
private void applyManagedProfileRestrictionIfDeviceOwnerLocked() {
final int doUserId = mOwners.getDeviceOwnerUserId();
if (doUserId == UserHandle.USER_NULL) {
- if (VERBOSE_LOG) Slog.d(LOG_TAG, "No DO found, skipping application of restriction.");
+ if (VERBOSE_LOG) Slogf.d(LOG_TAG, "No DO found, skipping application of restriction.");
return;
}
@@ -2114,10 +2114,10 @@
if (defaultRestrictions.equals(admin.defaultEnabledRestrictionsAlreadySet)) {
return; // The same set of default restrictions has been already applied.
}
- Slog.i(LOG_TAG, "New user restrictions need to be set by default for user " + userId);
+ Slogf.i(LOG_TAG, "New user restrictions need to be set by default for user " + userId);
if (VERBOSE_LOG) {
- Slog.d(LOG_TAG,"Default enabled restrictions: "
+ Slogf.d(LOG_TAG, "Default enabled restrictions: "
+ defaultRestrictions
+ ". Restrictions already enabled: "
+ admin.defaultEnabledRestrictionsAlreadySet);
@@ -2130,7 +2130,7 @@
admin.ensureUserRestrictions().putBoolean(restriction, true);
}
admin.defaultEnabledRestrictionsAlreadySet.addAll(restrictionsToSet);
- Slog.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictionsToSet);
+ Slogf.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictionsToSet);
saveUserRestrictionsLocked(userId);
}
}
@@ -2154,10 +2154,10 @@
final String value = Boolean.toString(hasDeviceOwner || hasOrgOwnedProfile);
final String currentVal = mInjector.systemPropertiesGet(PROPERTY_ORGANIZATION_OWNED, null);
if (TextUtils.isEmpty(currentVal)) {
- Slog.i(LOG_TAG, "Set ro.organization_owned property to " + value);
+ Slogf.i(LOG_TAG, "Set ro.organization_owned property to " + value);
mInjector.systemPropertiesSet(PROPERTY_ORGANIZATION_OWNED, value);
} else if (!value.equals(currentVal)) {
- Slog.w(LOG_TAG, "Cannot change existing ro.organization_owned to " + value);
+ Slogf.w(LOG_TAG, "Cannot change existing ro.organization_owned to " + value);
}
}
@@ -2185,7 +2185,7 @@
doComponentName.getPackageName(),
mOwners.getDeviceOwnerUserId());
if (doComponent == null) {
- Slog.e(LOG_TAG, "Device-owner isn't registered as device-admin");
+ Slogf.e(LOG_TAG, "Device-owner isn't registered as device-admin");
} else {
mOwners.setDeviceOwnerWithRestrictionsMigrated(
doComponent,
@@ -2194,7 +2194,7 @@
!mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
mOwners.writeDeviceOwner();
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "Device owner component filled in");
+ Slogf.v(LOG_TAG, "Device owner component filled in");
}
}
}
@@ -2209,7 +2209,7 @@
// except for the "system controlled" ones.
if (mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()) {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "Migrating DO user restrictions");
+ Slogf.v(LOG_TAG, "Migrating DO user restrictions");
}
migrated = true;
@@ -2237,7 +2237,7 @@
final int userId = ui.id;
if (mOwners.getProfileOwnerUserRestrictionsNeedsMigration(userId)) {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "Migrating PO user restrictions for user %d", userId);
+ Slogf.v(LOG_TAG, "Migrating PO user restrictions for user %d", userId);
}
migrated = true;
@@ -2260,7 +2260,7 @@
}
}
if (VERBOSE_LOG && migrated) {
- Slog.v(LOG_TAG, "User restrictions migrated.");
+ Slogf.v(LOG_TAG, "User restrictions migrated.");
}
}
@@ -2288,9 +2288,9 @@
}
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "origRestrictions=%s", origRestrictions);
- Slog.v(LOG_TAG, "newBaseRestrictions=%s", newBaseRestrictions);
- Slog.v(LOG_TAG, "newOwnerRestrictions=%s", newOwnerRestrictions);
+ Slogf.v(LOG_TAG, "origRestrictions=%s", origRestrictions);
+ Slogf.v(LOG_TAG, "newBaseRestrictions=%s", newBaseRestrictions);
+ Slogf.v(LOG_TAG, "newOwnerRestrictions=%s", newOwnerRestrictions);
}
mUserManagerInternal.setBaseUserRestrictionsByDpmsForMigration(user.getIdentifier(),
newBaseRestrictions);
@@ -2299,7 +2299,7 @@
admin.ensureUserRestrictions().clear();
admin.ensureUserRestrictions().putAll(newOwnerRestrictions);
} else {
- Slog.w(LOG_TAG, "ActiveAdmin for DO/PO not found. user=" + user.getIdentifier());
+ Slogf.w(LOG_TAG, "ActiveAdmin for DO/PO not found. user=" + user.getIdentifier());
}
saveSettingsLocked(user.getIdentifier());
}
@@ -2320,7 +2320,7 @@
}
}
if (nFound > 1) {
- Slog.w(LOG_TAG, "Multiple DA found; assume the first one is DO.");
+ Slogf.w(LOG_TAG, "Multiple DA found; assume the first one is DO.");
}
return found;
}
@@ -2760,7 +2760,7 @@
if (!permission.BIND_DEVICE_ADMIN.equals(ai.permission)) {
final String message = "DeviceAdminReceiver " + adminName + " must be protected with "
+ permission.BIND_DEVICE_ADMIN;
- Slog.w(LOG_TAG, message);
+ Slogf.w(LOG_TAG, message);
if (throwForMissingPermission &&
ai.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) {
throw new IllegalArgumentException(message);
@@ -2770,7 +2770,7 @@
try {
return new DeviceAdminInfo(mContext, ai);
} catch (XmlPullParserException | IOException e) {
- Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
+ Slogf.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
e);
return null;
}
@@ -2785,7 +2785,7 @@
private JournaledFile makeJournaledFile(@UserIdInt int userId, String fileName) {
final String base = new File(getPolicyFileDirectory(userId), fileName)
.getAbsolutePath();
- if (VERBOSE_LOG) Slog.v(LOG_TAG, "Opening %s", base);
+ if (VERBOSE_LOG) Slogf.v(LOG_TAG, "Opening %s", base);
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
@@ -3033,7 +3033,7 @@
if (!mTransferOwnershipMetadataManager.metadataFileExists()) {
return;
}
- Slog.e(LOG_TAG, "Owner transfer metadata file exists! Reverting transfer.");
+ Slogf.e(LOG_TAG, "Owner transfer metadata file exists! Reverting transfer.");
final TransferOwnershipMetadataManager.Metadata metadata =
mTransferOwnershipMetadataManager.loadMetadataFile();
// Revert transfer
@@ -3079,7 +3079,7 @@
// STOPSHIP Prevent the DO user from being killed.
} catch (RemoteException e) {
- Slog.w(LOG_TAG, "Exception starting user", e);
+ Slogf.w(LOG_TAG, "Exception starting user", e);
}
}
}
@@ -3512,7 +3512,7 @@
}
// Remove the admin skipping sending the broadcast.
removeAdminArtifacts(adminReceiver, userHandle);
- Slog.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle);
+ Slogf.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle);
});
}
@@ -3584,8 +3584,8 @@
// Active device/profile owners must remain active admins.
if (isDeviceOwner(adminReceiver, userHandle)
|| isProfileOwner(adminReceiver, userHandle)) {
- Slog.e(LOG_TAG, "Device/profile owner cannot be removed: component=" +
- adminReceiver);
+ Slogf.e(LOG_TAG, "Device/profile owner cannot be removed: component="
+ + adminReceiver);
return;
}
if (admin.getUid() != mInjector.binderGetCallingUid()) {
@@ -3850,7 +3850,7 @@
}
}
} else {
- Slog.w(LOG_TAG, "Unknown user type: " + userInfo);
+ Slogf.w(LOG_TAG, "Unknown user type: " + userInfo);
}
}
});
@@ -3959,7 +3959,7 @@
ap.passwordExpirationDate = expiration;
ap.passwordExpirationTimeout = timeout;
if (timeout > 0L) {
- Slog.w(LOG_TAG, "setPasswordExpiration(): password will expire on "
+ Slogf.w(LOG_TAG, "setPasswordExpiration(): password will expire on "
+ DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
.format(new Date(expiration)));
}
@@ -4883,7 +4883,7 @@
@Override
public boolean resetPassword(@Nullable String password, int flags) throws RemoteException {
if (!mLockPatternUtils.hasSecureLockScreen()) {
- Slog.w(LOG_TAG, "Cannot reset password when the device has no lock screen");
+ Slogf.w(LOG_TAG, "Cannot reset password when the device has no lock screen");
return false;
}
if (password == null) password = "";
@@ -4901,7 +4901,7 @@
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (getTargetSdk(admin.info.getPackageName(), userHandle) < Build.VERSION_CODES.O) {
- Slog.e(LOG_TAG, "DPC can no longer call resetPassword()");
+ Slogf.e(LOG_TAG, "DPC can no longer call resetPassword()");
return false;
}
throw new SecurityException("Device admin can no longer call resetPassword()");
@@ -4917,7 +4917,7 @@
"Unauthorized caller cannot call resetPassword.");
if (getTargetSdk(admin.info.getPackageName(),
userHandle) <= android.os.Build.VERSION_CODES.M) {
- Slog.e(LOG_TAG, "Device admin can no longer call resetPassword()");
+ Slogf.e(LOG_TAG, "Device admin can no longer call resetPassword()");
return false;
}
throw new SecurityException("Device admin can no longer call resetPassword()");
@@ -4944,7 +4944,7 @@
}
if (!validationErrors.isEmpty()) {
- Slog.w(LOG_TAG, "Failed to reset password due to constraint violation: %s",
+ Slogf.w(LOG_TAG, "Failed to reset password due to constraint violation: %s",
validationErrors.get(0));
return false;
}
@@ -4952,7 +4952,7 @@
DevicePolicyData policy = getUserData(userHandle);
if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
- Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user");
+ Slogf.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user");
return false;
}
@@ -5266,7 +5266,7 @@
if (userToLock == UserHandle.USER_ALL) {
if (mIsAutomotive) {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "lockNow(): not powering off display on automotive"
+ Slogf.v(LOG_TAG, "lockNow(): not powering off display on automotive"
+ " build");
}
} else {
@@ -5373,7 +5373,7 @@
});
if (alias == null) {
- Slog.w(LOG_TAG, "Problem installing cert");
+ Slogf.w(LOG_TAG, "Problem installing cert");
return false;
}
@@ -5446,12 +5446,12 @@
.write();
return true;
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Installing certificate", e);
+ Slogf.e(LOG_TAG, "Installing certificate", e);
} finally {
keyChainConnection.close();
}
} catch (InterruptedException e) {
- Slog.w(LOG_TAG, "Interrupted while installing certificate", e);
+ Slogf.w(LOG_TAG, "Interrupted while installing certificate", e);
Thread.currentThread().interrupt();
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -5496,12 +5496,12 @@
.write();
return keyChain.removeKeyPair(alias);
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Removing keypair", e);
+ Slogf.e(LOG_TAG, "Removing keypair", e);
} finally {
keyChainConnection.close();
}
} catch (InterruptedException e) {
- Slog.w(LOG_TAG, "Interrupted while removing keypair", e);
+ Slogf.w(LOG_TAG, "Interrupted while removing keypair", e);
Thread.currentThread().interrupt();
} finally {
Binder.restoreCallingIdentity(id);
@@ -5520,9 +5520,9 @@
KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
return keyChainConnection.getService().containsKeyPair(alias);
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Querying keypair", e);
+ Slogf.e(LOG_TAG, "Querying keypair", e);
} catch (InterruptedException e) {
- Slog.w(LOG_TAG, "Interrupted while querying keypair", e);
+ Slogf.w(LOG_TAG, "Interrupted while querying keypair", e);
Thread.currentThread().interrupt();
}
return false;
@@ -5564,7 +5564,7 @@
}
return false;
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Querying grant to wifi auth.", e);
+ Slogf.e(LOG_TAG, "Querying grant to wifi auth.", e);
return false;
}
});
@@ -5605,11 +5605,11 @@
keyChain.setGrant(granteeUid, alias, hasGrant);
return true;
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Setting grant for package.", e);
+ Slogf.e(LOG_TAG, "Setting grant for package.", e);
return false;
}
} catch (InterruptedException e) {
- Slog.w(LOG_TAG, "Interrupted while setting key grant", e);
+ Slogf.w(LOG_TAG, "Interrupted while setting key grant", e);
Thread.currentThread().interrupt();
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -5636,7 +5636,7 @@
for (final int uid : granteeUids) {
final String[] packages = pm.getPackagesForUid(uid);
if (packages == null) {
- Slog.wtf(LOG_TAG, "No packages found for uid " + uid);
+ Slogf.wtf(LOG_TAG, "No packages found for uid " + uid);
continue;
}
if (!result.isEmpty()) {
@@ -5646,9 +5646,9 @@
}
return result;
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Querying keypair grants", e);
+ Slogf.e(LOG_TAG, "Querying keypair grants", e);
} catch (InterruptedException e) {
- Slog.w(LOG_TAG, "Interrupted while querying keypair grants", e);
+ Slogf.w(LOG_TAG, "Interrupted while querying keypair grants", e);
Thread.currentThread().interrupt();
}
return Collections.emptyList();
@@ -5773,7 +5773,7 @@
// As the caller will be granted access to the key, ensure no UID was specified, as
// it will not have the desired effect.
if (keySpec.getUid() != KeyStore.UID_SELF) {
- Slog.e(LOG_TAG, "Only the caller can be granted access to the generated keypair.");
+ Slogf.e(LOG_TAG, "Only the caller can be granted access to the generated keypair.");
logGenerateKeyPairFailure(caller, isCredentialManagementApp);
return false;
}
@@ -5799,7 +5799,7 @@
final int generationResult = keyChain.generateKeyPair(algorithm,
new ParcelableKeyGenParameterSpec(keySpec));
if (generationResult != KeyChain.KEY_GEN_SUCCESS) {
- Slog.e(LOG_TAG, "KeyChain failed to generate a keypair, error %d.",
+ Slogf.e(LOG_TAG, "KeyChain failed to generate a keypair, error %d.",
generationResult);
logGenerateKeyPairFailure(caller, isCredentialManagementApp);
switch (generationResult) {
@@ -5839,7 +5839,7 @@
attestationChain.shallowCopyFrom(new KeymasterCertificateChain(encodedCerts));
} catch (CertificateException e) {
logGenerateKeyPairFailure(caller, isCredentialManagementApp);
- Slog.e(LOG_TAG, "While retrieving certificate chain.", e);
+ Slogf.e(LOG_TAG, "While retrieving certificate chain.", e);
return false;
}
@@ -5854,9 +5854,9 @@
return true;
}
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "KeyChain error while generating a keypair", e);
+ Slogf.e(LOG_TAG, "KeyChain error while generating a keypair", e);
} catch (InterruptedException e) {
- Slog.w(LOG_TAG, "Interrupted while generating keypair", e);
+ Slogf.w(LOG_TAG, "Interrupted while generating keypair", e);
Thread.currentThread().interrupt();
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -5914,10 +5914,10 @@
.write();
return true;
} catch (InterruptedException e) {
- Slog.w(LOG_TAG, "Interrupted while setting keypair certificate", e);
+ Slogf.w(LOG_TAG, "Interrupted while setting keypair certificate", e);
Thread.currentThread().interrupt();
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Failed setting keypair certificate", e);
+ Slogf.e(LOG_TAG, "Failed setting keypair certificate", e);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -5991,7 +5991,7 @@
} catch (Exception e) {
// Caller could throw RuntimeException or RemoteException back across processes. Catch
// everything just to be sure.
- Slog.e(LOG_TAG, "error while responding to callback", e);
+ Slogf.e(LOG_TAG, "error while responding to callback", e);
}
}
@@ -6208,7 +6208,7 @@
if (delegates.size() == 0) {
return null;
} else if (delegates.size() > 1) {
- Slog.wtf(LOG_TAG, "More than one delegate holds " + scope);
+ Slogf.wtf(LOG_TAG, "More than one delegate holds " + scope);
return null;
}
final String pkg = delegates.get(0);
@@ -6224,7 +6224,7 @@
final int count = receivers.size();
if (count >= 1) {
if (count > 1) {
- Slog.w(LOG_TAG, pkg + " defines more than one delegate receiver for " + action);
+ Slogf.w(LOG_TAG, pkg + " defines more than one delegate receiver for " + action);
}
return receivers.get(0).activityInfo.getComponentName();
} else {
@@ -6352,7 +6352,7 @@
boolean isUserSelectable) {
// Should not be user selectable
if (isUserSelectable) {
- Slog.e(LOG_TAG, "The credential management app is not allowed to install a "
+ Slogf.e(LOG_TAG, "The credential management app is not allowed to install a "
+ "user selectable key pair");
return false;
}
@@ -6442,7 +6442,7 @@
final int userId = caller.getUserId();
mInjector.binderWithCleanCallingIdentity(() -> {
if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) {
- Slog.w(LOG_TAG, "Non-existent VPN package specified: " + vpnPackage);
+ Slogf.w(LOG_TAG, "Non-existent VPN package specified: " + vpnPackage);
throw new ServiceSpecificException(
DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, vpnPackage);
}
@@ -6450,7 +6450,7 @@
if (vpnPackage != null && lockdown && lockdownAllowlist != null) {
for (String packageName : lockdownAllowlist) {
if (!isPackageInstalledForUser(packageName, userId)) {
- Slog.w(LOG_TAG, "Non-existent package in VPN allowlist: " + packageName);
+ Slogf.w(LOG_TAG, "Non-existent package in VPN allowlist: " + packageName);
throw new ServiceSpecificException(
DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, packageName);
}
@@ -6552,7 +6552,7 @@
// Persist the request so the device is automatically factory-reset on next start if
// the system crashes or reboots before the {@code DevicePolicySafetyChecker} calls
// its callback.
- Slog.i(LOG_TAG, "Persisting factory reset request as it could be delayed by %s",
+ Slogf.i(LOG_TAG, "Persisting factory reset request as it could be delayed by %s",
mSafetyChecker);
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
@@ -6563,7 +6563,7 @@
}
success = true;
} catch (IOException | SecurityException e) {
- Slog.w(LOG_TAG, "Failed requesting data wipe", e);
+ Slogf.w(LOG_TAG, "Failed requesting data wipe", e);
} finally {
if (!success) SecurityLog.writeEvent(SecurityLog.TAG_WIPE_FAILURE);
}
@@ -6577,7 +6577,7 @@
if (policy.mFactoryResetReason == null) {
// Shouldn't happen.
- Slog.e(LOG_TAG, "no persisted reason for factory resetting");
+ Slogf.e(LOG_TAG, "no persisted reason for factory resetting");
policy.mFactoryResetReason = "requested before boot";
}
FactoryResetter factoryResetter = FactoryResetter.newBuilder(mContext)
@@ -6589,16 +6589,16 @@
.setWipeFactoryResetProtection((policy.mFactoryResetFlags & DevicePolicyData
.FACTORY_RESET_FLAG_WIPE_FACTORY_RESET_PROTECTION) != 0)
.build();
- Slog.i(LOG_TAG, "Factory resetting on boot using " + factoryResetter);
+ Slogf.i(LOG_TAG, "Factory resetting on boot using " + factoryResetter);
try {
if (!factoryResetter.factoryReset()) {
// Shouldn't happen because FactoryResetter was created without a
// DevicePolicySafetyChecker.
- Slog.wtf(LOG_TAG, "Factory reset using " + factoryResetter + " failed.");
+ Slogf.wtf(LOG_TAG, "Factory reset using " + factoryResetter + " failed.");
}
} catch (IOException e) {
// Shouldn't happen.
- Slog.wtf(LOG_TAG, "Could not factory reset using " + factoryResetter, e);
+ Slogf.wtf(LOG_TAG, "Could not factory reset using " + factoryResetter, e);
}
}
}
@@ -6612,7 +6612,7 @@
success = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
if (!success) {
- Slog.w(LOG_TAG, "Couldn't remove user " + userId);
+ Slogf.w(LOG_TAG, "Couldn't remove user " + userId);
} else if (isManagedProfile(userId) && !wipeSilently) {
sendWipeProfileNotification(wipeReasonForUser);
}
@@ -6667,7 +6667,7 @@
int userId = admin != null ? admin.getUserHandle().getIdentifier()
: caller.getUserId();
- Slog.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser, admin,
+ Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser, admin,
userId);
if (calledByProfileOwnerOnOrgOwnedDevice) {
// When wipeData is called on the parent instance, it implies wiping the entire device.
@@ -6705,7 +6705,7 @@
} else {
adminComp = null;
adminName = mInjector.getPackageManager().getPackagesForUid(caller.getUid())[0];
- Slog.i(LOG_TAG, "Logging wipeData() event admin as " + adminName);
+ Slogf.i(LOG_TAG, "Logging wipeData() event admin as " + adminName);
event.setAdmin(adminName);
if (mInjector.userManagerIsHeadlessSystemUserMode()) {
// On headless system user mode, the call is meant to factory reset the whole
@@ -6980,7 +6980,7 @@
if (wipeData && strictestAdmin != null) {
final int userId = getUserIdToWipeForFailedPasswords(strictestAdmin);
- Slog.i(LOG_TAG, "Max failed password attempts policy reached for admin: "
+ Slogf.i(LOG_TAG, "Max failed password attempts policy reached for admin: "
+ strictestAdmin.info.getComponent().flattenToShortString()
+ ". Calling wipeData for user " + userId);
@@ -6999,7 +6999,7 @@
wipeReasonForUser,
userId);
} catch (SecurityException e) {
- Slog.w(LOG_TAG, "Failed to wipe user " + userId
+ Slogf.w(LOG_TAG, "Failed to wipe user " + userId
+ " after max failed password attempts reached.", e);
}
}
@@ -7133,7 +7133,7 @@
// If the user is not system, don't set the global proxy. Fail silently.
if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
- Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User "
+ Slogf.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User "
+ UserHandle.getCallingUserId() + " is not permitted.");
return null;
}
@@ -7226,7 +7226,7 @@
ProxyInfo proxyProperties = ProxyInfo.buildDirectProxy(data[0], proxyPort,
ProxyUtils.exclusionStringAsList(exclusionList));
if (!proxyProperties.isValid()) {
- Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
+ Slogf.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
}
mInjector.settingsGlobalPutString(Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
@@ -7253,8 +7253,8 @@
// Check for permissions
// Only system user can set storage encryption
if (userHandle != UserHandle.USER_SYSTEM) {
- Slog.w(LOG_TAG, "Only owner/system user is allowed to set storage encryption. User "
- + UserHandle.getCallingUserId() + " is not permitted.");
+ Slogf.w(LOG_TAG, "Only owner/system user is allowed to set storage encryption. "
+ + "User " + UserHandle.getCallingUserId() + " is not permitted.");
return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
}
@@ -7468,7 +7468,7 @@
try {
mInjector.getIWindowManager().refreshScreenCaptureDisabled(userHandle);
} catch (RemoteException e) {
- Slog.w(LOG_TAG, "Unable to notify WindowManager.", e);
+ Slogf.w(LOG_TAG, "Unable to notify WindowManager.", e);
}
});
}
@@ -7796,7 +7796,7 @@
intent.putExtras(extras);
}
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "sendActiveAdminCommand(): broadcasting " + action + " to "
+ Slogf.v(LOG_TAG, "sendActiveAdminCommand(): broadcasting " + action + " to "
+ receiverComponent.flattenToShortString() + " on user " + userId);
}
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
@@ -8083,7 +8083,7 @@
* feature will be appended to it.
*/
private void logMissingFeatureAction(String message) {
- Slog.w(LOG_TAG, message + " because device does not have the "
+ Slogf.w(LOG_TAG, message + " because device does not have the "
+ PackageManager.FEATURE_DEVICE_ADMIN + " feature.");
}
@@ -8150,11 +8150,11 @@
mDeviceAdminServiceController.startServiceForOwner(
admin.getPackageName(), userId, "set-device-owner");
- Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
+ Slogf.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
if (mInjector.userManagerIsHeadlessSystemUserMode()) {
int currentForegroundUser = getCurrentForegroundUserId();
- Slog.i(LOG_TAG, "setDeviceOwner(): setting " + admin
+ Slogf.i(LOG_TAG, "setDeviceOwner(): setting " + admin
+ " as profile owner on user " + currentForegroundUser);
// Sets profile owner on current foreground user since
// the human user will complete the DO setup workflow from there.
@@ -8383,7 +8383,7 @@
return admin;
}
}
- Slog.wtf(LOG_TAG, "Active admin for device owner not found. component=" + component);
+ Slogf.wtf(LOG_TAG, "Active admin for device owner not found. component=" + component);
return null;
}
@@ -8424,7 +8424,7 @@
sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED,
deviceOwnerUserId);
});
- Slog.i(LOG_TAG, "Device owner removed: " + deviceOwnerComponent);
+ Slogf.i(LOG_TAG, "Device owner removed: " + deviceOwnerComponent);
}
}
@@ -8518,7 +8518,7 @@
if (parentUserId != userHandle && mUserManager.hasUserRestriction(
UserManager.DISALLOW_ADD_MANAGED_PROFILE,
UserHandle.of(parentUserId))) {
- Slog.i(LOG_TAG, "Cannot set profile owner because of restriction.");
+ Slogf.i(LOG_TAG, "Cannot set profile owner because of restriction.");
return false;
}
@@ -8537,7 +8537,7 @@
mOwners.setProfileOwner(who, ownerName, userHandle);
mOwners.writeProfileOwner(userHandle);
- Slog.i(LOG_TAG, "Profile owner set: " + who + " on user " + userHandle);
+ Slogf.i(LOG_TAG, "Profile owner set: " + who + " on user " + userHandle);
mInjector.binderWithCleanCallingIdentity(() -> {
if (mUserManager.isManagedProfile(userHandle)) {
@@ -8593,7 +8593,7 @@
sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED,
userId);
});
- Slog.i(LOG_TAG, "Profile owner " + who + " removed from user " + userId);
+ Slogf.i(LOG_TAG, "Profile owner " + who + " removed from user " + userId);
}
}
@@ -8806,7 +8806,7 @@
// Check if the profile is already enabled.
UserInfo managedProfile = getUserInfo(userId);
if (managedProfile.isEnabled()) {
- Slog.e(LOG_TAG,
+ Slogf.e(LOG_TAG,
"setProfileEnabled is called when the profile is already enabled");
return;
}
@@ -9019,18 +9019,18 @@
// thrown but null data can be returned; if the appInfo for the specified package cannot
// be found then return false to prevent crashing the app.
if (appInfo == null) {
- Slog.w(LOG_TAG, "appInfo could not be found for package %s", packageName);
+ Slogf.w(LOG_TAG, "appInfo could not be found for package %s", packageName);
return false;
} else if (uid != appInfo.uid) {
String message = String.format("Package %s (uid=%d) does not match provided uid %d",
packageName, appInfo.uid, uid);
- Slog.w(LOG_TAG, message);
+ Slogf.w(LOG_TAG, message);
throw new SecurityException(message);
}
} catch (RemoteException e) {
// If an exception is caught obtaining the appInfo just return false to prevent crashing
// apps due to an internal error.
- Slog.e(LOG_TAG, e, "Exception caught obtaining appInfo for package %s", packageName);
+ Slogf.e(LOG_TAG, e, "Exception caught obtaining appInfo for package %s", packageName);
return false;
}
return true;
@@ -9046,7 +9046,7 @@
String message = String.format(
"Calling uid %d, pid %d cannot check device identifier access for package %s "
+ "(uid=%d, pid=%d)", callingUid, callingPid, packageName, uid, pid);
- Slog.w(LOG_TAG, message);
+ Slogf.w(LOG_TAG, message);
throw new SecurityException(message);
}
}
@@ -9062,7 +9062,7 @@
userContext = mContext.createPackageContextAsUser(packageName, /* flags= */ 0,
userHandle);
} catch (PackageManager.NameNotFoundException nnfe) {
- Slog.w(LOG_TAG, nnfe, "%s is not installed for user %d", packageName, userId);
+ Slogf.w(LOG_TAG, nnfe, "%s is not installed for user %d", packageName, userId);
return null;
}
ApplicationInfo appInfo = userContext.getApplicationInfo();
@@ -9079,7 +9079,7 @@
*/
private void wtfIfInLock() {
if (Thread.holdsLock(this)) {
- Slog.wtfStack(LOG_TAG, "Shouldn't be called with DPMS lock held");
+ Slogf.wtfStack(LOG_TAG, "Shouldn't be called with DPMS lock held");
}
}
@@ -9296,7 +9296,7 @@
try {
return mInjector.getIActivityManager().getCurrentUser().id;
} catch (RemoteException e) {
- Slog.wtf(LOG_TAG, "cannot get current user");
+ Slogf.wtf(LOG_TAG, "cannot get current user");
}
return UserHandle.USER_NULL;
}
@@ -9384,7 +9384,7 @@
// pm.getUnsuspendablePackages() will fail if it's called for a different user;
// as this dump is mostly useful for system user anyways, we can just ignore the
// others (rather than changing the permission check in the PM method)
- Slog.d(LOG_TAG, "skipping PersonalAppsSuspensionHelper.dump() for user " + userId);
+ Slogf.d(LOG_TAG, "skipping PersonalAppsSuspensionHelper.dump() for user " + userId);
}
}
}
@@ -9681,8 +9681,8 @@
}
result.add(info.options);
} else {
- Slog.w(LOG_TAG, "Ignoring admin %s because it has trust options but doesn't"
- + " declare KEYGUARD_DISABLE_TRUST_AGENTS", active.info);
+ Slogf.w(LOG_TAG, "Ignoring admin %s because it has trust options but "
+ + "doesn't declare KEYGUARD_DISABLE_TRUST_AGENTS", active.info);
}
} else if (disablesTrust) {
allAdminsHaveOptions = false;
@@ -9728,7 +9728,7 @@
try {
UserInfo parent = mUserManager.getProfileParent(callingUserId);
if (parent == null) {
- Slog.e(LOG_TAG, "Cannot call addCrossProfileIntentFilter if there is no "
+ Slogf.e(LOG_TAG, "Cannot call addCrossProfileIntentFilter if there is no "
+ "parent");
return;
}
@@ -9778,7 +9778,7 @@
try {
UserInfo parent = mUserManager.getProfileParent(callingUserId);
if (parent == null) {
- Slog.e(LOG_TAG, "Cannot call clearCrossProfileIntentFilter if there is no "
+ Slogf.e(LOG_TAG, "Cannot call clearCrossProfileIntentFilter if there is no "
+ "parent");
return;
}
@@ -9820,7 +9820,7 @@
userIdToCheck);
systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
} catch (RemoteException e) {
- Slog.i(LOG_TAG, "Can't talk to package managed", e);
+ Slogf.i(LOG_TAG, "Can't talk to package managed", e);
}
if (!systemService && !permittedList.contains(enabledPackage)) {
return false;
@@ -9873,7 +9873,7 @@
}
if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList,
userId)) {
- Slog.e(LOG_TAG, "Cannot set permitted accessibility services, "
+ Slogf.e(LOG_TAG, "Cannot set permitted accessibility services, "
+ "because it contains already enabled accesibility services.");
return false;
}
@@ -10026,7 +10026,7 @@
}
if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList,
userId)) {
- Slog.e(LOG_TAG, "Cannot set permitted input methods, because the list of "
+ Slogf.e(LOG_TAG, "Cannot set permitted input methods, because the list of "
+ "permitted input methods excludes an already-enabled input method.");
return false;
}
@@ -10292,7 +10292,7 @@
}
Object token = new Object();
- Slog.d(LOG_TAG, "Adding new pending token: " + token);
+ Slogf.d(LOG_TAG, "Adding new pending token: " + token);
mPendingUserCreatedCallbackTokens.add(token);
try {
UserInfo userInfo = mUserManagerInternal.createUserEvenWhenDisallowed(name,
@@ -10301,7 +10301,7 @@
user = userInfo.getUserHandle();
}
} catch (UserManager.CheckedUserOperationException e) {
- Slog.e(LOG_TAG, "Couldn't createUserEvenWhenDisallowed", e);
+ Slogf.e(LOG_TAG, "Couldn't createUserEvenWhenDisallowed", e);
}
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -10356,7 +10356,7 @@
boolean showDisclaimer) {
synchronized (getLockObject()) {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "manageUserUnchecked(): admin=" + admin + ", po=" + profileOwner
+ Slogf.v(LOG_TAG, "manageUserUnchecked(): admin=" + admin + ", po=" + profileOwner
+ ", userId=" + userId + ", hasAdminExtras=" + (adminExtras != null)
+ ", showDisclaimer=" + showDisclaimer);
}
@@ -10372,7 +10372,7 @@
}
} catch (RemoteException e) {
// Does not happen, same process
- Slog.wtf(LOG_TAG, e, "Failed to install admin package %s for user %d",
+ Slogf.wtf(LOG_TAG, e, "Failed to install admin package %s for user %d",
adminPkg, userId);
}
@@ -10396,7 +10396,7 @@
private void handleNewUserCreated(UserInfo user, @Nullable Object token) {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "handleNewUserCreated(): user=" + user.toFullString()
+ Slogf.v(LOG_TAG, "handleNewUserCreated(): user=" + user.toFullString()
+ ", token=" + token);
}
@@ -10405,7 +10405,7 @@
synchronized (getLockObject()) {
if (mPendingUserCreatedCallbackTokens.contains(token)) {
// Ignore because it was triggered by createAndManageUser()
- Slog.d(LOG_TAG, "handleNewUserCreated(): ignoring for user " + userId
+ Slogf.d(LOG_TAG, "handleNewUserCreated(): ignoring for user " + userId
+ " due to token" + token);
mPendingUserCreatedCallbackTokens.remove(token);
return;
@@ -10417,12 +10417,12 @@
if (mInjector.userManagerIsHeadlessSystemUserMode()) {
ComponentName admin = mOwners.getDeviceOwnerComponent();
- Slog.i(LOG_TAG, "Automatically setting profile owner (" + admin + ") on new user "
+ Slogf.i(LOG_TAG, "Automatically setting profile owner (" + admin + ") on new user "
+ userId);
manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
/* managedUser= */ userId, /* adminExtras= */ null, /* showDisclaimer= */ true);
} else {
- Slog.i(LOG_TAG, "User %d added on DO mode; setting ShowNewUserDisclaimer", userId);
+ Slogf.i(LOG_TAG, "User %d added on DO mode; setting ShowNewUserDisclaimer", userId);
setShowNewUserDisclaimer(userId, DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED);
}
}
@@ -10437,7 +10437,7 @@
}
private void setShowNewUserDisclaimer(@UserIdInt int userId, String value) {
- Slog.i(LOG_TAG, "Setting new user disclaimer for user " + userId + " as " + value);
+ Slogf.i(LOG_TAG, "Setting new user disclaimer for user " + userId + " as " + value);
synchronized (getLockObject()) {
DevicePolicyData policyData = getUserData(userId);
policyData.mNewUserDisclaimer = value;
@@ -10450,7 +10450,7 @@
synchronized (getLockObject()) {
DevicePolicyData policyData = getUserData(userId);
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "showNewUserDisclaimerIfNecessary(" + userId + "): "
+ Slogf.v(LOG_TAG, "showNewUserDisclaimerIfNecessary(" + userId + "): "
+ policyData.mNewUserDisclaimer + ")");
}
mustShow = DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED
@@ -10461,7 +10461,7 @@
Intent intent = new Intent(DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER);
// TODO(b/172691310): add CTS tests to make sure disclaimer is shown
- Slog.i(LOG_TAG, "Dispatching ACTION_SHOW_NEW_USER_DISCLAIMER intent");
+ Slogf.i(LOG_TAG, "Dispatching ACTION_SHOW_NEW_USER_DISCLAIMER intent");
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
@@ -10478,7 +10478,7 @@
? UserManager.DISALLOW_REMOVE_MANAGED_PROFILE
: UserManager.DISALLOW_REMOVE_USER;
if (isAdminAffectedByRestriction(who, restriction, caller.getUserId())) {
- Slog.w(LOG_TAG, "The device owner cannot remove a user because %s is enabled, and "
+ Slogf.w(LOG_TAG, "The device owner cannot remove a user because %s is enabled, and "
+ "was not set by the device owner", restriction);
return false;
}
@@ -10516,7 +10516,7 @@
}
return mInjector.getIActivityManager().switchUser(userId);
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Couldn't switch user", e);
+ Slogf.e(LOG_TAG, "Couldn't switch user", e);
return false;
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -10534,19 +10534,19 @@
final int userId = userHandle.getIdentifier();
if (isManagedProfile(userId)) {
- Slog.w(LOG_TAG, "Managed profile cannot be started in background");
+ Slogf.w(LOG_TAG, "Managed profile cannot be started in background");
return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
}
final long id = mInjector.binderClearCallingIdentity();
try {
if (!mInjector.getActivityManagerInternal().canStartMoreUsers()) {
- Slog.w(LOG_TAG, "Cannot start user %d, too many users in background", userId);
+ Slogf.w(LOG_TAG, "Cannot start user %d, too many users in background", userId);
return UserManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS;
}
if (mInjector.getIActivityManager().startUserInBackground(userId)) {
- Slog.i(LOG_TAG, "Started used %d in background", userId);
+ Slogf.i(LOG_TAG, "Started used %d in background", userId);
return UserManager.USER_OPERATION_SUCCESS;
} else {
return UserManager.USER_OPERATION_ERROR_UNKNOWN;
@@ -10569,7 +10569,7 @@
final int userId = userHandle.getIdentifier();
if (isManagedProfile(userId)) {
- Slog.w(LOG_TAG, "Managed profile cannot be stopped");
+ Slogf.w(LOG_TAG, "Managed profile cannot be stopped");
return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
}
@@ -10592,14 +10592,14 @@
}
if (isManagedProfile(callingUserId)) {
- Slog.w(LOG_TAG, "Managed profile cannot be logout");
+ Slogf.w(LOG_TAG, "Managed profile cannot be logout");
return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
}
final long id = mInjector.binderClearCallingIdentity();
try {
if (!mInjector.getIActivityManager().switchUser(UserHandle.USER_SYSTEM)) {
- Slog.w(LOG_TAG, "Failed to switch to primary user");
+ Slogf.w(LOG_TAG, "Failed to switch to primary user");
// This should never happen as target user is UserHandle.USER_SYSTEM
return UserManager.USER_OPERATION_ERROR_UNKNOWN;
}
@@ -10735,7 +10735,7 @@
suspended, null, null, null, PLATFORM_PACKAGE_NAME, caller.getUserId());
} catch (RemoteException re) {
// Shouldn't happen.
- Slog.e(LOG_TAG, "Failed talking to the package manager", re);
+ Slogf.e(LOG_TAG, "Failed talking to the package manager", re);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -10748,7 +10748,7 @@
.write();
if (nonSuspendedPackages == null) {
- Slog.w(LOG_TAG, "PM failed to suspend packages (%s)", Arrays.toString(packageNames));
+ Slogf.w(LOG_TAG, "PM failed to suspend packages (%s)", Arrays.toString(packageNames));
return packageNames;
}
if (exemptApps.isEmpty()) {
@@ -10756,7 +10756,7 @@
}
String[] result = buildNonSuspendedPackagesUnionArray(nonSuspendedPackages, exemptApps);
- if (VERBOSE_LOG) Slog.v(LOG_TAG, "Returning %s", Arrays.toString(result));
+ if (VERBOSE_LOG) Slogf.v(LOG_TAG, "Returning %s", Arrays.toString(result));
return result;
}
@@ -10790,7 +10790,7 @@
return mIPackageManager.isPackageSuspendedForUser(packageName, caller.getUserId());
} catch (RemoteException re) {
// Shouldn't happen.
- Slog.e(LOG_TAG, "Failed talking to the package manager", re);
+ Slogf.e(LOG_TAG, "Failed talking to the package manager", re);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -10978,7 +10978,7 @@
List<String> exemptApps = listPolicyExemptAppsUnchecked();
if (exemptApps.contains(packageName)) {
- Slog.d(LOG_TAG, "setApplicationHidden(): ignoring %s as it's on policy-exempt list",
+ Slogf.d(LOG_TAG, "setApplicationHidden(): ignoring %s as it's on policy-exempt list",
packageName);
return false;
}
@@ -10998,7 +10998,7 @@
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_APPLICATION_HIDDEN);
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "calling pm.setApplicationHiddenSettingAsUser(%s, %b, %d)",
+ Slogf.v(LOG_TAG, "calling pm.setApplicationHiddenSettingAsUser(%s, %b, %d)",
packageName, hidden, userId);
}
result = mInjector.binderWithCleanCallingIdentity(() -> mIPackageManager
@@ -11064,7 +11064,7 @@
long id = mInjector.binderClearCallingIdentity();
try {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "installing " + packageName + " for " + userId);
+ Slogf.v(LOG_TAG, "installing " + packageName + " for " + userId);
}
Preconditions.checkArgument(isDemo || isSystemApp(mIPackageManager, packageName,
@@ -11082,7 +11082,7 @@
}
} catch (RemoteException re) {
// shouldn't happen
- Slog.wtf(LOG_TAG, "Failed to install " + packageName, re);
+ Slogf.wtf(LOG_TAG, "Failed to install " + packageName, re);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -11116,7 +11116,7 @@
.getList();
if (VERBOSE_LOG) {
- Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
+ Slogf.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
}
if (activitiesToEnable != null) {
for (ResolveInfo info : activitiesToEnable) {
@@ -11129,7 +11129,7 @@
PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
PackageManager.INSTALL_REASON_POLICY, null);
} else {
- Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
+ Slogf.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
+ " system app");
}
}
@@ -11137,7 +11137,7 @@
}
} catch (RemoteException e) {
// shouldn't happen
- Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
+ Slogf.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
return 0;
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -11181,7 +11181,7 @@
final long id = mInjector.binderClearCallingIdentity();
try {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "installing " + packageName + " for " + caller.getUserId());
+ Slogf.v(LOG_TAG, "installing " + packageName + " for " + caller.getUserId());
}
// Install the package.
@@ -11294,7 +11294,7 @@
mIPackageManager.setBlockUninstallForUser(packageName, uninstallBlocked, userId);
} catch (RemoteException re) {
// Shouldn't happen.
- Slog.e(LOG_TAG, "Failed to setBlockUninstallForUser", re);
+ Slogf.e(LOG_TAG, "Failed to setBlockUninstallForUser", re);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -11332,7 +11332,7 @@
return mIPackageManager.getBlockUninstallForUser(packageName, userId);
} catch (RemoteException re) {
// Shouldn't happen.
- Slog.e(LOG_TAG, "Failed to getBlockUninstallForUser", re);
+ Slogf.e(LOG_TAG, "Failed to getBlockUninstallForUser", re);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -11457,7 +11457,7 @@
}
if (isCrossProfileQuickContactDisabled(managedUserId)) {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "Cross-profile contacts access disabled for user %d",
+ Slogf.v(LOG_TAG, "Cross-profile contacts access disabled for user %d",
managedUserId);
}
return;
@@ -11481,16 +11481,16 @@
* Otherwise -1.
*/
public int getManagedUserId(@UserIdInt int callingUserId) {
- if (VERBOSE_LOG) Slog.v(LOG_TAG, "getManagedUserId: callingUserId=%d", callingUserId);
+ if (VERBOSE_LOG) Slogf.v(LOG_TAG, "getManagedUserId: callingUserId=%d", callingUserId);
for (UserInfo ui : mUserManager.getProfiles(callingUserId)) {
if (ui.id == callingUserId || !ui.isManagedProfile()) {
continue; // Caller user self, or not a managed profile. Skip.
}
- if (VERBOSE_LOG) Slog.v(LOG_TAG, "Managed user=%d", ui.id);
+ if (VERBOSE_LOG) Slogf.v(LOG_TAG, "Managed user=%d", ui.id);
return ui.id;
}
- if (VERBOSE_LOG) Slog.v(LOG_TAG, "Managed user not found.");
+ if (VERBOSE_LOG) Slogf.v(LOG_TAG, "Managed user not found.");
return -1;
}
@@ -11724,13 +11724,13 @@
final List<String> lockTaskPackages = getUserData(userId).mLockTaskPackages;
if (!lockTaskPackages.isEmpty()) {
- Slog.d(LOG_TAG,
+ Slogf.d(LOG_TAG,
"User id " + userId + " not affiliated. Clearing lock task packages");
setLockTaskPackagesLocked(userId, Collections.<String>emptyList());
}
final int lockTaskFeatures = getUserData(userId).mLockTaskFeatures;
if (lockTaskFeatures != DevicePolicyManager.LOCK_TASK_FEATURE_NONE){
- Slog.d(LOG_TAG,
+ Slogf.d(LOG_TAG,
"User id " + userId + " not affiliated. Clearing lock task features");
setLockTaskFeaturesLocked(userId, DevicePolicyManager.LOCK_TASK_FEATURE_NONE);
}
@@ -11789,7 +11789,7 @@
// Some settings are no supported any more. However we do not want to throw a
// SecurityException to avoid breaking apps.
if (GLOBAL_SETTINGS_DEPRECATED.contains(setting)) {
- Slog.i(LOG_TAG, "Global setting no longer supported: %s", setting);
+ Slogf.i(LOG_TAG, "Global setting no longer supported: %s", setting);
return;
}
@@ -11910,7 +11910,7 @@
if (targetInfo != null) {
intent.setComponent(targetInfo.getComponentName());
} else {
- Slog.wtf(LOG_TAG, "Failed to resolve intent for location settings");
+ Slogf.wtf(LOG_TAG, "Failed to resolve intent for location settings");
}
// Simple notification clicks are immutable
@@ -12005,7 +12005,7 @@
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY + " instead.");
}
if (!mUserManager.isManagedProfile(callingUserId)) {
- Slog.e(LOG_TAG, "Ignoring setSecureSetting request for "
+ Slogf.e(LOG_TAG, "Ignoring setSecureSetting request for "
+ setting + ". User restriction "
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES + " or "
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY
@@ -12020,7 +12020,7 @@
.setStrings(setting, value)
.write();
} catch (NumberFormatException exc) {
- Slog.e(LOG_TAG, "Invalid value: " + value + " for setting " + setting);
+ Slogf.e(LOG_TAG, "Invalid value: " + value + " for setting " + setting);
}
}
return;
@@ -12171,7 +12171,7 @@
isLockTaskMode = mInjector.getIActivityTaskManager().getLockTaskModeState()
!= LOCK_TASK_MODE_NONE;
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Failed to get LockTask mode");
+ Slogf.e(LOG_TAG, "Failed to get LockTask mode");
}
if (!isLockTaskMode) {
if (!setStatusBarDisabledInternal(disabled, userId)) {
@@ -12203,7 +12203,7 @@
return true;
}
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Failed to disable the status bar", e);
+ Slogf.e(LOG_TAG, "Failed to disable the status bar", e);
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
@@ -12535,7 +12535,7 @@
synchronized (getLockObject()) {
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_PRINTING,
UserHandle.of(userId))) {
- Slog.e(LOG_TAG, "printing is enabled for user %d", userId);
+ Slogf.e(LOG_TAG, "printing is enabled for user %d", userId);
return null;
}
String ownerPackage = mOwners.getProfileOwnerPackage(userId);
@@ -12548,22 +12548,22 @@
try {
return pm.getPackageInfo(packageName, 0);
} catch (NameNotFoundException e) {
- Slog.e(LOG_TAG, "getPackageInfo error", e);
+ Slogf.e(LOG_TAG, "getPackageInfo error", e);
return null;
}
});
if (packageInfo == null) {
- Slog.e(LOG_TAG, "packageInfo is inexplicably null");
+ Slogf.e(LOG_TAG, "packageInfo is inexplicably null");
return null;
}
ApplicationInfo appInfo = packageInfo.applicationInfo;
if (appInfo == null) {
- Slog.e(LOG_TAG, "appInfo is inexplicably null");
+ Slogf.e(LOG_TAG, "appInfo is inexplicably null");
return null;
}
CharSequence appLabel = pm.getApplicationLabel(appInfo);
if (appLabel == null) {
- Slog.e(LOG_TAG, "appLabel is inexplicably null");
+ Slogf.e(LOG_TAG, "appLabel is inexplicably null");
return null;
}
return ((Context) ActivityThread.currentActivityThread().getSystemUiContext())
@@ -12617,7 +12617,7 @@
Objects.requireNonNull(intent);
Objects.requireNonNull(parentHandle);
final int userId = parentHandle.getIdentifier();
- Slog.i(LOG_TAG, "Sending %s broadcast to manifest receivers.", intent.getAction());
+ Slogf.i(LOG_TAG, "Sending %s broadcast to manifest receivers.", intent.getAction());
try {
final List<ResolveInfo> receivers = mIPackageManager.queryIntentReceivers(
intent, /* resolvedType= */ null,
@@ -12627,7 +12627,7 @@
if (checkCrossProfilePackagePermissions(packageName, userId,
requiresPermission)
|| checkModifyQuietModePermission(packageName, userId)) {
- Slog.i(LOG_TAG, "Sending %s broadcast to %s.", intent.getAction(),
+ Slogf.i(LOG_TAG, "Sending %s broadcast to %s.", intent.getAction(),
packageName);
final Intent packageIntent = new Intent(intent)
.setComponent(receiver.getComponentInfo().getComponentName())
@@ -12636,7 +12636,7 @@
}
}
} catch (RemoteException ex) {
- Slog.w(LOG_TAG, "Cannot get list of broadcast receivers for %s because: %s.",
+ Slogf.w(LOG_TAG, "Cannot get list of broadcast receivers for %s because: %s.",
intent.getAction(), ex);
}
}
@@ -12655,7 +12655,7 @@
android.Manifest.permission.MODIFY_QUIET_MODE, uid, /* owningUid= */
-1, /* exported= */ true);
} catch (NameNotFoundException ex) {
- Slog.w(LOG_TAG, "Cannot find the package %s to check for permissions.",
+ Slogf.w(LOG_TAG, "Cannot find the package %s to check for permissions.",
packageName);
return false;
}
@@ -12685,7 +12685,7 @@
return crossProfileAppsService.verifyPackageHasInteractAcrossProfilePermission(
packageName, userId);
} catch (NameNotFoundException ex) {
- Slog.w(LOG_TAG, "Cannot find the package %s to check for permissions.",
+ Slogf.w(LOG_TAG, "Cannot find the package %s to check for permissions.",
packageName);
return false;
}
@@ -12760,7 +12760,7 @@
// TODO(b/178494483): use EventLog instead
// TODO(b/178494483): log metrics?
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "notifyUnsafeOperationStateChanged(): %s=%b",
+ Slogf.v(LOG_TAG, "notifyUnsafeOperationStateChanged(): %s=%b",
DevicePolicyManager.operationSafetyReasonToString(reason), isSafe);
}
Preconditions.checkArgument(mSafetyChecker == checker,
@@ -12771,12 +12771,12 @@
extras.putBoolean(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_STATE, isSafe);
if (mOwners.hasDeviceOwner()) {
- if (VERBOSE_LOG) Slog.v(LOG_TAG, "Notifying DO");
+ if (VERBOSE_LOG) Slogf.v(LOG_TAG, "Notifying DO");
sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
extras);
}
for (int profileOwnerId : mOwners.getProfileOwnerKeys()) {
- if (VERBOSE_LOG) Slog.v(LOG_TAG, "Notifying PO for user " + profileOwnerId);
+ if (VERBOSE_LOG) Slogf.v(LOG_TAG, "Notifying PO for user " + profileOwnerId);
sendProfileOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
extras, profileOwnerId);
}
@@ -12893,7 +12893,7 @@
synchronized (getLockObject()) {
SystemUpdatePolicy policy = mOwners.getSystemUpdatePolicy();
if (policy != null && !policy.isValid()) {
- Slog.w(LOG_TAG, "Stored system update policy is invalid, return null instead.");
+ Slogf.w(LOG_TAG, "Stored system update policy is invalid, return null instead.");
return null;
}
return policy;
@@ -12922,7 +12922,7 @@
* @see SystemUpdatePolicy#validateAgainstPreviousFreezePeriod
*/
private void updateSystemUpdateFreezePeriodsRecord(boolean saveIfChanged) {
- Slog.d(LOG_TAG, "updateSystemUpdateFreezePeriodsRecord");
+ Slogf.d(LOG_TAG, "updateSystemUpdateFreezePeriodsRecord");
synchronized (getLockObject()) {
final SystemUpdatePolicy policy = mOwners.getSystemUpdatePolicy();
if (policy == null) {
@@ -12972,7 +12972,7 @@
+ "clearSystemUpdatePolicyFreezePeriodRecord");
synchronized (getLockObject()) {
// Print out current record to help diagnosed CTS failures
- Slog.i(LOG_TAG, "Clear freeze period record: "
+ Slogf.i(LOG_TAG, "Clear freeze period record: "
+ mOwners.getSystemUpdateFreezePeriodRecordAsString());
if (mOwners.setSystemUpdateFreezePeriodRecord(null, null)) {
mOwners.writeDeviceOwner();
@@ -13013,8 +13013,8 @@
"Only the system update service can broadcast update information");
if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
- Slog.w(LOG_TAG, "Only the system update service in the system user " +
- "can broadcast update information.");
+ Slogf.w(LOG_TAG, "Only the system update service in the system user can broadcast "
+ + "update information.");
return;
}
@@ -13043,7 +13043,7 @@
runningUserIds = mInjector.getIActivityManager().getRunningUserIds();
} catch (RemoteException e) {
// Shouldn't happen.
- Slog.e(LOG_TAG, "Could not retrieve the list of running users", e);
+ Slogf.e(LOG_TAG, "Could not retrieve the list of running users", e);
return;
}
// Send broadcasts to corresponding profile owners if any.
@@ -13171,7 +13171,7 @@
});
}
} catch (SecurityException e) {
- Slog.e(LOG_TAG, "Could not set permission grant state", e);
+ Slogf.e(LOG_TAG, "Could not set permission grant state", e);
callback.sendResult(null);
} finally {
@@ -13288,7 +13288,7 @@
}
final int code = checkProvisioningPreConditionSkipPermissionNoLog(action, packageName);
if (code != CODE_OK) {
- Slog.d(LOG_TAG, "checkProvisioningPreCondition(" + action + ", " + packageName
+ Slogf.d(LOG_TAG, "checkProvisioningPreCondition(" + action + ", " + packageName
+ ") failed: "
+ computeProvisioningErrorString(code, mInjector.userHandleGetCallingUserId()));
}
@@ -13353,7 +13353,7 @@
if (isHeadlessSystemUserMode) {
if (deviceOwnerUserId != UserHandle.USER_SYSTEM) {
- Slog.e(LOG_TAG, "In headless system user mode, "
+ Slogf.e(LOG_TAG, "In headless system user mode, "
+ "device owner can only be set on headless system user.");
return CODE_NOT_SYSTEM_USER;
}
@@ -13377,7 +13377,7 @@
if (callingUserId != currentForegroundUser
&& mInjector.userManagerIsHeadlessSystemUserMode()
&& currentForegroundUser == UserHandle.USER_SYSTEM) {
- Slog.wtf(LOG_TAG, "In headless system user mode, "
+ Slogf.wtf(LOG_TAG, "In headless system user mode, "
+ "current user cannot be system user when setting device owner");
return CODE_SYSTEM_USER;
}
@@ -13404,7 +13404,7 @@
final int deviceOwnerUserId = mInjector.userManagerIsHeadlessSystemUserMode()
? UserHandle.USER_SYSTEM
: callingUserId;
- Slog.i(LOG_TAG, "Calling user %d, device owner will be set on user %d",
+ Slogf.i(LOG_TAG, "Calling user %d, device owner will be set on user %d",
callingUserId, deviceOwnerUserId);
// hasIncompatibleAccountsOrNonAdb doesn't matter since the caller is not adb.
return checkDeviceOwnerProvisioningPreConditionLocked(/* owner unknown */ null,
@@ -13435,7 +13435,8 @@
UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserHandle);
if (mUserManager.getUserInfo(callingUserId).isProfile()) {
- Slog.i(LOG_TAG, "Calling user %d is a profile, cannot add another.", callingUserId);
+ Slogf.i(LOG_TAG, "Calling user %d is a profile, cannot add another.",
+ callingUserId);
// The check is called from inside a managed profile. A managed profile cannot
// be provisioned from within another managed profile.
return CODE_CANNOT_ADD_MANAGED_PROFILE;
@@ -13443,12 +13444,12 @@
// If there's a device owner, the restriction on adding a managed profile must be set.
if (hasDeviceOwner && !addingProfileRestricted) {
- Slog.wtf(LOG_TAG, "Has a device owner but no restriction on adding a profile.");
+ Slogf.wtf(LOG_TAG, "Has a device owner but no restriction on adding a profile.");
}
// Do not allow adding a managed profile if there's a restriction.
if (addingProfileRestricted) {
- Slog.i(LOG_TAG, "Adding a profile is restricted: User %s Has device owner? %b",
+ Slogf.i(LOG_TAG, "Adding a profile is restricted: User %s Has device owner? %b",
callingUserHandle, hasDeviceOwner);
return CODE_CANNOT_ADD_MANAGED_PROFILE;
}
@@ -13456,7 +13457,7 @@
// Bail out if we are trying to provision a work profile but one already exists.
if (!mUserManager.canAddMoreManagedProfiles(
callingUserId, /* allowedToRemoveOne= */ false)) {
- Slog.i(LOG_TAG, "A work profile already exists.");
+ Slogf.i(LOG_TAG, "A work profile already exists.");
return CODE_CANNOT_ADD_MANAGED_PROFILE;
}
} finally {
@@ -13944,7 +13945,7 @@
who.flattenToString(), userId));
}
- Slog.i(LOG_TAG, "Marking %s as profile owner on organization-owned device for user %d",
+ Slogf.i(LOG_TAG, "Marking %s as profile owner on organization-owned device for user %d",
who.flattenToString(), userId);
// First, set restriction on removing the profile.
@@ -14089,7 +14090,7 @@
for (int i = 0; i < userInfos.size(); i++) {
int userId = userInfos.get(i).id;
if (!isUserAffiliatedWithDeviceLocked(userId)) {
- Slog.d(LOG_TAG, "User id " + userId + " not affiliated.");
+ Slogf.d(LOG_TAG, "User id " + userId + " not affiliated.");
return false;
}
}
@@ -14218,7 +14219,7 @@
}
return new ParceledListSlice<SecurityEvent>(output);
} catch (IOException e) {
- Slog.w(LOG_TAG, "Fail to read previous events" , e);
+ Slogf.w(LOG_TAG, "Fail to read previous events" , e);
return new ParceledListSlice<SecurityEvent>(Collections.<SecurityEvent>emptyList());
}
}
@@ -14387,7 +14388,7 @@
try { // force stop the package before uninstalling
mInjector.getIActivityManager().forceStopPackage(packageName, userId);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Failure talking to ActivityManager while force stopping package");
+ Slogf.e(LOG_TAG, "Failure talking to ActivityManager while force stopping package");
}
final Uri packageURI = Uri.parse("package:" + packageName);
final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
@@ -14423,7 +14424,7 @@
updateMaximumTimeToLockLocked(userHandle);
policy.mRemovingAdmins.remove(adminReceiver);
- Slog.i(LOG_TAG, "Device admin " + adminReceiver + " removed from user " + userHandle);
+ Slogf.i(LOG_TAG, "Device admin " + adminReceiver + " removed from user " + userHandle);
}
// The removed admin might have disabled camera, so update user
// restrictions.
@@ -14643,7 +14644,7 @@
}
synchronized (getLockObject()) {
if (owner == null || !isAdminTestOnlyLocked(owner, userId)) {
- Slog.w(LOG_TAG,
+ Slogf.w(LOG_TAG,
"Non test-only owner can't be installed with existing accounts.");
return true;
}
@@ -14657,20 +14658,20 @@
boolean compatible = true;
for (Account account : accounts) {
if (hasAccountFeatures(am, account, feature_disallow)) {
- Slog.e(LOG_TAG, "%s has %s", account, feature_disallow[0]);
+ Slogf.e(LOG_TAG, "%s has %s", account, feature_disallow[0]);
compatible = false;
break;
}
if (!hasAccountFeatures(am, account, feature_allow)) {
- Slog.e(LOG_TAG, "%s doesn't have %s", account, feature_allow[0]);
+ Slogf.e(LOG_TAG, "%s doesn't have %s", account, feature_allow[0]);
compatible = false;
break;
}
}
if (compatible) {
- Slog.w(LOG_TAG, "All accounts are compatible");
+ Slogf.w(LOG_TAG, "All accounts are compatible");
} else {
- Slog.e(LOG_TAG, "Found incompatible accounts");
+ Slogf.e(LOG_TAG, "Found incompatible accounts");
}
return !compatible;
});
@@ -14680,7 +14681,7 @@
try {
return am.hasFeatures(account, features, null, null).getResult();
} catch (Exception e) {
- Slog.w(LOG_TAG, "Failed to get account feature", e);
+ Slogf.w(LOG_TAG, "Failed to get account feature", e);
return false;
}
}
@@ -14740,14 +14741,14 @@
}
if (!mNetworkLogger.startNetworkLogging()) {
mNetworkLogger = null;
- Slog.wtf(LOG_TAG, "Network logging could not be started due to the logging"
+ Slogf.wtf(LOG_TAG, "Network logging could not be started due to the logging"
+ " service not being available yet.");
}
maybePauseDeviceWideLoggingLocked();
sendNetworkLoggingNotificationLocked();
} else {
if (mNetworkLogger != null && !mNetworkLogger.stopNetworkLogging()) {
- Slog.wtf(LOG_TAG, "Network logging could not be stopped due to the logging"
+ Slogf.wtf(LOG_TAG, "Network logging could not be stopped due to the logging"
+ " service not being available yet.");
}
mNetworkLogger = null;
@@ -14799,14 +14800,14 @@
private void maybePauseDeviceWideLoggingLocked() {
if (!areAllUsersAffiliatedWithDeviceLocked()) {
if (mOwners.hasDeviceOwner()) {
- Slog.i(LOG_TAG, "There are unaffiliated users, network logging will be "
+ Slogf.i(LOG_TAG, "There are unaffiliated users, network logging will be "
+ "paused if enabled.");
if (mNetworkLogger != null) {
mNetworkLogger.pause();
}
}
if (!isOrganizationOwnedDeviceWithManagedProfile()) {
- Slog.i(LOG_TAG, "Not org-owned managed profile device, security logging will be "
+ Slogf.i(LOG_TAG, "Not org-owned managed profile device, security logging will be "
+ "paused if enabled.");
mSecurityLogMonitor.pause();
}
@@ -14980,7 +14981,7 @@
0, // flags
targetUserId);
if (info == null || info.serviceInfo == null) {
- Slog.e(LOG_TAG, "Fail to look up the service: %s or user %d is not running", rawIntent,
+ Slogf.e(LOG_TAG, "Fail to look up the service: %s or user %d is not running", rawIntent,
targetUserId);
return null;
}
@@ -15116,7 +15117,7 @@
return resetPasswordInternal(password, policy.mPasswordTokenHandle, token,
flags, caller);
} else {
- Slog.w(LOG_TAG, "No saved token handle");
+ Slogf.w(LOG_TAG, "No saved token handle");
}
}
return false;
@@ -15166,8 +15167,8 @@
// This can happen e.g. for device admin packages, do not throw out the exception,
// because callers have no means to know beforehand for which packages this might
// happen. If so, we send back that removal failed.
- Slog.w(LOG_TAG, "Not allowed to clear application user data for package " + packageName,
- se);
+ Slogf.w(LOG_TAG, "Not allowed to clear application user data for package "
+ + packageName, se);
try {
callback.onRemoveCompleted(packageName, false);
} catch (RemoteException re) {
@@ -15323,7 +15324,7 @@
int profileOwnerUserId) {
transferActiveAdminUncheckedLocked(target, admin, profileOwnerUserId);
mOwners.transferProfileOwner(target, profileOwnerUserId);
- Slog.i(LOG_TAG, "Profile owner set: " + target + " on user " + profileOwnerUserId);
+ Slogf.i(LOG_TAG, "Profile owner set: " + target + " on user " + profileOwnerUserId);
mOwners.writeProfileOwner(profileOwnerUserId);
mDeviceAdminServiceController.startServiceForOwner(
target.getPackageName(), profileOwnerUserId, "transfer-profile-owner");
@@ -15335,7 +15336,7 @@
private void transferDeviceOwnershipLocked(ComponentName admin, ComponentName target, int userId) {
transferActiveAdminUncheckedLocked(target, admin, userId);
mOwners.transferDeviceOwnership(target);
- Slog.i(LOG_TAG, "Device owner set: " + target + " on user " + userId);
+ Slogf.i(LOG_TAG, "Device owner set: " + target + " on user " + userId);
mOwners.writeDeviceOwner();
mDeviceAdminServiceController.startServiceForOwner(
target.getPackageName(), userId, "transfer-device-owner");
@@ -15453,7 +15454,7 @@
parser.next();
return PersistableBundle.restoreFromXml(parser);
} catch (IOException | XmlPullParserException | IllegalArgumentException e) {
- Slog.e(LOG_TAG, "Caught exception while trying to load the "
+ Slogf.e(LOG_TAG, "Caught exception while trying to load the "
+ "owner transfer parameters from file " + bundleFile, e);
return null;
}
@@ -15475,7 +15476,7 @@
return mInjector.binderWithCleanCallingIdentity(
() -> tm.addDevicePolicyOverrideApn(mContext, apnSetting));
} else {
- Slog.w(LOG_TAG, "TelephonyManager is null when trying to add override apn");
+ Slogf.w(LOG_TAG, "TelephonyManager is null when trying to add override apn");
return Telephony.Carriers.INVALID_APN_ID;
}
}
@@ -15499,7 +15500,7 @@
return mInjector.binderWithCleanCallingIdentity(
() -> tm.modifyDevicePolicyOverrideApn(mContext, apnId, apnSetting));
} else {
- Slog.w(LOG_TAG, "TelephonyManager is null when trying to modify override apn");
+ Slogf.w(LOG_TAG, "TelephonyManager is null when trying to modify override apn");
return false;
}
}
@@ -15542,7 +15543,7 @@
return mInjector.binderWithCleanCallingIdentity(
() -> tm.getDevicePolicyOverrideApns(mContext));
}
- Slog.w(LOG_TAG, "TelephonyManager is null when trying to get override apns");
+ Slogf.w(LOG_TAG, "TelephonyManager is null when trying to get override apns");
return Collections.emptyList();
}
@@ -15587,7 +15588,7 @@
return enforceCursor.getInt(enforceCursor.getColumnIndex(ENFORCE_KEY)) == 1;
}
} catch (IllegalArgumentException e) {
- Slog.e(LOG_TAG, "Cursor returned from ENFORCE_MANAGED_URI doesn't contain "
+ Slogf.e(LOG_TAG, "Cursor returned from ENFORCE_MANAGED_URI doesn't contain "
+ "correct info.", e);
} finally {
enforceCursor.close();
@@ -15612,7 +15613,7 @@
serializer.endDocument();
atomicFile.finishWrite(stream);
} catch (IOException | XmlPullParserException e) {
- Slog.e(LOG_TAG, "Caught exception while trying to save the "
+ Slogf.e(LOG_TAG, "Caught exception while trying to save the "
+ "owner transfer parameters to file " + parametersFile, e);
parametersFile.delete();
atomicFile.failWrite(stream);
@@ -16042,7 +16043,7 @@
return false;
}
if (!isPackageAllowedToAccessCalendarForUser(packageName, workProfileUserId)) {
- Slog.d(LOG_TAG, "Package %s is not allowed to access cross-profile calendar APIs",
+ Slogf.d(LOG_TAG, "Package %s is not allowed to access cross-profile calendar APIs",
packageName);
return false;
}
@@ -16057,7 +16058,7 @@
try {
mContext.startActivityAsUser(intent, UserHandle.of(workProfileUserId));
} catch (ActivityNotFoundException e) {
- Slog.e(LOG_TAG, "View event activity not found", e);
+ Slogf.e(LOG_TAG, "View event activity not found", e);
return false;
}
return true;
@@ -16071,7 +16072,7 @@
packageName, UserHandle.getUserId(callingUid));
return packageUid == callingUid;
} catch (NameNotFoundException e) {
- Slog.d(LOG_TAG, "Calling package not found", e);
+ Slogf.d(LOG_TAG, "Calling package not found", e);
return false;
}
});
@@ -16181,7 +16182,7 @@
final long deadline = admin.mProfileOffDeadline;
final int result = makeSuspensionReasons(admin.mSuspendPersonalApps,
deadline != 0 && mInjector.systemCurrentTimeMillis() > deadline);
- Slog.d(LOG_TAG, "getPersonalAppsSuspendedReasons user: %d; result: %d",
+ Slogf.d(LOG_TAG, "getPersonalAppsSuspendedReasons user: %d; result: %d",
mInjector.userHandleGetCallingUserId(), result);
return result;
}
@@ -16239,7 +16240,7 @@
synchronized (getLockObject()) {
final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(profileUserId);
if (profileOwner == null) {
- Slog.wtf(LOG_TAG, "Profile owner not found for compliance check");
+ Slogf.wtf(LOG_TAG, "Profile owner not found for compliance check");
return;
}
if (suspended) {
@@ -16271,7 +16272,7 @@
updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked);
final boolean suspendedExplicitly = profileOwner.mSuspendPersonalApps;
final boolean suspendedByTimeout = profileOwner.mProfileOffDeadline == -1;
- Slog.d(LOG_TAG,
+ Slogf.d(LOG_TAG,
"Personal apps suspended explicitly: %b, by timeout: %b, notification: %d",
suspendedExplicitly, suspendedByTimeout, notificationState);
updateProfileOffDeadlineNotificationLocked(
@@ -16296,7 +16297,7 @@
int profileUserId, ActiveAdmin profileOwner, boolean unlocked) {
final long now = mInjector.systemCurrentTimeMillis();
if (profileOwner.mProfileOffDeadline != 0 && now > profileOwner.mProfileOffDeadline) {
- Slog.i(LOG_TAG, "Profile off deadline has been reached, unlocked: " + unlocked);
+ Slogf.i(LOG_TAG, "Profile off deadline has been reached, unlocked: " + unlocked);
if (profileOwner.mProfileOffDeadline != -1) {
// Move the deadline far to the past so that it cannot be rolled back by TZ change.
profileOwner.mProfileOffDeadline = -1;
@@ -16315,14 +16316,14 @@
&& (profileOwner.mProfileMaximumTimeOffMillis == 0)) {
// There is a deadline but either there is no policy -> clear
// the deadline.
- Slog.i(LOG_TAG, "Profile off deadline is reset to zero");
+ Slogf.i(LOG_TAG, "Profile off deadline is reset to zero");
profileOwner.mProfileOffDeadline = 0;
shouldSaveSettings = true;
} else if (profileOwner.mProfileOffDeadline == 0
&& (profileOwner.mProfileMaximumTimeOffMillis != 0 && !unlocked)) {
// There profile is locked and there is a policy, but the deadline is not set -> set the
// deadline.
- Slog.i(LOG_TAG, "Profile off deadline is set.");
+ Slogf.i(LOG_TAG, "Profile off deadline is set.");
profileOwner.mProfileOffDeadline = now + profileOwner.mProfileMaximumTimeOffMillis;
shouldSaveSettings = true;
}
@@ -16357,10 +16358,10 @@
| PendingIntent.FLAG_IMMUTABLE);
if (alarmTime == 0) {
- Slog.i(LOG_TAG, "Profile off deadline alarm is removed.");
+ Slogf.i(LOG_TAG, "Profile off deadline alarm is removed.");
am.cancel(pi);
} else {
- Slog.i(LOG_TAG, "Profile off deadline alarm is set.");
+ Slogf.i(LOG_TAG, "Profile off deadline alarm is set.");
am.set(AlarmManager.RTC, alarmTime, pi);
}
@@ -16371,7 +16372,7 @@
if (getUserData(userId).mAppsSuspended == suspended) {
return;
}
- Slog.i(LOG_TAG, "%s personal apps for user %d", suspended ? "Suspending" : "Unsuspending",
+ Slogf.i(LOG_TAG, "%s personal apps for user %d", suspended ? "Suspending" : "Unsuspending",
userId);
if (suspended) {
@@ -16394,11 +16395,11 @@
final String[] failedApps = mIPackageManager.setPackagesSuspendedAsUser(
appsToSuspend, true, null, null, null, PLATFORM_PACKAGE_NAME, userId);
if (!ArrayUtils.isEmpty(failedApps)) {
- Slog.wtf(LOG_TAG, "Failed to suspend apps: " + String.join(",", failedApps));
+ Slogf.wtf(LOG_TAG, "Failed to suspend apps: " + String.join(",", failedApps));
}
} catch (RemoteException re) {
// Shouldn't happen.
- Slog.e(LOG_TAG, "Failed talking to the package manager", re);
+ Slogf.e(LOG_TAG, "Failed talking to the package manager", re);
}
});
}
@@ -16568,17 +16569,17 @@
poAppInfo = mIPackageManager.getApplicationInfo(
poAdmin.info.getPackageName(), 0 /* flags */, userId);
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Failed to query PO app info", e);
+ Slogf.e(LOG_TAG, "Failed to query PO app info", e);
return false;
}
if (poAppInfo == null) {
- Slog.wtf(LOG_TAG, "Cannot find AppInfo for profile owner");
+ Slogf.wtf(LOG_TAG, "Cannot find AppInfo for profile owner");
return false;
}
if (!poAppInfo.isEncryptionAware()) {
return false;
}
- Slog.d(LOG_TAG, "PO should be able to reset password from direct boot");
+ Slogf.d(LOG_TAG, "PO should be able to reset password from direct boot");
return true;
}
}
@@ -16618,7 +16619,7 @@
Preconditions.checkArgument(!TextUtils.isEmpty(organizationId),
"Enterprise ID may not be empty.");
- Slog.i(LOG_TAG, "Setting Enterprise ID to %s for user %d", organizationId, userId);
+ Slogf.i(LOG_TAG, "Setting Enterprise ID to %s for user %d", organizationId, userId);
final String ownerPackage;
synchronized (getLockObject()) {
@@ -16873,11 +16874,11 @@
final UserHandle sourceUser = UserHandle.of(sourceUserId);
final UserHandle targetUser = UserHandle.of(targetUserId);
if (accountToMigrate == null) {
- Slog.d(LOG_TAG, "No account to migrate.");
+ Slogf.d(LOG_TAG, "No account to migrate.");
return;
}
if (sourceUser.equals(targetUser)) {
- Slog.w(LOG_TAG, "sourceUser and targetUser are the same, won't migrate account.");
+ Slogf.w(LOG_TAG, "sourceUser and targetUser are the same, won't migrate account.");
return;
}
copyAccount(targetUser, sourceUser, accountToMigrate, callerPackage);
@@ -16906,15 +16907,15 @@
callerPackage);
} else {
logCopyAccountStatus(COPY_ACCOUNT_FAILED, callerPackage);
- Slog.e(LOG_TAG, "Failed to copy account to " + targetUser);
+ Slogf.e(LOG_TAG, "Failed to copy account to " + targetUser);
}
} catch (OperationCanceledException e) {
// Account migration is not considered a critical operation.
logCopyAccountStatus(COPY_ACCOUNT_TIMED_OUT, callerPackage);
- Slog.e(LOG_TAG, "Exception copying account to " + targetUser, e);
+ Slogf.e(LOG_TAG, "Exception copying account to " + targetUser, e);
} catch (AuthenticatorException | IOException e) {
logCopyAccountStatus(COPY_ACCOUNT_EXCEPTION, callerPackage);
- Slog.e(LOG_TAG, "Exception copying account to " + targetUser, e);
+ Slogf.e(LOG_TAG, "Exception copying account to " + targetUser, e);
}
}
@@ -16934,22 +16935,22 @@
try {
final Bundle result = bundle.getResult();
if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, /* default */ false)) {
- Slog.i(LOG_TAG, "Account removed from the primary user.");
+ Slogf.i(LOG_TAG, "Account removed from the primary user.");
} else {
// TODO(174768447): Revisit start activity logic.
final Intent removeIntent = result.getParcelable(AccountManager.KEY_INTENT);
removeIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
if (removeIntent != null) {
- Slog.i(LOG_TAG, "Starting activity to remove account");
+ Slogf.i(LOG_TAG, "Starting activity to remove account");
new Handler(Looper.getMainLooper()).post(() -> {
mContext.startActivity(removeIntent);
});
} else {
- Slog.e(LOG_TAG, "Could not remove account from the primary user.");
+ Slogf.e(LOG_TAG, "Could not remove account from the primary user.");
}
}
} catch (OperationCanceledException | AuthenticatorException | IOException e) {
- Slog.e(LOG_TAG, "Exception removing account from the primary user.", e);
+ Slogf.e(LOG_TAG, "Exception removing account from the primary user.", e);
}
}
@@ -17042,7 +17043,7 @@
}
} catch (Exception e) {
// Do not stop provisioning and ignore this error.
- Slog.e(LOG_TAG, "Alarm manager failed to set the system time/timezone.", e);
+ Slogf.e(LOG_TAG, "Alarm manager failed to set the system time/timezone.", e);
}
}
@@ -17056,7 +17057,7 @@
LocalePicker.updateLocale(locale);
} catch (Exception e) {
// Do not stop provisioning and ignore this error.
- Slog.e(LOG_TAG, "Failed to set the system locale.", e);
+ Slogf.e(LOG_TAG, "Failed to set the system locale.", e);
}
}
@@ -17069,21 +17070,21 @@
removeNonInstalledPackages(packagesToDelete, userId);
if (packagesToDelete.isEmpty()) {
- Slog.i(LOG_TAG, "No packages to delete on user " + userId);
+ Slogf.i(LOG_TAG, "No packages to delete on user " + userId);
return true;
}
NonRequiredPackageDeleteObserver packageDeleteObserver =
new NonRequiredPackageDeleteObserver(packagesToDelete.size());
for (String packageName : packagesToDelete) {
- Slog.i(LOG_TAG, "Deleting package [" + packageName + "] as user " + userId);
+ Slogf.i(LOG_TAG, "Deleting package [" + packageName + "] as user " + userId);
mContext.getPackageManager().deletePackageAsUser(
packageName,
packageDeleteObserver,
PackageManager.DELETE_SYSTEM_APP,
userId);
}
- Slog.i(LOG_TAG, "Waiting for non required apps to be deleted");
+ Slogf.i(LOG_TAG, "Waiting for non required apps to be deleted");
return packageDeleteObserver.awaitPackagesDeletion();
}
@@ -17099,7 +17100,7 @@
private void disallowAddUser() {
if (mInjector.userManagerIsHeadlessSystemUserMode()) {
- Slog.i(LOG_TAG, "Not setting DISALLOW_ADD_USER on headless system user mode.");
+ Slogf.i(LOG_TAG, "Not setting DISALLOW_ADD_USER on headless system user mode.");
return;
}
for (UserInfo userInfo : mUserManager.getUsers()) {
@@ -17286,7 +17287,7 @@
}
if (!mInjector.binderWithCleanCallingIdentity(
() -> mInjector.getUsbManager().enableUsbDataSignal(usbEnabled))) {
- Slog.w(LOG_TAG, "Failed to set usb data signaling state");
+ Slogf.w(LOG_TAG, "Failed to set usb data signaling state");
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
index 28a6987..964be38 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
@@ -26,10 +26,10 @@
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.service.persistentdata.PersistentDataBlockManager;
-import android.util.Slog;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.Preconditions;
+import com.android.server.utils.Slogf;
import java.io.IOException;
import java.util.Objects;
@@ -68,16 +68,16 @@
IResultReceiver receiver = new IResultReceiver.Stub() {
@Override
public void send(int resultCode, Bundle resultData) throws RemoteException {
- Slog.i(TAG, "Factory reset confirmed by %s, proceeding", mSafetyChecker);
+ Slogf.i(TAG, "Factory reset confirmed by %s, proceeding", mSafetyChecker);
try {
factoryResetInternalUnchecked();
} catch (IOException e) {
// Shouldn't happen
- Slog.wtf(TAG, e, "IOException calling underlying systems");
+ Slogf.wtf(TAG, e, "IOException calling underlying systems");
}
}
};
- Slog.i(TAG, "Delaying factory reset until %s confirms", mSafetyChecker);
+ Slogf.i(TAG, "Delaying factory reset until %s confirms", mSafetyChecker);
mSafetyChecker.onFactoryReset(receiver);
return false;
}
@@ -112,7 +112,7 @@
}
private void factoryResetInternalUnchecked() throws IOException {
- Slog.i(TAG, "factoryReset(): reason=%s, shutdown=%b, force=%b, wipeEuicc=%b, "
+ Slogf.i(TAG, "factoryReset(): reason=%s, shutdown=%b, force=%b, wipeEuicc=%b, "
+ "wipeAdoptableStorage=%b, wipeFRP=%b", mReason, mShutdown, mForce, mWipeEuicc,
mWipeAdoptableStorage, mWipeFactoryResetProtection);
@@ -125,15 +125,15 @@
PersistentDataBlockManager manager = mContext
.getSystemService(PersistentDataBlockManager.class);
if (manager != null) {
- Slog.w(TAG, "Wiping factory reset protection");
+ Slogf.w(TAG, "Wiping factory reset protection");
manager.wipe();
} else {
- Slog.w(TAG, "No need to wipe factory reset protection");
+ Slogf.w(TAG, "No need to wipe factory reset protection");
}
}
if (mWipeAdoptableStorage) {
- Slog.w(TAG, "Wiping adoptable storage");
+ Slogf.w(TAG, "Wiping adoptable storage");
StorageManager sm = mContext.getSystemService(StorageManager.class);
sm.wipeAdoptableDisks();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
index 0b9ece4..48d2d73 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
@@ -39,13 +39,13 @@
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.view.inputmethod.InputMethodInfo;
import com.android.internal.R;
import com.android.server.inputmethod.InputMethodManagerInternal;
+import com.android.server.utils.Slogf;
import java.util.ArrayList;
import java.util.Arrays;
@@ -109,7 +109,7 @@
}
if (Log.isLoggable(LOG_TAG, Log.INFO)) {
- Slog.i(LOG_TAG, "Packages subject to suspension: %s", String.join(",", result));
+ Slogf.i(LOG_TAG, "Packages subject to suspension: %s", String.join(",", result));
}
return result.toArray(new String[0]);
}
@@ -123,7 +123,7 @@
for (final ResolveInfo resolveInfo : matchingActivities) {
if (resolveInfo.activityInfo == null
|| TextUtils.isEmpty(resolveInfo.activityInfo.packageName)) {
- Slog.wtf(LOG_TAG, "Could not find package name for launcher app %s", resolveInfo);
+ Slogf.wtf(LOG_TAG, "Could not find package name for launcher app %s", resolveInfo);
continue;
}
final String packageName = resolveInfo.activityInfo.packageName;
@@ -134,7 +134,7 @@
result.add(packageName);
}
} catch (PackageManager.NameNotFoundException e) {
- Slog.e(LOG_TAG, "Could not find application info for launcher app: %s",
+ Slogf.e(LOG_TAG, "Could not find application info for launcher app: %s",
packageName);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
index 5f35a26..d7cbd9b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -45,11 +45,11 @@
import android.provider.Settings;
import android.text.format.DateUtils;
import android.util.Pair;
-import android.util.Slog;
import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.server.utils.Slogf;
import java.io.FileNotFoundException;
import java.lang.annotation.Retention;
@@ -135,7 +135,7 @@
if (targetInfo != null) {
dialogIntent.setComponent(targetInfo.getComponentName());
} else {
- Slog.wtf(LOG_TAG, "Failed to resolve intent for remote bugreport dialog");
+ Slogf.wtf(LOG_TAG, "Failed to resolve intent for remote bugreport dialog");
}
// Simple notification clicks are immutable
@@ -191,7 +191,7 @@
public boolean requestBugreport() {
if (mRemoteBugreportServiceIsActive.get()
|| (mService.getDeviceOwnerRemoteBugreportUriAndHash() != null)) {
- Slog.d(LOG_TAG, "Remote bugreport wasn't started because there's already one running.");
+ Slogf.d(LOG_TAG, "Remote bugreport wasn't started because there's already one running");
return false;
}
@@ -208,7 +208,7 @@
return true;
} catch (RemoteException re) {
// should never happen
- Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
+ Slogf.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
return false;
} finally {
mInjector.binderRestoreCallingIdentity(callingIdentity);
@@ -222,7 +222,7 @@
mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
} catch (IntentFilter.MalformedMimeTypeException e) {
// should never happen, as setting a constant
- Slog.w(LOG_TAG, e, "Failed to set type %s", BUGREPORT_MIMETYPE);
+ Slogf.w(LOG_TAG, e, "Failed to set type %s", BUGREPORT_MIMETYPE);
}
final IntentFilter filterConsent = new IntentFilter();
filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 63488f9..f843ea4 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -150,6 +150,11 @@
return ok();
}
+binder::Status BinderIncrementalService::onInstallationComplete(int32_t storageId) {
+ mImpl.onInstallationComplete(storageId);
+ return ok();
+}
+
binder::Status BinderIncrementalService::makeBindMount(int32_t storageId,
const std::string& sourcePath,
const std::string& targetFullPath,
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index ebb23dc..5c8741b 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -52,6 +52,8 @@
const ::android::sp<IStorageHealthListener>& healthListener,
const ::std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts,
bool* _aidl_return) final;
+ binder::Status onInstallationComplete(int32_t storageId) final;
+
binder::Status makeBindMount(int32_t storageId, const std::string& sourcePath,
const std::string& targetFullPath, int32_t bindType,
int32_t* _aidl_return) final;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 6695ba8..388f932 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -100,6 +100,12 @@
return (s & (Constants::blockSize - 1)) == 0;
}
+static bool getAlwaysEnableReadTimeoutsForSystemDataLoaders() {
+ return android::base::
+ GetBoolProperty("debug.incremental.always_enable_read_timeouts_for_system_dataloaders",
+ true);
+}
+
static bool getEnforceReadLogsMaxIntervalForSystemDataLoaders() {
return android::base::GetBoolProperty("debug.incremental.enforce_readlogs_max_interval_for_"
"system_dataloaders",
@@ -315,19 +321,11 @@
::rmdir(path::c_str(root));
}
-void IncrementalService::IncFsMount::setReadLogsEnabled(bool value) {
+void IncrementalService::IncFsMount::setFlag(StorageFlags flag, bool value) {
if (value) {
- flags |= StorageFlags::ReadLogsEnabled;
+ flags |= flag;
} else {
- flags &= ~StorageFlags::ReadLogsEnabled;
- }
-}
-
-void IncrementalService::IncFsMount::setReadLogsRequested(bool value) {
- if (value) {
- flags |= StorageFlags::ReadLogsRequested;
- } else {
- flags &= ~StorageFlags::ReadLogsRequested;
+ flags &= ~flag;
}
}
@@ -728,10 +726,17 @@
LOG(INFO) << "Skipped data loader stub creation because it already exists";
return false;
}
+
prepareDataLoaderLocked(*ifs, std::move(dataLoaderParams), std::move(statusListener),
healthCheckParams, std::move(healthListener));
CHECK(ifs->dataLoaderStub);
dataLoaderStub = ifs->dataLoaderStub;
+
+ // Disable long read timeouts for non-system dataloaders.
+ // To be re-enabled after installation is complete.
+ ifs->setReadTimeoutsRequested(dataLoaderStub->isSystemDataLoader() &&
+ getAlwaysEnableReadTimeoutsForSystemDataLoaders());
+ applyStorageParamsLocked(*ifs);
}
if (dataLoaderStub->isSystemDataLoader() &&
@@ -765,6 +770,18 @@
return dataLoaderStub->requestStart();
}
+void IncrementalService::onInstallationComplete(StorageId storage) {
+ IfsMountPtr ifs = getIfs(storage);
+ if (!ifs) {
+ return;
+ }
+
+ // Always enable long read timeouts after installation is complete.
+ std::unique_lock l(ifs->lock);
+ ifs->setReadTimeoutsRequested(true);
+ applyStorageParamsLocked(*ifs);
+}
+
IncrementalService::BindPathMap::const_iterator IncrementalService::findStorageLocked(
std::string_view path) const {
return findParentPath(mBindsByPath, path);
@@ -868,7 +885,7 @@
if (!ifs->readLogsRequested()) {
return 0;
}
- if (auto status = applyStorageParamsLocked(*ifs, /*enableReadLogs=*/true); status != 0) {
+ if (auto status = applyStorageParamsLocked(*ifs); status != 0) {
return status;
}
}
@@ -880,10 +897,10 @@
int IncrementalService::disableReadLogsLocked(IncFsMount& ifs) {
ifs.setReadLogsRequested(false);
- return applyStorageParamsLocked(ifs, /*enableReadLogs=*/false);
+ return applyStorageParamsLocked(ifs);
}
-int IncrementalService::applyStorageParamsLocked(IncFsMount& ifs, bool enableReadLogs) {
+int IncrementalService::applyStorageParamsLocked(IncFsMount& ifs) {
os::incremental::IncrementalFileSystemControlParcel control;
control.cmd.reset(dup(ifs.control.cmd()));
control.pendingReads.reset(dup(ifs.control.pendingReads()));
@@ -892,11 +909,15 @@
control.log.reset(dup(logsFd));
}
+ bool enableReadLogs = ifs.readLogsRequested();
+ bool enableReadTimeouts = ifs.readTimeoutsRequested();
+
std::lock_guard l(mMountOperationLock);
- auto status = mVold->setIncFsMountOptions(control, enableReadLogs);
+ auto status = mVold->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts);
if (status.isOk()) {
- // Store enabled state.
+ // Store states.
ifs.setReadLogsEnabled(enableReadLogs);
+ ifs.setReadTimeoutsEnabled(enableReadTimeouts);
} else {
LOG(ERROR) << "applyStorageParams failed: " << status.toString8();
}
@@ -1271,7 +1292,7 @@
maxPendingTimeUs = std::max(maxPendingTimeUs, microseconds(timeouts.maxPendingTimeUs));
}
if (maxPendingTimeUs < Constants::minPerUidTimeout) {
- LOG(ERROR) << "Skip setting read timeouts (maxPendingTime < Constants::minPerUidTimeout): "
+ LOG(ERROR) << "Skip setting read timeouts (maxPendingTime < Constants::minPerUidTimeout): "
<< duration_cast<milliseconds>(maxPendingTimeUs).count() << "ms < "
<< Constants::minPerUidTimeout.count() << "ms";
return;
@@ -2946,8 +2967,10 @@
return result;
}
- LOG(DEBUG) << id() << ": pendingReads: " << control.pendingReads() << ", "
- << mLastPendingReads.size() << ": " << mLastPendingReads.front().bootClockTsUs;
+ LOG(DEBUG) << id() << ": pendingReads: fd(" << control.pendingReads() << "), count("
+ << mLastPendingReads.size() << "), block: " << mLastPendingReads.front().block
+ << ", time: " << mLastPendingReads.front().bootClockTsUs
+ << ", uid: " << mLastPendingReads.front().uid;
return getOldestTsFromLastPendingReads();
}
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index fb6f56c..e3b1e6f 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -118,6 +118,9 @@
ReadLogsAllowed = 1 << 0,
ReadLogsEnabled = 1 << 1,
ReadLogsRequested = 1 << 2,
+
+ ReadTimeoutsEnabled = 1 << 3,
+ ReadTimeoutsRequested = 1 << 4,
};
struct LoadingProgress {
@@ -160,6 +163,7 @@
const StorageHealthCheckParams& healthCheckParams,
StorageHealthListener healthListener,
std::vector<PerUidReadTimeouts> perUidReadTimeouts);
+ void onInstallationComplete(StorageId storage);
int bind(StorageId storage, std::string_view source, std::string_view target, BindKind kind);
int unbind(StorageId storage, std::string_view target);
@@ -316,7 +320,7 @@
} mHealthBase = {TimePoint::max(), kMaxBootClockTsUs};
StorageHealthCheckParams mHealthCheckParams;
int mStreamStatus = content::pm::IDataLoaderStatusListener::STREAM_HEALTHY;
- std::vector<incfs::ReadInfo> mLastPendingReads;
+ std::vector<incfs::ReadInfoWithUid> mLastPendingReads;
};
using DataLoaderStubPtr = sp<DataLoaderStub>;
@@ -364,13 +368,32 @@
void disallowReadLogs() { flags &= ~StorageFlags::ReadLogsAllowed; }
int32_t readLogsAllowed() const { return (flags & StorageFlags::ReadLogsAllowed); }
- void setReadLogsEnabled(bool value);
+ void setReadLogsEnabled(bool value) {
+ return setFlag(StorageFlags::ReadLogsEnabled, value);
+ }
int32_t readLogsEnabled() const { return (flags & StorageFlags::ReadLogsEnabled); }
- void setReadLogsRequested(bool value);
+ void setReadLogsRequested(bool value) {
+ return setFlag(StorageFlags::ReadLogsRequested, value);
+ }
int32_t readLogsRequested() const { return (flags & StorageFlags::ReadLogsRequested); }
+ void setReadTimeoutsEnabled(bool value) {
+ return setFlag(StorageFlags::ReadTimeoutsEnabled, value);
+ }
+ int32_t readTimeoutsEnabled() const { return (flags & StorageFlags::ReadTimeoutsEnabled); }
+
+ void setReadTimeoutsRequested(bool value) {
+ return setFlag(StorageFlags::ReadTimeoutsRequested, value);
+ }
+ int32_t readTimeoutsRequested() const {
+ return (flags & StorageFlags::ReadTimeoutsRequested);
+ }
+
static void cleanupFilesystem(std::string_view root);
+
+ private:
+ void setFlag(StorageFlags flag, bool value);
};
using IfsMountPtr = std::shared_ptr<IncFsMount>;
@@ -422,7 +445,7 @@
int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode);
int disableReadLogsLocked(IncFsMount& ifs);
- int applyStorageParamsLocked(IncFsMount& ifs, bool enableReadLogs);
+ int applyStorageParamsLocked(IncFsMount& ifs);
LoadingProgress getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 8e416f3..0755a22 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -55,8 +55,8 @@
}
binder::Status setIncFsMountOptions(
const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
- bool enableReadLogs) const final {
- return mInterface->setIncFsMountOptions(control, enableReadLogs);
+ bool enableReadLogs, bool enableReadTimeouts) const final {
+ return mInterface->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts);
}
private:
@@ -233,8 +233,9 @@
ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const final {
return incfs::reserveSpace(control, id, size);
}
- WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
- std::vector<incfs::ReadInfo>* pendingReadsBuffer) const final {
+ WaitResult waitForPendingReads(
+ const Control& control, std::chrono::milliseconds timeout,
+ std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer) const final {
return incfs::waitForPendingReads(control, timeout, pendingReadsBuffer);
}
ErrorCode setUidReadTimeouts(const Control& control,
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index d4cdcbe..78e9589 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -56,8 +56,8 @@
virtual binder::Status bindMount(const std::string& sourceDir,
const std::string& targetDir) const = 0;
virtual binder::Status setIncFsMountOptions(
- const os::incremental::IncrementalFileSystemControlParcel& control,
- bool enableReadLogs) const = 0;
+ const os::incremental::IncrementalFileSystemControlParcel& control, bool enableReadLogs,
+ bool enableReadTimeouts) const = 0;
};
class DataLoaderManagerWrapper {
@@ -117,7 +117,7 @@
virtual ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const = 0;
virtual WaitResult waitForPendingReads(
const Control& control, std::chrono::milliseconds timeout,
- std::vector<incfs::ReadInfo>* pendingReadsBuffer) const = 0;
+ std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer) const = 0;
virtual ErrorCode setUidReadTimeouts(
const Control& control,
const std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts)
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 1ec446d..14bcd4e 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -56,10 +56,10 @@
MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
MOCK_CONST_METHOD2(bindMount,
binder::Status(const std::string& sourceDir, const std::string& argetDir));
- MOCK_CONST_METHOD2(
+ MOCK_CONST_METHOD3(
setIncFsMountOptions,
binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&,
- bool));
+ bool, bool));
void mountIncFsFails() {
ON_CALL(*this, mountIncFs(_, _, _, _))
@@ -83,12 +83,13 @@
ON_CALL(*this, bindMount(_, _)).WillByDefault(Return(binder::Status::ok()));
}
void setIncFsMountOptionsFails() const {
- ON_CALL(*this, setIncFsMountOptions(_, _))
+ ON_CALL(*this, setIncFsMountOptions(_, _, _))
.WillByDefault(Return(
binder::Status::fromExceptionCode(1, String8("failed to set options"))));
}
void setIncFsMountOptionsSuccess() {
- ON_CALL(*this, setIncFsMountOptions(_, _)).WillByDefault(Return(binder::Status::ok()));
+ ON_CALL(*this, setIncFsMountOptions(_, _, _))
+ .WillByDefault(Invoke(this, &MockVoldService::setIncFsMountOptionsOk));
}
binder::Status getInvalidControlParcel(const std::string& imagePath,
const std::string& targetDir, int32_t flags,
@@ -103,10 +104,23 @@
_aidl_return->log.reset(base::unique_fd(dup(STDIN_FILENO)));
return binder::Status::ok();
}
+ binder::Status setIncFsMountOptionsOk(
+ const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
+ bool enableReadLogs, bool enableReadTimeouts) {
+ mReadLogsEnabled = enableReadLogs;
+ mReadTimeoutsEnabled = enableReadTimeouts;
+ return binder::Status::ok();
+ }
+
+ bool readLogsEnabled() const { return mReadLogsEnabled; }
+ bool readTimeoutsEnabled() const { return mReadTimeoutsEnabled; }
private:
TemporaryFile cmdFile;
TemporaryFile logFile;
+
+ bool mReadLogsEnabled = false;
+ bool mReadTimeoutsEnabled = true;
};
class MockDataLoader : public IDataLoader {
@@ -395,7 +409,7 @@
MOCK_CONST_METHOD3(reserveSpace, ErrorCode(const Control& control, FileId id, IncFsSize size));
MOCK_CONST_METHOD3(waitForPendingReads,
WaitResult(const Control& control, std::chrono::milliseconds timeout,
- std::vector<incfs::ReadInfo>* pendingReadsBuffer));
+ std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer));
MOCK_CONST_METHOD2(setUidReadTimeouts,
ErrorCode(const Control& control,
const std::vector<PerUidReadTimeouts>& perUidReadTimeouts));
@@ -435,7 +449,7 @@
ON_CALL(*this, waitForPendingReads(_, _, _))
.WillByDefault(
Invoke([ts](const Control& control, std::chrono::milliseconds timeout,
- std::vector<incfs::ReadInfo>* pendingReadsBuffer) {
+ std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer) {
pendingReadsBuffer->push_back({.bootClockTsUs = ts});
return android::incfs::WaitResult::HaveData;
}));
@@ -1302,8 +1316,10 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ // on startLoading
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
// We are calling setIncFsMountOptions(true).
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1325,8 +1341,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(2);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1353,8 +1369,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(2);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(2);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(2);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1394,8 +1410,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(3);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(3);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1435,8 +1451,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(2);
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(3);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(5);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(3);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
@@ -1448,9 +1464,14 @@
IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
+ // Before install - long timeouts.
+ ASSERT_TRUE(mVold->readTimeoutsEnabled());
+
auto dataLoaderParcel = mDataLoaderParcel;
ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(dataLoaderParcel), {}, {},
{}, {}));
+ // During install - short timeouts.
+ ASSERT_FALSE(mVold->readTimeoutsEnabled());
// Disable readlogs callback present.
ASSERT_EQ(storageId, mTimedQueue->mId);
@@ -1463,9 +1484,15 @@
mClock->advance(90min);
ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+ mIncrementalService->onInstallationComplete(storageId);
+ // After install - long timeouts.
+ ASSERT_TRUE(mVold->readTimeoutsEnabled());
+
// New installation.
ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
{}, {}));
+ // New installation - short timeouts.
+ ASSERT_FALSE(mVold->readTimeoutsEnabled());
// New callback present.
ASSERT_EQ(storageId, mTimedQueue->mId);
@@ -1485,6 +1512,10 @@
// And timeout.
mClock->advance(90min);
ASSERT_EQ(mDataLoader->setStorageParams(true), -EPERM);
+
+ mIncrementalService->onInstallationComplete(storageId);
+ // After install - long timeouts.
+ ASSERT_TRUE(mVold->readTimeoutsEnabled());
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
@@ -1495,9 +1526,9 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions(true).
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
// setIncFsMountOptions(false) is called on the callback.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(2);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// After callback is called, disable read logs and remove callback.
@@ -1520,7 +1551,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// checkPermission fails, no calls to set opitions, start or stop WatchingMode.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
@@ -1539,7 +1571,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// checkPermission fails, no calls to set opitions, start or stop WatchingMode.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(0);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
@@ -1559,7 +1592,8 @@
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions.
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
// setIncFsMountOptions fails, no calls to start or stop WatchingMode.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index fbf677d..aad4208 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -454,6 +454,11 @@
private static native void startSensorService();
/**
+ * Start the memtrack proxy service.
+ */
+ private static native void startMemtrackProxyService();
+
+ /**
* Start all HIDL services that are run inside the system server. This may take some time.
*/
private static native void startHidlServices();
@@ -1024,6 +1029,12 @@
mSystemServiceManager.startService(PowerStatsService.class);
t.traceEnd();
+ // Start MemtrackProxyService before ActivityManager, so that early calls
+ // to Memtrack::getMemory() don't fail.
+ t.traceBegin("MemtrackProxyService");
+ startMemtrackProxyService();
+ t.traceEnd();
+
// Activity manager runs the show.
t.traceBegin("StartActivityManager");
// TODO: Might need to move after migration to WM.
@@ -2667,7 +2678,7 @@
t.traceBegin("RegisterAppOpsPolicy");
try {
- mActivityManagerService.setAppOpsPolicy(new AppOpsPolicy());
+ mActivityManagerService.setAppOpsPolicy(new AppOpsPolicy(mSystemContext));
} catch (Throwable e) {
reportWtf("registering app ops policy", e);
}
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 75614d6..9f24d9a 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -63,6 +63,7 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -105,6 +106,7 @@
public class DataManager {
private static final String TAG = "DataManager";
+ private static final boolean DEBUG = false;
private static final long RECENT_NOTIFICATIONS_MAX_AGE_MS = 10 * DateUtils.DAY_IN_MILLIS;
private static final long QUERY_EVENTS_MAX_AGE_MS = 5L * DateUtils.MINUTE_IN_MILLIS;
@@ -217,6 +219,7 @@
List<ShortcutInfo> shortcuts = getShortcuts(packageName, userId,
Collections.singletonList(shortcutId));
if (shortcuts != null && !shortcuts.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "Found shortcut for " + shortcuts.get(0).getLabel());
return shortcuts.get(0);
}
return null;
@@ -258,6 +261,7 @@
}
ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
if (shortcutInfo == null) {
+ Slog.e(TAG, " Shortcut no longer found: " + shortcutId);
return null;
}
int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
@@ -705,6 +709,7 @@
}
});
for (String packageName : packagesToDelete) {
+ if (DEBUG) Log.d(TAG, "Deleting packages data for: " + packageName);
userData.deletePackageData(packageName);
}
}
@@ -716,6 +721,7 @@
@ShortcutQuery.QueryFlags int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC
| ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
| ShortcutQuery.FLAG_MATCH_CACHED | ShortcutQuery.FLAG_GET_PERSONS_DATA;
+ if (DEBUG) Log.d(TAG, " Get shortcuts with IDs: " + shortcutIds);
return mShortcutServiceInternal.getShortcuts(
UserHandle.USER_SYSTEM, mContext.getPackageName(),
/*changedSince=*/ 0, packageName, shortcutIds, /*locusIds=*/ null,
@@ -742,7 +748,7 @@
TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
String defaultDialer = telecomManager != null
? telecomManager.getDefaultDialerPackage(
- new UserHandle(userData.getUserId())) : null;
+ new UserHandle(userData.getUserId())) : null;
userData.setDefaultDialer(defaultDialer);
}
@@ -848,6 +854,9 @@
ConversationStore conversationStore = packageData.getConversationStore();
ConversationInfo oldConversationInfo =
conversationStore.getConversation(shortcutInfo.getId());
+ if (oldConversationInfo == null) {
+ if (DEBUG) Log.d(TAG, "Nothing previously stored about conversation.");
+ }
ConversationInfo.Builder builder = oldConversationInfo != null
? new ConversationInfo.Builder(oldConversationInfo)
: new ConversationInfo.Builder();
@@ -1083,6 +1092,7 @@
Set<String> shortcutIds = new HashSet<>();
for (ShortcutInfo shortcutInfo : shortcuts) {
if (packageData != null) {
+ if (DEBUG) Log.d(TAG, "Deleting shortcut: " + shortcutInfo.getId());
packageData.deleteDataForConversation(shortcutInfo.getId());
}
shortcutIds.add(shortcutInfo.getId());
@@ -1309,6 +1319,7 @@
int userId = getChangingUserId();
UserData userData = getUnlockedUserData(userId);
if (userData != null) {
+ if (DEBUG) Log.d(TAG, "Delete package data for: " + packageName);
userData.deletePackageData(packageName);
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index 46487ea2..411c31c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -17,8 +17,12 @@
package com.android.server.pm
import android.os.Build
+import android.os.Handler
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
import com.android.server.apphibernation.AppHibernationManagerInternal
import com.android.server.extendedtestutils.wheneverStatic
import com.android.server.testutils.whenever
@@ -28,12 +32,12 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(JUnit4::class)
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
class PackageManagerServiceHibernationTests {
companion object {
@@ -60,6 +64,8 @@
rule.system().stageNominalSystemState()
whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java))
.thenReturn(appHibernationManager)
+ whenever(rule.mocks().injector.handler)
+ .thenReturn(Handler(TestableLooper.get(this).looper))
}
@Test
@@ -74,6 +80,9 @@
ps!!.setStopped(true, TEST_USER_ID)
pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
+
+ TestableLooper.get(this).processAllMessages()
+
verify(appHibernationManager).setHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID, false)
verify(appHibernationManager).setHibernatingGlobally(TEST_PACKAGE_NAME, false)
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java
index 01a641f..b8535c2 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java
@@ -119,36 +119,36 @@
when(mAccessibilitySecurityPolicy.isA11yCategoryService(
mMockA11yServiceInfo)).thenReturn(false);
- mFakeNotificationController.onReceive(mContext, createIntent(TEST_USER_ID,
- PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
- TEST_COMPONENT_NAME.flattenToShortString()));
+ mFakeNotificationController.onReceive(mContext,
+ PolicyWarningUIController.createIntent(mContext, TEST_USER_ID,
+ PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
+ TEST_COMPONENT_NAME));
verify(mNotificationManager).notify(eq(TEST_COMPONENT_NAME.flattenToShortString()),
- eq(NOTE_A11Y_VIEW_AND_CONTROL_ACCESS), any(
- Notification.class));
+ eq(NOTE_A11Y_VIEW_AND_CONTROL_ACCESS), any(Notification.class));
}
@Test
public void receiveActionA11ySettings_launchA11ySettingsAndDismissNotification() {
mFakeNotificationController.onReceive(mContext,
- createIntent(TEST_USER_ID, PolicyWarningUIController.ACTION_A11Y_SETTINGS,
- TEST_COMPONENT_NAME.flattenToShortString()));
+ PolicyWarningUIController.createIntent(mContext, TEST_USER_ID,
+ PolicyWarningUIController.ACTION_A11Y_SETTINGS,
+ TEST_COMPONENT_NAME));
verifyLaunchA11ySettings();
verify(mNotificationManager).cancel(TEST_COMPONENT_NAME.flattenToShortString(),
NOTE_A11Y_VIEW_AND_CONTROL_ACCESS);
- assertNotifiedSettingsEqual(TEST_USER_ID,
- TEST_COMPONENT_NAME.flattenToShortString());
+ assertNotifiedSettingsEqual(TEST_USER_ID, TEST_COMPONENT_NAME.flattenToShortString());
}
@Test
public void receiveActionDismissNotification_addToNotifiedSettings() {
- mFakeNotificationController.onReceive(mContext, createIntent(TEST_USER_ID,
- PolicyWarningUIController.ACTION_DISMISS_NOTIFICATION,
- TEST_COMPONENT_NAME.flattenToShortString()));
+ mFakeNotificationController.onReceive(mContext,
+ PolicyWarningUIController.createIntent(mContext, TEST_USER_ID,
+ PolicyWarningUIController.ACTION_DISMISS_NOTIFICATION,
+ TEST_COMPONENT_NAME));
- assertNotifiedSettingsEqual(TEST_USER_ID,
- TEST_COMPONENT_NAME.flattenToShortString());
+ assertNotifiedSettingsEqual(TEST_USER_ID, TEST_COMPONENT_NAME.flattenToShortString());
}
@Test
@@ -172,8 +172,7 @@
verify(mAlarmManager).set(eq(RTC_WAKEUP), anyLong(),
eq(PolicyWarningUIController.createPendingIntent(mContext, TEST_USER_ID,
- PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
- TEST_COMPONENT_NAME.flattenToShortString())));
+ PolicyWarningUIController.ACTION_SEND_NOTIFICATION, TEST_COMPONENT_NAME)));
}
@Test
@@ -184,8 +183,7 @@
verify(mAlarmManager).cancel(
eq(PolicyWarningUIController.createPendingIntent(mContext, TEST_USER_ID,
- PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
- TEST_COMPONENT_NAME.flattenToShortString())));
+ PolicyWarningUIController.ACTION_SEND_NOTIFICATION, TEST_COMPONENT_NAME)));
}
private void assertNotifiedSettingsEqual(int userId, String settingString) {
@@ -196,14 +194,6 @@
assertEquals(settingString, notifiedServicesSetting);
}
- private Intent createIntent(int userId, String action, String serviceComponentName) {
- final Intent intent = new Intent(action);
- intent.setPackage(mContext.getPackageName())
- .setIdentifier(serviceComponentName)
- .putExtra(Intent.EXTRA_USER_ID, userId);
- return intent;
- }
-
private void verifyLaunchA11ySettings() {
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
final ArgumentCaptor<UserHandle> userHandleCaptor = ArgumentCaptor.forClass(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 81be2e7..b7f5f4d 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -331,6 +331,29 @@
}
@Test
+ public void onAccessibilityActionPerformed_magnifierEnabled_showMagnificationButton()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_WINDOW);
+
+ mMagnificationController.onAccessibilityActionPerformed(TEST_DISPLAY);
+
+ verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_WINDOW));
+ }
+
+ @Test
+ public void onAccessibilityActionPerformed_capabilityNotAll_removeMagnificationButton()
+ throws RemoteException {
+ mMagnificationController.setMagnificationCapabilities(
+ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ setMagnificationEnabled(MODE_WINDOW);
+
+ mMagnificationController.onAccessibilityActionPerformed(TEST_DISPLAY);
+
+ verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
+ }
+
+ @Test
public void onWindowMagnificationActivationState_windowActivated_logWindowDuration() {
mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, true);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index ffa0185..a20272a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -313,6 +313,17 @@
}
@Test
+ public void onAccessibilityActionPerformed_magnifierEnabled_notifyAction()
+ throws RemoteException {
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, NaN, NaN);
+
+ mMockConnection.getConnectionCallback().onAccessibilityActionPerformed(TEST_DISPLAY);
+
+ verify(mMockCallback).onAccessibilityActionPerformed(eq(TEST_DISPLAY));
+ }
+
+ @Test
public void binderDied_windowMagnifierIsEnabled_resetState() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index fc4804b..41237c8 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -72,6 +72,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.IntArray;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
@@ -121,7 +122,8 @@
UidRecord.CHANGE_GONE,
UidRecord.CHANGE_GONE | UidRecord.CHANGE_IDLE,
UidRecord.CHANGE_IDLE,
- UidRecord.CHANGE_ACTIVE
+ UidRecord.CHANGE_ACTIVE,
+ UidRecord.CHANGE_CAPABILITY,
};
private static PackageManagerInternal sPackageManagerInternal;
@@ -528,8 +530,10 @@
ActivityManager.UID_OBSERVER_GONE,
ActivityManager.UID_OBSERVER_IDLE,
ActivityManager.UID_OBSERVER_ACTIVE,
+ ActivityManager.UID_OBSERVER_CAPABILITY,
ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
| ActivityManager.UID_OBSERVER_ACTIVE | ActivityManager.UID_OBSERVER_IDLE
+ | ActivityManager.UID_OBSERVER_CAPABILITY
};
final IUidObserver[] observers = new IUidObserver.Stub[changesToObserve.length];
for (int i = 0; i < observers.length; ++i) {
@@ -553,7 +557,16 @@
ActivityManager.PROCESS_STATE_NONEXISTENT,
ActivityManager.PROCESS_STATE_CACHED_EMPTY,
ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- ActivityManager.PROCESS_STATE_TOP
+ ActivityManager.PROCESS_STATE_TOP,
+ ActivityManager.PROCESS_STATE_TOP,
+ };
+ final int[] capabilitiesForPendingUidRecords = {
+ ActivityManager.PROCESS_CAPABILITY_ALL,
+ ActivityManager.PROCESS_CAPABILITY_NONE,
+ ActivityManager.PROCESS_CAPABILITY_NONE,
+ ActivityManager.PROCESS_CAPABILITY_NONE,
+ ActivityManager.PROCESS_CAPABILITY_NONE,
+ ActivityManager.PROCESS_CAPABILITY_NETWORK,
};
final Map<Integer, ChangeRecord> changeItems = new HashMap<>();
for (int i = 0; i < changesForPendingUidRecords.length; ++i) {
@@ -562,6 +575,7 @@
pendingChange.uid = i;
pendingChange.procState = procStatesForPendingUidRecords[i];
pendingChange.procStateSeq = i;
+ pendingChange.capability = capabilitiesForPendingUidRecords[i];
changeItems.put(changesForPendingUidRecords[i], pendingChange);
addPendingUidChange(pendingChange);
}
@@ -606,20 +620,26 @@
verify(observer).onUidGone(changeItem.uid, changeItem.ephemeral);
});
}
- if ((changeToObserve & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
+ if ((changeToObserve & ActivityManager.UID_OBSERVER_PROCSTATE) != 0
+ || (changeToObserve & ActivityManager.UID_OBSERVER_CAPABILITY) != 0) {
// Observer listens to uid procState changes, so change items corresponding to
// UidRecord.CHANGE_PROCSTATE or UidRecord.CHANGE_IDLE or UidRecord.CHANGE_ACTIVE
// needs to be delivered to this observer.
- final int[] changesToVerify = {
- UidRecord.CHANGE_PROCSTATE,
- UidRecord.CHANGE_ACTIVE,
- UidRecord.CHANGE_IDLE
- };
- verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems,
+ final IntArray changesToVerify = new IntArray();
+ if ((changeToObserve & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) {
+ changesToVerify.add(UidRecord.CHANGE_CAPABILITY);
+ } else {
+ changesToVerify.add(UidRecord.CHANGE_PROCSTATE);
+ changesToVerify.add(UidRecord.CHANGE_ACTIVE);
+ changesToVerify.add(UidRecord.CHANGE_IDLE);
+ changesToVerify.add(UidRecord.CHANGE_CAPABILITY);
+ }
+ verifyObserverReceivedChanges(observerToTest, changesToVerify.toArray(),
+ changeItems,
(observer, changeItem) -> {
verify(observer).onUidStateChanged(changeItem.uid,
changeItem.procState, changeItem.procStateSeq,
- ActivityManager.PROCESS_CAPABILITY_NONE);
+ changeItem.capability);
});
}
// Verify there are no other callbacks for this observer.
@@ -725,11 +745,11 @@
ActivityManager.PROCESS_STATE_CACHED_EMPTY,
ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
ActivityManager.PROCESS_STATE_SERVICE,
- ActivityManager.PROCESS_STATE_RECEIVER
+ ActivityManager.PROCESS_STATE_RECEIVER,
};
final ArrayList<ChangeRecord> pendingItemsForUids =
- new ArrayList<>(changesForPendingItems.length);
- for (int i = 0; i < changesForPendingItems.length; ++i) {
+ new ArrayList<>(procStatesForPendingItems.length);
+ for (int i = 0; i < procStatesForPendingItems.length; ++i) {
final ChangeRecord item = new ChangeRecord();
item.uid = i;
item.change = changesForPendingItems[i];
diff --git a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
index 1de5f6f..0db118d 100644
--- a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
@@ -109,6 +110,7 @@
@Test
public void testMergeWithPendingChange() {
+ // Map of expectedChange -> {(currentChange, pendingChange)}
final SparseArray<Pair<Integer, Integer>> changesToVerify = new SparseArray<>();
changesToVerify.put(UidRecord.CHANGE_ACTIVE,
@@ -127,6 +129,8 @@
Pair.create(UidRecord.CHANGE_GONE, UidRecord.CHANGE_ACTIVE));
changesToVerify.put(UidRecord.CHANGE_GONE,
Pair.create(UidRecord.CHANGE_GONE, UidRecord.CHANGE_CACHED));
+ changesToVerify.put(UidRecord.CHANGE_PROCSTATE | UidRecord.CHANGE_CAPABILITY,
+ Pair.create(UidRecord.CHANGE_PROCSTATE, UidRecord.CHANGE_CAPABILITY));
for (int i = 0; i < changesToVerify.size(); ++i) {
final int expectedChange = changesToVerify.keyAt(i);
@@ -149,7 +153,8 @@
ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_ACTIVE,
PROCESS_STATE_IMPORTANT_FOREGROUND, TEST_PKG2, TEST_UID2);
final IUidObserver observer2 = mock(IUidObserver.Stub.class);
- registerObserver(observer2, ActivityManager.UID_OBSERVER_PROCSTATE,
+ registerObserver(observer2,
+ ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_CAPABILITY,
PROCESS_STATE_SERVICE, TEST_PKG3, TEST_UID3);
mUidObserverController.dispatchUidsChanged();
@@ -177,6 +182,14 @@
verifyNoMoreInteractions(observer1);
verifyNoMoreInteractions(observer2);
+ addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE | UidRecord.CHANGE_CAPABILITY,
+ PROCESS_STATE_RECEIVER, 111, PROCESS_CAPABILITY_NETWORK, false);
+ mUidObserverController.dispatchUidsChanged();
+ verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_RECEIVER,
+ 111, PROCESS_CAPABILITY_NETWORK);
+ verifyNoMoreInteractions(observer1);
+ verifyNoMoreInteractions(observer2);
+
unregisterObserver(observer1);
addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_TOP,
diff --git a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceTests.java
index 24a8b61..edc0d46 100644
--- a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -235,4 +235,37 @@
assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
+
+ /**
+ * Test game modes are user-specific.
+ */
+ @Test
+ public void testGameModeMultipleUsers() {
+ GameManagerService gameManagerService = new GameManagerService(mMockContext);
+ gameManagerService.onUserStarting(USER_ID_1);
+ gameManagerService.onUserStarting(USER_ID_2);
+
+ mockModifyGameModeGranted();
+
+ // Set User 1 to Standard
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
+ assertEquals(GameManager.GAME_MODE_STANDARD,
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
+
+ // Set User 2 to Performance and verify User 1 is still Standard
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE,
+ USER_ID_2);
+ assertEquals(GameManager.GAME_MODE_PERFORMANCE,
+ gameManagerService.getGameMode(mPackageName, USER_ID_2));
+ assertEquals(GameManager.GAME_MODE_STANDARD,
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
+
+ // Set User 1 to Battery and verify User 2 is still Performance
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY,
+ USER_ID_1);
+ assertEquals(GameManager.GAME_MODE_BATTERY,
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
+ assertEquals(GameManager.GAME_MODE_PERFORMANCE,
+ gameManagerService.getGameMode(mPackageName, USER_ID_2));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index c34c00d..ba4d585 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -988,6 +988,49 @@
}
@Test
+ public void testClearPackageData() throws AppSearchException {
+ List<SchemaTypeConfigProto> existingSchemas =
+ mAppSearchImpl.getSchemaProtoLocked().getTypesList();
+
+ // Insert package schema
+ List<AppSearchSchema> schema =
+ ImmutableList.of(new AppSearchSchema.Builder("schema").build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schema,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert package document
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace", "uri", "schema").build();
+ mAppSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
+
+ // Verify the document is indexed.
+ SearchSpec searchSpec =
+ new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.query("package", "database", /*queryExpression=*/ "", searchSpec);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document);
+
+ // Remove the package
+ mAppSearchImpl.clearPackageData("package");
+
+ // Verify the document is cleared.
+ searchResultPage =
+ mAppSearchImpl.query("package2", "database2", /*queryExpression=*/ "", searchSpec);
+ assertThat(searchResultPage.getResults()).isEmpty();
+
+ // Verify the schema is cleared.
+ assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
+ .containsExactlyElementsIn(existingSchemas);
+ }
+
+ @Test
public void testGetPackageToDatabases() throws Exception {
Map<String, Set<String>> existingMapping = mAppSearchImpl.getPackageToDatabases();
Map<String, Set<String>> expectedMapping = new ArrayMap<>();
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 4295172..7cd6028 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -346,6 +346,9 @@
DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
displayDeviceInfo.width = 100;
displayDeviceInfo.height = 200;
+ displayDeviceInfo.supportedModes = new Display.Mode[1];
+ displayDeviceInfo.supportedModes[0] = new Display.Mode(1, 100, 200, 60f);
+ displayDeviceInfo.modeId = 1;
final Rect zeroRect = new Rect();
displayDeviceInfo.displayCutout = new DisplayCutout(
Insets.of(0, 10, 0, 0),
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index bcd853c..d784a22 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -239,6 +239,9 @@
displayDeviceInfo.width = width;
displayDeviceInfo.height = height;
displayDeviceInfo.flags = flags;
+ displayDeviceInfo.supportedModes = new Display.Mode[1];
+ displayDeviceInfo.supportedModes[0] = new Display.Mode(1, width, height, 60f);
+ displayDeviceInfo.modeId = 1;
displayDeviceInfo.address = new DisplayAddressImpl();
return device;
}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index f5876fa..e9e2486 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -18,6 +18,12 @@
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.NETWORK_STACK;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
@@ -29,10 +35,17 @@
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+import static android.net.NetworkPolicyManager.allowedReasonsToString;
+import static android.net.NetworkPolicyManager.blockedReasonsToString;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
@@ -59,6 +72,7 @@
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
+import static com.android.server.net.NetworkPolicyManagerService.UidBlockedState.getEffectiveBlockedReasons;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -134,8 +148,10 @@
import android.util.ArrayMap;
import android.util.DataUnit;
import android.util.Log;
+import android.util.Pair;
import android.util.Range;
import android.util.RecurrenceRule;
+import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
@@ -1896,6 +1912,65 @@
assertFalse(mService.isUidNetworkingBlocked(UID_E, false));
}
+ @Test
+ public void testUpdateEffectiveBlockedReasons() {
+ final SparseArray<Pair<Integer, Integer>> effectiveBlockedReasons = new SparseArray<>();
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE));
+
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_SYSTEM));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
+ ALLOWED_REASON_SYSTEM));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER,
+ ALLOWED_METERED_REASON_SYSTEM));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_SYSTEM));
+
+ effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER,
+ ALLOWED_REASON_SYSTEM));
+ effectiveBlockedReasons.put(BLOCKED_REASON_APP_STANDBY,
+ Pair.create(BLOCKED_REASON_APP_STANDBY | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_SYSTEM));
+
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
+ ALLOWED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, ALLOWED_METERED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER,
+ ALLOWED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_REASON_BATTERY_SAVER,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_FOREGROUND));
+ // TODO: test more combinations of blocked reasons.
+
+ for (int i = 0; i < effectiveBlockedReasons.size(); ++i) {
+ final int expectedEffectiveBlockedReasons = effectiveBlockedReasons.keyAt(i);
+ final int blockedReasons = effectiveBlockedReasons.valueAt(i).first;
+ final int allowedReasons = effectiveBlockedReasons.valueAt(i).second;
+ final String errorMsg = "Expected="
+ + blockedReasonsToString(expectedEffectiveBlockedReasons)
+ + "; blockedReasons=" + blockedReasonsToString(blockedReasons)
+ + ", allowedReasons=" + allowedReasonsToString(allowedReasons);
+ assertEquals(errorMsg, expectedEffectiveBlockedReasons,
+ getEffectiveBlockedReasons(blockedReasons, allowedReasons));
+ }
+ }
+
private String formatBlockedStateError(int uid, int rule, boolean metered,
boolean backgroundRestricted) {
return String.format(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
index c69ef8d..a2ad89e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
@@ -56,7 +56,7 @@
}
private StatusBarNotification getNotification(String pkg, int id, UserHandle user) {
- Notification n = new Notification.Builder(getContext(), "test")
+ Notification n = new Notification.Builder(getContext(), "test" + id)
.setContentTitle("A")
.setWhen(1205)
.build();
@@ -140,4 +140,23 @@
assertThat(expected).contains(sbn.getKey());
}
}
+
+ @Test
+ public void testRemoveChannelNotifications() {
+ List<String> expected = new ArrayList<>();
+ for (int i = 0; i < SIZE; i++) {
+ StatusBarNotification sbn = getNotification("pkg", i, UserHandle.of(USER_CURRENT));
+ mArchive.record(sbn, REASON_CANCEL);
+ if (i != 3) {
+ // Will delete notification for this user in channel "test3".
+ expected.add(sbn.getKey());
+ }
+ }
+ mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test3");
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ assertThat(actual).hasSize(expected.size());
+ for (StatusBarNotification sbn : actual) {
+ assertThat(expected).contains(sbn.getKey());
+ }
+ }
}
diff --git a/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerPerUserService.java b/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerPerUserService.java
index f805904..55cbc72 100644
--- a/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerPerUserService.java
+++ b/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerPerUserService.java
@@ -174,7 +174,7 @@
try {
callbackRunnable.runOrThrow();
} catch (RemoteException ex) {
- Slog.w(TAG, "Failed running callback method", ex);
+ Slog.i(TAG, "Failed running callback method: " + ex);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index ccaeaf9..9aded89 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1439,7 +1439,6 @@
@Override
public ComponentName getActiveServiceComponentName() {
- enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
synchronized (this) {
return mImpl != null ? mImpl.mComponent : null;
}
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 5e50bea..d250297 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -571,7 +571,7 @@
*
* @throws SecurityException if the caller does not have the required permission/privileges
*/
- public static void enforeceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
+ public static void enforceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
Context context, int subId, String message) {
if (context.checkCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE)
== PERMISSION_GRANTED) {
@@ -591,7 +591,7 @@
*
* @throws SecurityException if the caller does not have the required permission/privileges
*/
- public static void enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+ public static void enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
Context context, int subId, String message) {
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
== PERMISSION_GRANTED) {
@@ -613,7 +613,7 @@
*
* @throws SecurityException if the caller does not have the required permission/privileges
*/
- public static void enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ public static void enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
Context context, int subId, String message) {
if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
== PERMISSION_GRANTED) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 24fcf46..cc3b6c5 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3298,6 +3298,14 @@
public static final String KEY_USE_CALLER_ID_USSD_BOOL = "use_caller_id_ussd_bool";
/**
+ * Call waiting uses USSD command without SS command.
+ * When {@code true}, the call waiting query/set by ussd command.
+ * When {@code false}, doesn't use USSD to query/set call waiting.
+ * @hide
+ */
+ public static final String KEY_USE_CALL_WAITING_USSD_BOOL = "use_call_waiting_ussd_bool";
+
+ /**
* Specifies the service class for call waiting service.
* Default value is
* {@link com.android.internal.telephony.CommandsInterface#SERVICE_CLASS_VOICE}.
@@ -5377,6 +5385,7 @@
sDefaults.putBoolean(KEY_SUPPORT_EMERGENCY_DIALER_SHORTCUT_BOOL, true);
sDefaults.putBoolean(KEY_USE_CALL_FORWARDING_USSD_BOOL, false);
sDefaults.putBoolean(KEY_USE_CALLER_ID_USSD_BOOL, false);
+ sDefaults.putBoolean(KEY_USE_CALL_WAITING_USSD_BOOL, false);
sDefaults.putInt(KEY_CALL_WAITING_SERVICE_CLASS_INT, 1 /* SERVICE_CLASS_VOICE */);
sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
"connected_mmwave:5G,connected:5G,not_restricted_rrc_idle:5G,"
diff --git a/telephony/java/android/telephony/ims/RcsConfig.java b/telephony/java/android/telephony/ims/RcsConfig.java
index 07e95cc..8a31211 100644
--- a/telephony/java/android/telephony/ims/RcsConfig.java
+++ b/telephony/java/android/telephony/ims/RcsConfig.java
@@ -48,6 +48,9 @@
private static final String LOG_TAG = "RcsConfig";
private static final boolean DBG = Build.IS_ENG;
+ // Tag for Rcs Volte single registration defined in RCC.07 A.1.6.2
+ private static final String TAG_SINGLE_REGISTRATION = "rcsVolteSingleRegistration";
+
private final HashMap<String, String> mValues = new HashMap<>();
private RcsConfig(HashMap<String, String> values) {
@@ -145,6 +148,14 @@
return mValues.containsKey(tag);
}
+ /**
+ * Check whether Rcs Volte single registration is supported by the config.
+ */
+ public boolean isRcsVolteSingleRegistrationSupported() {
+ return getBoolean(TAG_SINGLE_REGISTRATION, false)
+ || getInteger(TAG_SINGLE_REGISTRATION, 0) != 0;
+ }
+
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index b529563..d21fcab 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -204,7 +204,9 @@
/**
* @return the UTF-8 encoded SIP message.
+ * @deprecated Use {@link #toEncodedMessage} instead
*/
+ @Deprecated
public @NonNull byte[] getEncodedMessage() {
byte[] header = new StringBuilder()
.append(mStartLine)
@@ -216,4 +218,26 @@
System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
return sipMessage;
}
+
+ /**
+ * According RFC-3261 section 7, SIP is a text protocol and uses the UTF-8 charset. Its format
+ * consists of a start-line, one or more header fields, an empty line indicating the end of the
+ * header fields, and an optional message-body.
+ *
+ * <p>
+ * Returns a byte array with UTF-8 format representation of the encoded SipMessage.
+ *
+ * @return byte array with UTF-8 format representation of the encoded SipMessage.
+ */
+ public @NonNull byte[] toEncodedMessage() {
+ byte[] header = new StringBuilder()
+ .append(mStartLine)
+ .append(mHeaderSection)
+ .append(CRLF)
+ .toString().getBytes(UTF_8);
+ byte[] sipMessage = new byte[header.length + mContent.length];
+ System.arraycopy(header, 0, sipMessage, 0, header.length);
+ System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
+ return sipMessage;
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index af7eb59..93a2bb0 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -63,6 +63,7 @@
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
@@ -89,6 +90,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
@@ -3030,10 +3032,11 @@
// Verify NOT_RESTRICTED is set appropriately
final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
.build().networkCapabilities;
- if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN ||
- capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA ||
- capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS ||
- capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
+ if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN
+ || capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA
+ || capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS
+ || capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
+ || capability == NET_CAPABILITY_VSIM || capability == NET_CAPABILITY_BIP
|| capability == NET_CAPABILITY_ENTERPRISE) {
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
} else {
@@ -3168,6 +3171,8 @@
tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
tryNetworkFactoryRequests(NET_CAPABILITY_TRUSTED);
tryNetworkFactoryRequests(NET_CAPABILITY_NOT_VPN);
+ tryNetworkFactoryRequests(NET_CAPABILITY_VSIM);
+ tryNetworkFactoryRequests(NET_CAPABILITY_BIP);
// Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
}
@@ -9251,7 +9256,7 @@
final int expectedOwnerUidWithoutIncludeFlag =
shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
- ? Process.myUid() : INVALID_UID;
+ ? myUid : INVALID_UID;
assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
myUid, myUid, false /* includeLocationSensitiveInfo */));
@@ -9270,22 +9275,26 @@
}
+ private void verifyOwnerUidAndTransportInfoNetCapsPermissionPreS() {
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
+ // Ensure that owner uid is included even if the request asks to remove it (which is
+ // the default) since the app has necessary permissions and targetSdk < S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ // Ensure that location info is removed if the request asks to remove it even if the
+ // app has necessary permissions.
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ );
+ }
+
@Test
- public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQ()
+ public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQPreS()
throws Exception {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that we include owner uid even if the request asks to remove it since the
- // app has necessary permissions and targetSdk < S.
- true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- // Ensure that we remove location info if the request asks to remove it even if the
- // app has necessary permissions.
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
}
@Test
@@ -9294,16 +9303,7 @@
setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that we include owner uid even if the request asks to remove it since the
- // app has necessary permissions and targetSdk < S.
- true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- // Ensure that we remove location info if the request asks to remove it even if the
- // app has necessary permissions.
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
}
@Test
@@ -9314,13 +9314,13 @@
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that we owner UID if the request asks us to remove it even if the app
- // has necessary permissions since targetSdk >= S.
+ // Ensure that the owner UID is removed if the request asks us to remove it even
+ // if the app has necessary permissions since targetSdk >= S.
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- // Ensure that we remove location info if the request asks to remove it even if the
+ // Ensure that location info is removed if the request asks to remove it even if the
// app has necessary permissions.
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -9331,15 +9331,15 @@
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
+ verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
+ }
+
+ private void verifyOwnerUidAndTransportInfoNetCapsNotIncluded() {
verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that we owner UID if the request asks us to remove it even if the app
- // has necessary permissions since targetSdk >= S.
- true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- // Ensure that we remove location info if the request asks to remove it even if the
- // app has necessary permissions.
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -9349,12 +9349,7 @@
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
}
@Test
@@ -9376,26 +9371,17 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
}
@Test
- public void testCreateWithLocationInfoSanitizedWithoutLocationPermission()
+ public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterS()
throws Exception {
// Test that not having fine location permission leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
+ setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
}
@Test
diff --git a/tools/hiddenapi/OWNERS b/tools/hiddenapi/OWNERS
new file mode 100644
index 0000000..afbeef5
--- /dev/null
+++ b/tools/hiddenapi/OWNERS
@@ -0,0 +1,7 @@
+# compat-team@ for changes to hiddenapi files
+andreionea@google.com
+mathewi@google.com
+satayev@google.com
+
+# soong-team@ as the files these tools protect are tightly coupled with Soong
+file:platform/build/soong:/OWNERS
diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh
index 73eacc0..2924e01 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -7,11 +7,9 @@
# the team email to use in the event of this detecting an entry in a <team> package. Also
# add <team> to the TEAMS list.
LIBCORE_PACKAGES="\
- android.icu \
android.system \
android.test \
com.android.bouncycastle \
- com.android.conscrypt \
com.android.i18n.phonenumbers \
com.android.okhttp \
com.sun \
@@ -24,37 +22,54 @@
org.json \
org.w3c.dom \
org.xml.sax \
+ org.xmlpull.v1 \
sun \
"
LIBCORE_EMAIL=libcore-team@android.com
+I18N_PACKAGES="\
+ android.icu \
+ "
+
+I18N_EMAIL=$LIBCORE_EMAIL
+
+CONSCRYPT_PACKAGES="\
+ com.android.org.conscrypt \
+ "
+
+CONSCRYPT_EMAIL=$LIBCORE_EMAIL
+
# List of teams.
-TEAMS=LIBCORE
+TEAMS="LIBCORE I18N CONSCRYPT"
+
+SHA=$1
# Generate the list of packages and convert to a regular expression.
PACKAGES=$(for t in $TEAMS; do echo $(eval echo \${${t}_PACKAGES}); done)
RE=$(echo ${PACKAGES} | sed "s/ /|/g")
-git show --name-only --pretty=format: $1 | grep "config/hiddenapi-.*txt" | while read file; do
- ENTRIES=$(grep -E "^L(${RE})/" || true <(git show $1:$file))
+EXIT_CODE=0
+for file in $(git show --name-only --pretty=format: $SHA | grep "config/hiddenapi-.*txt"); do
+ ENTRIES=$(grep -E "^\+L(${RE})/" <(git diff ${SHA}~1 ${SHA} $file) | sed "s|^\+||" || echo)
if [[ -n "${ENTRIES}" ]]; then
- echo -e "\e[1m\e[31m$file $1 contains the following entries\e[0m"
+ echo -e "\e[1m\e[31m$file $SHA contains the following entries\e[0m"
echo -e "\e[1m\e[31mfor packages that are handled using UnsupportedAppUsage. Please remove\e[0m"
echo -e "\e[1m\e[31mthese entries and add annotations instead.\e[0m"
# Partition the entries by team and provide contact details to aid in fixing the issue.
for t in ${TEAMS}
do
PACKAGES=$(eval echo \${${t}_PACKAGES})
- RE=$(echo ${PACKAGES} | sed "s/ /|/g")
- TEAM_ENTRIES=$(grep -E "^L(${RE})/" <(echo "${ENTRIES}"))
+ TEAM_RE=$(echo ${PACKAGES} | sed "s/ /|/g")
+ TEAM_ENTRIES=$(grep -E "^L(${TEAM_RE})/" <(echo "${ENTRIES}") || echo)
if [[ -n "${TEAM_ENTRIES}" ]]; then
EMAIL=$(eval echo \${${t}_EMAIL})
- echo -e "\e[33mContact ${EMAIL} or compat- for help with the following:\e[0m"
- for i in ${ENTRIES}
+ echo -e "\e[33mContact ${EMAIL} for help with the following:\e[0m"
+ for i in ${TEAM_ENTRIES}
do
echo -e "\e[33m ${i}\e[0m"
done
fi
done
- exit 1
+ EXIT_CODE=1
fi
done
+exit $EXIT_CODE