Merge "Modify uwb permission strings" into sc-dev
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/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 877dacb..5f3a3ae 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;
@@ -67,6 +72,7 @@
/** 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;
@@ -79,14 +85,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
@@ -663,7 +715,7 @@
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyUserUnlocked(callingUserId);
- mImplInstanceManager.getOrCreateAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getOrCreateAppSearchImpl(mContext, callingUserId);
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
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/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/core/api/current.txt b/core/api/current.txt
index 6fb6116..38104b5 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -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);
@@ -35478,8 +35478,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 +41921,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
@@ -42374,7 +42374,7 @@
method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharingContacts(@NonNull java.util.List<android.net.Uri>, int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharingContacts(int, @NonNull java.util.List<android.net.Uri>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharingPreference(int, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
method public void setSubscriptionOverrideCongested(int, boolean, long);
@@ -42455,10 +42455,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 +42476,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 +42484,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 +42524,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 +50821,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
@@ -55495,6 +55492,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 +55566,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);
@@ -56741,18 +56738,19 @@
package android.window {
public interface SplashScreen {
- method public void setOnExitAnimationListener(@Nullable android.window.SplashScreen.OnExitAnimationListener);
+ method public void clearOnExitAnimationListener();
+ method public void setOnExitAnimationListener(@NonNull android.window.SplashScreen.OnExitAnimationListener);
}
public static interface SplashScreen.OnExitAnimationListener {
- method public void onSplashScreenExit(@NonNull android.window.SplashScreenView);
+ method @UiThread public void onSplashScreenExit(@NonNull android.window.SplashScreenView);
}
public final class SplashScreenView extends android.widget.FrameLayout {
- method public long getIconAnimationDurationMillis();
- method public long getIconAnimationStartMillis();
+ method @Nullable public java.time.Duration getIconAnimationDuration();
+ method @Nullable public java.time.Instant getIconAnimationStart();
method @Nullable public android.view.View getIconView();
- method public void remove();
+ method @UiThread public void remove();
}
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 930c298..40f26e8 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";
@@ -1923,6 +1924,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 +1936,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 +2228,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);
}
@@ -3005,12 +3013,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 +7936,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);
}
@@ -11364,15 +11385,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 +11742,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 +11804,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 +13615,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;
}
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/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/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/PendingIntent.java b/core/java/android/app/PendingIntent.java
index f4b9542..4cf3a80 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -379,8 +379,7 @@
if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED)
&& !flagImmutableSet && !flagMutableSet) {
- //TODO(b/178065720) Remove check for chrome and enforce this requirement
- if (packageName.equals("com.android.chrome") || mInstrumentation.isInstrumenting()) {
+ if (mInstrumentation.isInstrumenting()) {
Log.e(TAG, msg);
} else {
throw new IllegalArgumentException(msg);
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/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/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/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/graphics/fonts/FontFamilyUpdateRequest.java b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java
index fbc951e..9290497 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,9 +273,6 @@
/**
* Returns the index of collection
- *
- * TODO(183752879): Make font index configurable and make this SystemApi.
- * @hide
*/
public @IntRange(from = 0) int getIndex() {
return 0;
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/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 2d6fa3c..b427df7 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -302,7 +302,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 +342,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 +365,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 (!usage.packageName.equals(SYSTEM_PKG) && (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,8 +395,8 @@
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.
@@ -411,12 +413,12 @@
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)) {
@@ -440,9 +442,9 @@
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);
}
}
@@ -490,8 +492,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/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/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/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/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/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index 4b88a9b..18f29ae 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -17,8 +17,8 @@
package android.window;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.annotation.UiThread;
import android.app.Activity;
import android.app.ActivityThread;
import android.content.Context;
@@ -52,7 +52,13 @@
* @see OnExitAnimationListener#onSplashScreenExit(SplashScreenView)
*/
@SuppressLint("ExecutorRegistration")
- void setOnExitAnimationListener(@Nullable SplashScreen.OnExitAnimationListener listener);
+ void setOnExitAnimationListener(@NonNull SplashScreen.OnExitAnimationListener listener);
+
+ /**
+ * Clear exist listener
+ * @see #setOnExitAnimationListener
+ */
+ void clearOnExitAnimationListener();
/**
* Listens for the splash screen exit event.
@@ -63,15 +69,14 @@
* of the activity. The {@link SplashScreenView} represents the splash screen view
* object, developer can make an exit animation based on this view.</p>
*
- * <p>If {@link SplashScreenView#remove} is not called after 5000ms, the method will be
- * automatically called and the splash screen removed.</p>
- *
- * <p>This method is never invoked if your activity sets
- * {@link #setOnExitAnimationListener} to <code>null</code>..
+ * <p>This method is never invoked if your activity clear the listener by
+ * {@link #clearOnExitAnimationListener}.
*
* @param view The view object which on top of this Activity.
* @see #setOnExitAnimationListener
+ * @see #clearOnExitAnimationListener
*/
+ @UiThread
void onSplashScreenExit(@NonNull SplashScreenView view);
}
@@ -90,20 +95,30 @@
@Override
public void setOnExitAnimationListener(
- @Nullable SplashScreen.OnExitAnimationListener listener) {
+ @NonNull SplashScreen.OnExitAnimationListener listener) {
if (mActivityToken == null) {
// This is not an activity.
return;
}
synchronized (mGlobal.mGlobalLock) {
- mExitAnimationListener = listener;
if (listener != null) {
+ mExitAnimationListener = listener;
mGlobal.addImpl(this);
- } else {
- mGlobal.removeImpl(this);
}
}
}
+
+ @Override
+ public void clearOnExitAnimationListener() {
+ if (mActivityToken == null) {
+ // This is not an activity.
+ return;
+ }
+ synchronized (mGlobal.mGlobalLock) {
+ mExitAnimationListener = null;
+ mGlobal.removeImpl(this);
+ }
+ }
}
/**
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 9789d70..933760c 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.annotation.UiThread;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
@@ -32,7 +33,6 @@
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.SystemClock;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
@@ -46,7 +46,8 @@
import com.android.internal.R;
import com.android.internal.policy.DecorView;
-import java.util.function.Consumer;
+import java.time.Duration;
+import java.time.Instant;
/**
* <p>The view which allows an activity to customize its splash screen exit animation.</p>
@@ -75,8 +76,8 @@
private Bitmap mParceledIconBitmap;
private View mBrandingImageView;
private Bitmap mParceledBrandingBitmap;
- private long mIconAnimationDuration;
- private long mIconAnimationStart;
+ private Duration mIconAnimationDuration;
+ private Instant mIconAnimationStart;
// The host activity when transfer view to it.
private Activity mHostActivity;
@@ -85,6 +86,7 @@
private boolean mDrawBarBackground;
private int mStatusBarColor;
private int mNavigationBarColor;
+ private boolean mHasRemoved;
/**
* Internal builder to create a SplashScreenView object.
@@ -101,8 +103,8 @@
private int mBrandingImageHeight;
private Drawable mBrandingDrawable;
private Bitmap mParceledBrandingBitmap;
- private long mIconAnimationStart;
- private long mIconAnimationDuration;
+ private Instant mIconAnimationStart;
+ private Duration mIconAnimationDuration;
public Builder(@NonNull Context context) {
mContext = context;
@@ -126,8 +128,8 @@
parcelable.mBrandingHeight);
mParceledBrandingBitmap = parcelable.mBrandingBitmap;
}
- mIconAnimationStart = parcelable.mIconAnimationStart;
- mIconAnimationDuration = parcelable.mIconAnimationDuration;
+ mIconAnimationStart = Instant.ofEpochMilli(parcelable.mIconAnimationStartMillis);
+ mIconAnimationDuration = Duration.ofMillis(parcelable.mIconAnimationDurationMillis);
return this;
}
@@ -166,8 +168,8 @@
/**
* Set the animation duration if icon is animatable.
*/
- public Builder setAnimationDuration(int duration) {
- mIconAnimationDuration = duration;
+ public Builder setAnimationDurationMillis(int duration) {
+ mIconAnimationDuration = Duration.ofMillis(duration);
return this;
}
@@ -203,7 +205,8 @@
}
if (mIconDrawable != null) {
view.mIconView.setBackground(mIconDrawable);
- view.initIconAnimation(mIconDrawable, mIconAnimationDuration);
+ view.initIconAnimation(mIconDrawable,
+ mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
}
view.mIconAnimationStart = mIconAnimationStart;
view.mIconAnimationDuration = mIconAnimationDuration;
@@ -266,15 +269,16 @@
* @see android.R.attr#windowSplashScreenAnimatedIcon
* @see android.R.attr#windowSplashScreenAnimationDuration
*/
- public long getIconAnimationDurationMillis() {
+ @Nullable
+ public Duration getIconAnimationDuration() {
return mIconAnimationDuration;
}
/**
- * If the replaced icon is animatable, return the animation start time in millisecond based on
- * system. The start time is set using {@link SystemClock#uptimeMillis()}.
+ * If the replaced icon is animatable, return the animation start time based on system clock.
*/
- public long getIconAnimationStartMillis() {
+ @Nullable
+ public Instant getIconAnimationStart() {
return mIconAnimationStart;
}
@@ -286,8 +290,8 @@
aniDrawable.prepareAnimate(duration, this::animationStartCallback);
}
- private void animationStartCallback(long startAt) {
- mIconAnimationStart = startAt;
+ private void animationStartCallback() {
+ mIconAnimationStart = Instant.now();
}
/**
@@ -295,7 +299,11 @@
* <p><strong>Do not</strong> invoke this method from a drawing method
* ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
*/
+ @UiThread
public void remove() {
+ if (mHasRemoved) {
+ return;
+ }
setVisibility(GONE);
if (mParceledIconBitmap != null) {
mIconView.setBackground(null);
@@ -321,6 +329,7 @@
if (mHostActivity != null) {
mHostActivity.detachSplashScreenView();
}
+ mHasRemoved = true;
}
/**
@@ -414,7 +423,7 @@
* @param startListener The callback listener used to receive the start of the animation.
* @return true if this drawable object can also be animated and it can be played now.
*/
- protected boolean prepareAnimate(long duration, Consumer<Long> startListener) {
+ protected boolean prepareAnimate(long duration, Runnable startListener) {
return false;
}
}
@@ -433,8 +442,8 @@
private int mBrandingHeight;
private Bitmap mBrandingBitmap;
- private long mIconAnimationStart;
- private long mIconAnimationDuration;
+ private long mIconAnimationStartMillis;
+ private long mIconAnimationDurationMillis;
public SplashScreenViewParcelable(SplashScreenView view) {
ViewGroup.LayoutParams params = view.getIconView().getLayoutParams();
@@ -447,8 +456,12 @@
mBrandingWidth = params.width;
mBrandingHeight = params.height;
- mIconAnimationStart = view.getIconAnimationStartMillis();
- mIconAnimationDuration = view.getIconAnimationDurationMillis();
+ if (view.getIconAnimationStart() != null) {
+ mIconAnimationStartMillis = view.getIconAnimationStart().toEpochMilli();
+ }
+ if (view.getIconAnimationDuration() != null) {
+ mIconAnimationDurationMillis = view.getIconAnimationDuration().toMillis();
+ }
}
private Bitmap copyDrawable(Drawable drawable) {
@@ -479,8 +492,8 @@
mBrandingWidth = source.readInt();
mBrandingHeight = source.readInt();
mBrandingBitmap = source.readTypedObject(Bitmap.CREATOR);
- mIconAnimationStart = source.readLong();
- mIconAnimationDuration = source.readLong();
+ mIconAnimationStartMillis = source.readLong();
+ mIconAnimationDurationMillis = source.readLong();
mIconBackground = source.readInt();
}
@@ -497,8 +510,8 @@
dest.writeInt(mBrandingWidth);
dest.writeInt(mBrandingHeight);
dest.writeTypedObject(mBrandingBitmap, flags);
- dest.writeLong(mIconAnimationStart);
- dest.writeLong(mIconAnimationDuration);
+ dest.writeLong(mIconAnimationStartMillis);
+ dest.writeLong(mIconAnimationDurationMillis);
dest.writeInt(mIconBackground);
}
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index c7672dc..08bb1a9 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -50,12 +50,19 @@
*/
public static final int STARTING_WINDOW_TYPE_SNAPSHOT = 2;
/**
+ * Prefer empty splash screen starting window.
+ * @hide
+ */
+ public static final int STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN = 3;
+
+ /**
* @hide
*/
@IntDef(flag = true, prefix = "STARTING_WINDOW_TYPE_", value = {
STARTING_WINDOW_TYPE_NONE,
STARTING_WINDOW_TYPE_SPLASH_SCREEN,
- STARTING_WINDOW_TYPE_SNAPSHOT
+ STARTING_WINDOW_TYPE_SNAPSHOT,
+ STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN
})
public @interface StartingWindowType {}
@@ -95,7 +102,8 @@
TYPE_PARAMETER_TASK_SWITCH,
TYPE_PARAMETER_PROCESS_RUNNING,
TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT,
- TYPE_PARAMETER_ACTIVITY_CREATED
+ TYPE_PARAMETER_ACTIVITY_CREATED,
+ TYPE_PARAMETER_SAME_PACKAGE
})
public @interface StartingTypeParams {}
@@ -112,6 +120,8 @@
public static final int TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT = 0x00000008;
/** @hide */
public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010;
+ /** @hide */
+ public static final int TYPE_PARAMETER_SAME_PACKAGE = 0x00000020;
/**
* The parameters which effect the starting window type.
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/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/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 0bed29b..8b70966 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1026,21 +1026,6 @@
gUsapPoolCount = 0;
}
-NO_PAC_FUNC
-static void PAuthKeyChange(JNIEnv* env) {
-#ifdef __aarch64__
- unsigned long int hwcaps = getauxval(AT_HWCAP);
- if (hwcaps & HWCAP_PACA) {
- const unsigned long key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
- PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY;
- if (prctl(PR_PAC_RESET_KEYS, key_mask, 0, 0, 0) != 0) {
- ALOGE("Failed to change the PAC keys: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "PAC key change failed.");
- }
- }
-#endif
-}
-
// Create an app data directory over tmpfs overlayed CE / DE storage, and bind mount it
// from the actual app data directory in data mirror.
static bool createAndMountAppData(std::string_view package_name,
@@ -2020,7 +2005,6 @@
}
// Utility routine to fork a process from the zygote.
-NO_PAC_FUNC
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
const std::vector<int>& fds_to_ignore,
@@ -2075,7 +2059,6 @@
}
// The child process.
- PAuthKeyChange(env);
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
@@ -2107,7 +2090,6 @@
PreApplicationInit();
}
-NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
@@ -2157,7 +2139,6 @@
return pid;
}
-NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
@@ -2229,7 +2210,6 @@
* @param is_priority_fork Controls the nice level assigned to the newly created process
* @return child pid in the parent, 0 in the child
*/
-NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkApp(JNIEnv* env,
jclass,
jint read_pipe_fd,
@@ -2244,7 +2224,6 @@
args_known == JNI_TRUE, is_priority_fork == JNI_TRUE, true);
}
-NO_PAC_FUNC
int zygote::forkApp(JNIEnv* env,
int read_pipe_fd,
int write_pipe_fd,
diff --git a/core/jni/com_android_internal_os_Zygote.h b/core/jni/com_android_internal_os_Zygote.h
index d2da914..b87396c 100644
--- a/core/jni/com_android_internal_os_Zygote.h
+++ b/core/jni/com_android_internal_os_Zygote.h
@@ -20,18 +20,6 @@
#define LOG_TAG "Zygote"
#define ATRACE_TAG ATRACE_TAG_DALVIK
-/* Functions in the callchain during the fork shall not be protected with
- Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
-#ifdef __ARM_FEATURE_PAC_DEFAULT
-#ifdef __ARM_FEATURE_BTI_DEFAULT
-#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
-#else
-#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
-#endif /* __ARM_FEATURE_BTI_DEFAULT */
-#else /* !__ARM_FEATURE_PAC_DEFAULT */
-#define NO_PAC_FUNC
-#endif /* __ARM_FEATURE_PAC_DEFAULT */
-
#include <jni.h>
#include <vector>
#include <android-base/stringprintf.h>
@@ -42,7 +30,6 @@
namespace android {
namespace zygote {
-NO_PAC_FUNC
pid_t ForkCommon(JNIEnv* env,bool is_system_server,
const std::vector<int>& fds_to_close,
const std::vector<int>& fds_to_ignore,
@@ -57,7 +44,6 @@
* communication is required. Is_priority_fork should be true if this is on the app startup
* critical path. Purge specifies that unused pages should be purged before the fork.
*/
-NO_PAC_FUNC
int forkApp(JNIEnv* env,
int read_pipe_fd,
int write_pipe_fd,
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 011e8f8..24fef48 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -365,7 +365,6 @@
// We only process fork commands if the peer uid matches expected_uid.
// For every fork command after the first, we check that the requested uid is at
// least minUid.
-NO_PAC_FUNC
jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
JNIEnv* env,
jclass,
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..46f2f3e 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" />
@@ -4258,6 +4257,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/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/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/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/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 855faaa..516dfd0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -357,7 +357,7 @@
if (iconDrawable != null) {
builder.setCenterViewDrawable(iconDrawable);
}
- builder.setAnimationDuration(mIconAnimationDuration);
+ builder.setAnimationDurationMillis(mIconAnimationDuration);
if (mBrandingDrawable != null) {
builder.setBrandingDrawable(mBrandingDrawable, mBrandingImageWidth,
mBrandingImageHeight);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index a4a83eb..4196d68 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -37,15 +37,12 @@
import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.SystemClock;
import android.os.Trace;
import android.util.PathParser;
import android.window.SplashScreenView;
import com.android.internal.R;
-import java.util.function.Consumer;
-
/**
* Creating a lightweight Drawable object used for splash screen.
* @hide
@@ -133,7 +130,6 @@
private Animatable mAnimatableIcon;
private Animator mIconAnimator;
private boolean mAnimationTriggered;
- private long mIconAnimationStart;
AnimatableIconDrawable(@ColorInt int backgroundColor, Drawable foregroundDrawable) {
mForegroundDrawable = foregroundDrawable;
@@ -150,16 +146,15 @@
}
@Override
- protected boolean prepareAnimate(long duration, Consumer<Long> startListener) {
+ protected boolean prepareAnimate(long duration, Runnable startListener) {
mAnimatableIcon = (Animatable) mForegroundDrawable;
mIconAnimator = ValueAnimator.ofInt(0, 1);
mIconAnimator.setDuration(duration);
mIconAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
- mIconAnimationStart = SystemClock.uptimeMillis();
if (startListener != null) {
- startListener.accept(mIconAnimationStart);
+ startListener.run();
}
mAnimatableIcon.start();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 29a144f..e95135a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -105,8 +105,10 @@
/**
* Called when a task need a splash screen starting window.
+ * @param emptyView Whether drawing an empty frame without anything on it.
*/
- public void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+ void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken,
+ boolean emptyView) {
final RunningTaskInfo taskInfo = windowInfo.taskInfo;
final ActivityInfo activityInfo = taskInfo.topActivityInfo;
if (activityInfo == null) {
@@ -203,7 +205,6 @@
}
final PhoneWindow win = new PhoneWindow(context);
- win.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
win.setIsStartingWindow(true);
CharSequence label = context.getResources().getText(labelRes, null);
@@ -270,17 +271,20 @@
try {
final View view = win.getDecorView();
final WindowManager wm = mContext.getSystemService(WindowManager.class);
- // splash screen content will be deprecated after S.
- sView = SplashscreenContentDrawer.makeSplashscreenContent(
- context, splashscreenContentResId[0]);
- final boolean splashscreenContentCompatible = sView != null;
- if (splashscreenContentCompatible) {
- win.setContentView(sView);
- } else {
- sView = mSplashscreenContentDrawer
- .makeSplashScreenContentView(context, activityInfo);
- win.setContentView(sView);
- sView.cacheRootWindow(win);
+ if (!emptyView) {
+ // splash screen content will be deprecated after S.
+ sView = SplashscreenContentDrawer.makeSplashscreenContent(
+ context, splashscreenContentResId[0]);
+ final boolean splashscreenContentCompatible = sView != null;
+ if (splashscreenContentCompatible) {
+ win.setContentView(sView);
+ } else {
+ sView = mSplashscreenContentDrawer
+ .makeSplashScreenContentView(context, activityInfo);
+ win.setContentView(sView);
+ win.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+ sView.cacheRootWindow(win);
+ }
}
postAddWindow(taskId, appToken, view, wm, params);
} catch (RuntimeException e) {
@@ -393,6 +397,9 @@
// animation
removeWindowInner(record.mDecorView, false);
}
+ } else {
+ // no animation will be applied
+ removeWindowInner(record.mDecorView, false);
}
}
if (record.mTaskSnapshotWindow != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index a06068d6..8a629bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.startingsurface;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
@@ -23,6 +24,7 @@
import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_SAME_PACKAGE;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
@@ -65,7 +67,8 @@
*/
public class StartingWindowController implements RemoteCallable<StartingWindowController> {
private static final String TAG = StartingWindowController.class.getSimpleName();
- static final boolean DEBUG_SPLASH_SCREEN = false;
+ // TODO b/183150443 Keep this flag open for a while, several things might need to adjust.
+ static final boolean DEBUG_SPLASH_SCREEN = true;
static final boolean DEBUG_TASK_SNAPSHOT = false;
private final StartingSurfaceDrawer mStartingSurfaceDrawer;
@@ -123,24 +126,37 @@
final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
+ final boolean samePackage = (parameter & TYPE_PARAMETER_SAME_PACKAGE) != 0;
return estimateStartingWindowType(windowInfo, newTask, taskSwitch,
- processRunning, allowTaskSnapshot, activityCreated);
+ processRunning, allowTaskSnapshot, activityCreated, samePackage);
}
// reference from ActivityRecord#getStartingWindowType
private int estimateStartingWindowType(StartingWindowInfo windowInfo,
boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated) {
+ boolean allowTaskSnapshot, boolean activityCreated, boolean samePackage) {
if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
+ " taskSwitch " + taskSwitch
+ " processRunning " + processRunning
+ " allowTaskSnapshot " + allowTaskSnapshot
- + " activityCreated " + activityCreated);
+ + " activityCreated " + activityCreated
+ + " samePackage " + samePackage);
}
- if ((newTask || !processRunning || (taskSwitch && !activityCreated))
- && windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
- return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
+ if (!processRunning) {
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
+ if (newTask) {
+ if (samePackage) {
+ return STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
+ } else {
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
+ }
+ if (taskSwitch && !activityCreated) {
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
}
if (taskSwitch && allowTaskSnapshot) {
final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
@@ -207,6 +223,10 @@
mTaskLaunchingCallback = listener;
}
+ private boolean shouldSendToListener(int suggestionType) {
+ return suggestionType != STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
+ }
+
/**
* Called when a task need a starting window.
*/
@@ -214,11 +234,15 @@
mSplashScreenExecutor.execute(() -> {
final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
- if (mTaskLaunchingCallback != null) {
+ if (mTaskLaunchingCallback != null && shouldSendToListener(suggestionType)) {
mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
}
if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
- mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken,
+ false /* emptyView */);
+ } else if (suggestionType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN) {
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken,
+ true /* emptyView */);
} else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 78b3d4e..d1d1313 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -131,7 +131,7 @@
final Handler mainLoop = new Handler(Looper.getMainLooper());
final StartingWindowInfo windowInfo =
createWindowInfo(taskId, android.R.style.Theme);
- mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder, false);
waitHandlerIdle(mainLoop);
verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
@@ -148,7 +148,7 @@
final Handler mainLoop = new Handler(Looper.getMainLooper());
final StartingWindowInfo windowInfo =
createWindowInfo(taskId, 0);
- mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder, false);
waitHandlerIdle(mainLoop);
verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
assertNotEquals(mStartingSurfaceDrawer.mViewThemeResId, 0);
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/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..5627a7e 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>
@@ -256,6 +257,11 @@
canvas->drawAnnotation(bounds, String8::format(
"SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);
}
+
+ if (renderNode->hasHolePunches()) {
+ TransformCanvas transformCanvas(canvas);
+ displayList->draw(&transformCanvas);
+ }
canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,
SkCanvas::kStrict_SrcRectConstraint);
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/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/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index b77d821..e2db2d6 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -3475,6 +3475,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/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/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 4ff3c55..5a3298d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -405,6 +405,9 @@
<!-- Permission required for CTS test - CtsHdmiCecHostTestCases -->
<uses-permission android:name="android.permission.HDMI_CEC" />
+ <!-- Permission needed for CTS test - MediaPlayerTest -->
+ <uses-permission android:name="android.permission.BIND_IMS_SERVICE" />
+
<!-- Permission needed for CTS test - WifiManagerTest -->
<uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index a235935..6574353 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -70,7 +70,6 @@
"res",
],
static_libs: [
- "bcsmartspace",
"WindowManager-Shell",
"SystemUIPluginLib",
"SystemUISharedLib",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e97d279..88d7710 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -275,8 +275,7 @@
<!-- Permission to make accessibility service access Bubbles -->
<uses-permission android:name="android.permission.ADD_TRUSTED_DISPLAY" />
- <!-- Permission for Smartspace. -->
- <uses-permission android:name="android.permission.MANAGE_SMARTSPACE"/>
+ <uses-permission android:name="android.permission.MANAGE_SMARTSPACE" />
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_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/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/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/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/ids.xml b/packages/SystemUI/res/values/ids.xml
index 9665c89..bb9d331 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -173,5 +173,7 @@
<item type="id" name="action_move_top_right"/>
<item type="id" name="action_move_bottom_left"/>
<item type="id" name="action_move_bottom_right"/>
+ <item type="id" name="action_move_to_edge_and_hide"/>
+ <item type="id" name="action_move_out_edge_and_show"/>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fba6269..4a29578 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2705,6 +2705,10 @@
<string name="accessibility_floating_button_action_move_bottom_left">Move bottom left</string>
<!-- Action in accessibility menu to move the accessibility floating button to the bottom right of the screen. [CHAR LIMIT=30]-->
<string name="accessibility_floating_button_action_move_bottom_right">Move bottom right</string>
+ <!-- Action in accessibility menu to move the accessibility floating button to the edge and hide it to half. [CHAR LIMIT=30]-->
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half">Move to edge and hide</string>
+ <!-- Action in accessibility menu to move the accessibility floating button out the edge and show. [CHAR LIMIT=30]-->
+ <string name="accessibility_floating_button_action_move_out_edge_and_show">Move out edge and show</string>
<!-- Device Controls strings -->
<!-- Device Controls empty state, title [CHAR LIMIT=30] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e6fc332..de14dbd 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>
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/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/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
index 57be4e8..d89dff5 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -303,25 +303,39 @@
final Rect bounds = getAvailableBounds();
if (action == R.id.action_move_top_left) {
+ setShapeType(ShapeType.OVAL);
snapToLocation(bounds.left, bounds.top);
return true;
}
if (action == R.id.action_move_top_right) {
+ setShapeType(ShapeType.OVAL);
snapToLocation(bounds.right, bounds.top);
return true;
}
if (action == R.id.action_move_bottom_left) {
+ setShapeType(ShapeType.OVAL);
snapToLocation(bounds.left, bounds.bottom);
return true;
}
if (action == R.id.action_move_bottom_right) {
+ setShapeType(ShapeType.OVAL);
snapToLocation(bounds.right, bounds.bottom);
return true;
}
+ if (action == R.id.action_move_to_edge_and_hide) {
+ setShapeType(ShapeType.HALF_OVAL);
+ return true;
+ }
+
+ if (action == R.id.action_move_out_edge_and_show) {
+ setShapeType(ShapeType.OVAL);
+ return true;
+ }
+
return false;
}
@@ -446,6 +460,16 @@
res.getString(
R.string.accessibility_floating_button_action_move_bottom_right));
info.addAction(moveBottomRight);
+
+ final int moveEdgeId = mShapeType == ShapeType.OVAL
+ ? R.id.action_move_to_edge_and_hide
+ : R.id.action_move_out_edge_and_show;
+ final int moveEdgeTextResId = mShapeType == ShapeType.OVAL
+ ? R.string.accessibility_floating_button_action_move_to_edge_and_hide_to_half
+ : R.string.accessibility_floating_button_action_move_out_edge_and_show;
+ final AccessibilityAction moveToOrOutEdge =
+ new AccessibilityAction(moveEdgeId, res.getString(moveEdgeTextResId));
+ info.addAction(moveToOrOutEdge);
}
private boolean onTouched(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 4e93f58..1c0aa06 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -589,7 +589,7 @@
@Override
public void dismissFromSystemServer() {
- removeWindowIfAttached();
+ animateAway(false /* sendReason */, 0 /* reason */);
}
@Override
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..405151d 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;
@@ -53,6 +54,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 +91,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;
@@ -292,6 +294,8 @@
Log.v(TAG, "onTouch | finger up");
onFingerUp();
}
+ mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
+
break;
default:
@@ -311,9 +315,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 +329,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 +357,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
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 6812f77..5bdc7a4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -224,7 +224,9 @@
}
FalsingClassifier.Result singleTapResult =
- mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents());
+ mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents().isEmpty()
+ ? mDataProvider.getPriorMotionEvents()
+ : mDataProvider.getRecentMotionEvents());
mPriorResults = Collections.singleton(singleTapResult);
if (!singleTapResult.isFalse() && robustCheck) {
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/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/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 33681c8..a3ff375 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -1,7 +1,6 @@
package com.android.systemui.media
import android.animation.ArgbEvaluator
-import android.app.smartspace.SmartspaceTarget
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
@@ -202,18 +201,9 @@
}
}
- override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
- Log.d(TAG, "My Smartspace media update is here")
- addOrUpdateSmartspaceMediaRecommendations(key, data)
- }
-
override fun onMediaDataRemoved(key: String) {
removePlayer(key)
}
-
- override fun onSmartspaceMediaDataRemoved(key: String) {
- Log.d(TAG, "My Smartspace media removal request is received")
- }
})
mediaFrame.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
// The pageIndicator is not laid out yet when we get the current state update,
@@ -301,10 +291,6 @@
}
}
- private fun addOrUpdateSmartspaceMediaRecommendations(key: String, data: SmartspaceTarget) {
- // TODO(b/182813345): Add Smartspace media recommendation view.
- }
-
private fun removePlayer(key: String, dismissMediaData: Boolean = true) {
val removed = MediaPlayerData.removeMediaPlayer(key)
removed?.apply {
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/media/MediaDataCombineLatest.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
index 2c094b8..aa3699e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media
-import android.app.smartspace.SmartspaceTarget
import javax.inject.Inject
/**
@@ -38,18 +37,10 @@
}
}
- override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
- listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, data) }
- }
-
override fun onMediaDataRemoved(key: String) {
remove(key)
}
- override fun onSmartspaceMediaDataRemoved(key: String) {
- listeners.toSet().forEach { it.onSmartspaceMediaDataRemoved(key) }
- }
-
override fun onMediaDeviceChanged(
key: String,
oldKey: String?,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
index aab2747..1f580a9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media
-import android.app.smartspace.SmartspaceTarget
import android.util.Log
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -83,10 +82,6 @@
}
}
- override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
- listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data) }
- }
-
override fun onMediaDataRemoved(key: String) {
allEntries.remove(key)
userEntries.remove(key)?.let {
@@ -97,10 +92,6 @@
}
}
- override fun onSmartspaceMediaDataRemoved(key: String) {
- listeners.forEach { it.onSmartspaceMediaDataRemoved(key) }
- }
-
@VisibleForTesting
internal fun handleUserSwitched(id: Int) {
// If the user changes, remove all current MediaData objects and inform listeners
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index dfd588d..41c9dae 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -18,10 +18,6 @@
import android.app.Notification
import android.app.PendingIntent
-import android.app.smartspace.SmartspaceConfig
-import android.app.smartspace.SmartspaceManager
-import android.app.smartspace.SmartspaceSession
-import android.app.smartspace.SmartspaceTarget
import android.content.BroadcastReceiver
import android.content.ContentResolver
import android.content.Context
@@ -37,7 +33,6 @@
import android.media.session.MediaController
import android.media.session.MediaSession
import android.net.Uri
-import android.os.Parcelable
import android.os.UserHandle
import android.service.notification.StatusBarNotification
import android.text.TextUtils
@@ -50,7 +45,6 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.util.Assert
@@ -60,7 +54,6 @@
import java.io.IOException
import java.io.PrintWriter
import java.util.concurrent.Executor
-import java.util.concurrent.Executors
import javax.inject.Inject
// URI fields to try loading album art from
@@ -106,16 +99,9 @@
mediaDataCombineLatest: MediaDataCombineLatest,
private val mediaDataFilter: MediaDataFilter,
private val activityStarter: ActivityStarter,
- private val smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
private var useMediaResumption: Boolean,
private val useQsMediaPlayer: Boolean
-) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
-
- companion object {
- // UI surface label for subscribing Smartspace updates.
- @JvmField
- val SMARTSPACE_UI_SURFACE_LABEL = "media_data_manager"
- }
+) : Dumpable {
private val themeText = com.android.settingslib.Utils.getColorAttr(context,
com.android.internal.R.attr.textColorPrimary).defaultColor
@@ -131,8 +117,6 @@
// TODO(b/159539991#comment5): Move internal listeners to separate package.
private val internalListeners: MutableSet<Listener> = mutableSetOf()
private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
- // There should ONLY be at most one Smartspace media recommendation.
- private var smartspaceMediaTarget: SmartspaceTarget? = null
internal var appsBlockedFromResume: MutableSet<String> = Utils.getBlockedMediaApps(context)
set(value) {
// Update list
@@ -144,7 +128,6 @@
removeAllForPackage(it)
}
}
- private var smartspaceSession: SmartspaceSession? = null
@Inject
constructor(
@@ -160,13 +143,11 @@
mediaDeviceManager: MediaDeviceManager,
mediaDataCombineLatest: MediaDataCombineLatest,
mediaDataFilter: MediaDataFilter,
- activityStarter: ActivityStarter,
- smartspaceMediaDataProvider: SmartspaceMediaDataProvider
+ activityStarter: ActivityStarter
) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory,
broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener,
mediaSessionBasedFilter, mediaDeviceManager, mediaDataCombineLatest, mediaDataFilter,
- activityStarter, smartspaceMediaDataProvider, Utils.useMediaResumption(context),
- Utils.useQsMediaPlayer(context))
+ activityStarter, Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context))
private val appChangeReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -219,31 +200,9 @@
}
// BroadcastDispatcher does not allow filters with data schemes
context.registerReceiver(appChangeReceiver, uninstallFilter)
-
- // Register for Smartspace data updates.
- smartspaceMediaDataProvider.registerListener(this)
- val smartspaceManager: SmartspaceManager =
- context.getSystemService(SmartspaceManager::class.java)
- smartspaceSession = smartspaceManager.createSmartspaceSession(
- SmartspaceConfig.Builder(context, SMARTSPACE_UI_SURFACE_LABEL).build())
- smartspaceSession?.let {
- it.registerSmartspaceUpdates(
- // Use a new thread listening to Smartspace updates instead of using the existing
- // backgroundExecutor. SmartspaceSession has scheduled routine updates which can be
- // unpredictable on test simulators, using the backgroundExecutor makes it's hard to
- // test the threads numbers.
- // Switch to use backgroundExecutor when SmartspaceSession has a good way to be
- // mocked.
- Executors.newCachedThreadPool(),
- SmartspaceSession.Callback { targets ->
- smartspaceMediaDataProvider.onTargetsAvailable(targets)
- })
- }
- smartspaceSession?.let { it.requestSmartspaceUpdate() }
}
fun destroy() {
- smartspaceMediaDataProvider.unregisterListener(this)
context.unregisterReceiver(appChangeReceiver)
}
@@ -350,7 +309,7 @@
private fun addInternalListener(listener: Listener) = internalListeners.add(listener)
/**
- * Notify internal listeners of media loaded event.
+ * Notify internal listeners of loaded event.
*
* External listeners registered with [addListener] will be notified after the event propagates
* through the internal listener pipeline.
@@ -360,17 +319,7 @@
}
/**
- * Notify internal listeners of Smartspace media loaded event.
- *
- * External listeners registered with [addListener] will be notified after the event propagates
- * through the internal listener pipeline.
- */
- private fun notifySmartspaceMediaDataLoaded(key: String, info: SmartspaceTarget) {
- internalListeners.forEach { it.onSmartspaceMediaDataLoaded(key, info) }
- }
-
- /**
- * Notify internal listeners of media removed event.
+ * Notify internal listeners of removed event.
*
* External listeners registered with [addListener] will be notified after the event propagates
* through the internal listener pipeline.
@@ -380,16 +329,6 @@
}
/**
- * Notify internal listeners of Smartspace media removed event.
- *
- * External listeners registered with [addListener] will be notified after the event propagates
- * through the internal listener pipeline.
- */
- private fun notifySmartspaceMediaDataRemoved(key: String) {
- internalListeners.forEach { it.onSmartspaceMediaDataRemoved(key) }
- }
-
- /**
* Called whenever the player has been paused or stopped for a while, or swiped from QQS.
* This will make the player not active anymore, hiding it from QQS and Keyguard.
* @see MediaData.active
@@ -662,49 +601,6 @@
}
}
- override fun onSmartspaceTargetsUpdated(targets: List<Parcelable>) {
- Log.d(TAG, "My Smartspace media updates are here")
- val mediaTargets = targets.filterIsInstance<SmartspaceTarget>()
- when (mediaTargets.size) {
- 0 -> {
- Log.d(TAG, "Empty Smartspace media target")
- smartspaceMediaTarget?.let {
- notifySmartspaceMediaDataRemoved(it.smartspaceTargetId)
- }
- smartspaceMediaTarget = null
- }
- 1 -> {
- // TODO(b/182811956): Reactivate the resumable media sessions whose last active
- // time is within 3 hours.
- // TODO(b/182813365): Wire this up with MediaTimeoutListener so the session can be
- // expired after 30 seconds.
- val newMediaTarget = mediaTargets.get(0)
- if (smartspaceMediaTarget != null &&
- smartspaceMediaTarget!!.smartspaceTargetId ==
- newMediaTarget.smartspaceTargetId) {
- // The same Smartspace updates can be received. Only send the first one.
- Log.d(TAG, "Same Smartspace media update exists. Skip loading data.")
- } else {
- smartspaceMediaTarget?.let {
- notifySmartspaceMediaDataRemoved(it.smartspaceTargetId)
- }
- notifySmartspaceMediaDataLoaded(
- newMediaTarget.smartspaceTargetId, newMediaTarget)
- smartspaceMediaTarget = newMediaTarget
- }
- }
- else -> {
- // There should NOT be more than 1 Smartspace media update. When it happens, it
- // indicates a bad state or an error. Reset the status accordingly.
- Log.wtf(TAG, "More than 1 Smartspace Media Update. Resetting the status...")
- smartspaceMediaTarget?.let {
- notifySmartspaceMediaDataRemoved(it.smartspaceTargetId)
- }
- smartspaceMediaTarget = null
- }
- }
- }
-
fun onNotificationRemoved(key: String) {
Assert.isMainThread()
val removed = mediaEntries.remove(key)
@@ -789,16 +685,10 @@
*/
fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {}
- /** Called whenever there's new Smartspace media data loaded. */
- fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {}
-
/**
* Called whenever a previously existing Media notification was removed
*/
fun onMediaDataRemoved(key: String) {}
-
- /** Called whenever a previously existing Smartspace media data was removed. */
- fun onSmartspaceMediaDataRemoved(key: String) {}
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
index 8c12a30..b74ca28 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -1,6 +1,5 @@
package com.android.systemui.media
-import android.app.smartspace.SmartspaceTarget
import android.graphics.Rect
import android.util.ArraySet
import android.view.View
@@ -54,17 +53,9 @@
updateViewVisibility()
}
- override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
- updateViewVisibility()
- }
-
override fun onMediaDataRemoved(key: String) {
updateViewVisibility()
}
-
- override fun onSmartspaceMediaDataRemoved(key: String) {
- updateViewVisibility()
- }
}
fun addVisibilityChangeListener(listener: (Boolean) -> Unit) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt
index d973478..f695622 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media
-import android.app.smartspace.SmartspaceTarget
import android.content.ComponentName
import android.content.Context
import android.media.session.MediaController
@@ -135,12 +134,6 @@
}
}
- override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
- backgroundExecutor.execute {
- dispatchSmartspaceMediaDataLoaded(key, data)
- }
- }
-
override fun onMediaDataRemoved(key: String) {
// Queue on background thread to ensure ordering of loaded and removed events is maintained.
backgroundExecutor.execute {
@@ -149,12 +142,6 @@
}
}
- override fun onSmartspaceMediaDataRemoved(key: String) {
- backgroundExecutor.execute {
- dispatchSmartspaceMediaDataRemoved(key)
- }
- }
-
private fun dispatchMediaDataLoaded(key: String, oldKey: String?, info: MediaData) {
foregroundExecutor.execute {
listeners.toSet().forEach { it.onMediaDataLoaded(key, oldKey, info) }
@@ -167,18 +154,6 @@
}
}
- private fun dispatchSmartspaceMediaDataLoaded(key: String, info: SmartspaceTarget) {
- foregroundExecutor.execute {
- listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, info) }
- }
- }
-
- private fun dispatchSmartspaceMediaDataRemoved(key: String) {
- foregroundExecutor.execute {
- listeners.toSet().forEach { it.onSmartspaceMediaDataRemoved(key) }
- }
- }
-
private fun handleControllersChanged(controllers: List<MediaController>) {
packageControllers.clear()
controllers.forEach {
diff --git a/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt b/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt
deleted file mode 100644
index 0eab572..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.android.systemui.media
-
-import android.app.smartspace.SmartspaceTarget
-import com.android.systemui.plugins.BcSmartspaceDataPlugin
-import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
-import javax.inject.Inject
-
-/** Provides SmartspaceTargets of media types for SystemUI media control. */
-class SmartspaceMediaDataProvider @Inject constructor() : BcSmartspaceDataPlugin {
-
- private val smartspaceMediaTargetListeners: MutableList<SmartspaceTargetListener> =
- mutableListOf()
- private var smartspaceMediaTargets: List<SmartspaceTarget> = listOf()
-
- override fun registerListener(smartspaceTargetListener: SmartspaceTargetListener) {
- smartspaceMediaTargetListeners.add(smartspaceTargetListener)
- }
-
- override fun unregisterListener(smartspaceTargetListener: SmartspaceTargetListener?) {
- smartspaceMediaTargetListeners.remove(smartspaceTargetListener)
- }
-
- /** Updates Smartspace data and propagates it to any listeners. */
- fun onTargetsAvailable(targets: List<SmartspaceTarget>) {
- // Filter out non-media targets.
- val mediaTargets = mutableListOf<SmartspaceTarget>()
- for (target in targets) {
- val smartspaceTarget = target
- if (smartspaceTarget.featureType == SmartspaceTarget.FEATURE_MEDIA) {
- mediaTargets.add(smartspaceTarget)
- }
- }
-
- smartspaceMediaTargets = mediaTargets
- smartspaceMediaTargetListeners.forEach {
- it.onSmartspaceTargetsUpdated(smartspaceMediaTargets)
- }
- }
-}
\ No newline at end of file
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/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 a17aeba..1cb2683 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,9 @@
mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_CLICK, 0, getMetricsSpec(),
getInstanceId());
mQSLogger.logTileClick(mTileSpec, mStatusBarStateController.getState(), mState.state);
- mHandler.sendEmptyMessage(H.CLICK);
+ if (!mFalsingManager.isFalseTap(true, 0.1)) {
+ mHandler.sendEmptyMessage(H.CLICK);
+ }
}
public void secondaryClick() {
@@ -290,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) {
@@ -372,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);
}
/**
@@ -605,16 +616,14 @@
mContext, mEnforcedAdmin);
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
} else {
- if (!mFalsingManager.isFalseTap(true, 0.1)) {
- handleClick();
- }
+ handleClick();
}
} else if (msg.what == SECONDARY_CLICK) {
name = "handleSecondaryClick";
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/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/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 5782d38..c565a271 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -24,7 +24,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
-import android.app.smartspace.SmartspaceTarget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
@@ -249,11 +248,6 @@
}
@Override
- public void onSmartspaceMediaDataLoaded(@NonNull String key,
- @NonNull SmartspaceTarget data) {
- }
-
- @Override
public void onMediaDataRemoved(@NonNull String key) {
mNotifPipeline.getAllNotifs()
.stream()
@@ -266,9 +260,6 @@
getDismissedByUserStats(entry));
});
}
-
- @Override
- public void onSmartspaceMediaDataRemoved(@NonNull String key) {}
});
}
@@ -322,11 +313,6 @@
}
@Override
- public void onSmartspaceMediaDataLoaded(@NonNull String key,
- @NonNull SmartspaceTarget data) {
- }
-
- @Override
public void onMediaDataRemoved(@NonNull String key) {
NotificationEntry entry = mEntryManager.getPendingOrActiveNotif(key);
if (entry != null) {
@@ -337,9 +323,6 @@
NotificationListenerService.REASON_CANCEL);
}
}
-
- @Override
- public void onSmartspaceMediaDataRemoved(@NonNull String key) {}
});
}
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/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a3a4014..207a894 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;
@@ -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/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..f1f34dc 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;
@@ -692,6 +691,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 +1058,7 @@
mMainThreadHandler.post(() -> {
mOverlays.remove(plugin);
mNotificationShadeWindowController
- .setForcePluginOpen(mOverlays.size() != 0);
+ .setForcePluginOpen(mOverlays.size() != 0, this);
});
}
@@ -1081,7 +1081,7 @@
.setStateListener(b -> mOverlays.forEach(
o -> o.setCollapseDesired(b)));
mNotificationShadeWindowController
- .setForcePluginOpen(mOverlays.size() != 0);
+ .setForcePluginOpen(mOverlays.size() != 0, this);
});
}
}
@@ -1215,6 +1215,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 +1225,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 +1371,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 +1395,7 @@
mStatusBarNotificationActivityStarterBuilder
.setStatusBar(this)
.setActivityLaunchAnimator(mActivityLaunchAnimator)
+ .setNotificationAnimatorControllerProvider(mNotificationAnimationProvider)
.setNotificationPresenter(mPresenter)
.setNotificationPanelViewController(mNotificationPanelViewController)
.build();
@@ -1519,6 +1523,7 @@
mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
mLockscreenLockIconController = statusBarComponent.getLockscreenLockIconController();
mLockscreenLockIconController.init();
+ statusBarComponent.getAuthRippleController().init();
mNotificationPanelViewController.setLaunchAffordanceListener(
mLockscreenLockIconController::onShowingLaunchAffordanceChanged);
@@ -1798,7 +1803,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 +1996,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 +2014,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 +2731,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 +2739,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 +2815,7 @@
callback.onActivityStarted(ActivityManager.START_CANCELED);
}
};
- executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
+ executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShadeDirectly,
afterKeyguardGone, true /* deferred */);
}
@@ -3134,18 +3160,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 +3660,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 +4102,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 +4154,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 +4476,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 +4499,8 @@
action.run();
}).start();
- return mShadeController.collapsePanel();
+ boolean deferred = collapsePanel ? mShadeController.collapsePanel() : false;
+ return deferred;
}, afterKeyguardGone);
}
@@ -4443,27 +4512,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 +4568,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/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
index 814f073..28cc580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
@@ -348,61 +348,95 @@
final AccessibilityNodeInfo infos = new AccessibilityNodeInfo();
mMenuView.onInitializeAccessibilityNodeInfo(infos);
- assertThat(infos.getActionList().size()).isEqualTo(4);
+ assertThat(infos.getActionList().size()).isEqualTo(5);
}
@Test
- public void accessibilityActionMove_moveTopLeft_success() {
+ public void accessibilityActionMove_halfOval_moveTopLeft_success() {
final AccessibilityFloatingMenuView menuView =
spy(new AccessibilityFloatingMenuView(mContext));
doReturn(mAvailableBounds).when(menuView).getAvailableBounds();
+ menuView.setShapeType(/* halfOvalShape */ 1);
final boolean isActionPerformed =
menuView.performAccessibilityAction(R.id.action_move_top_left, null);
assertThat(isActionPerformed).isTrue();
+ assertThat(menuView.mShapeType).isEqualTo(/* ovalShape */ 0);
verify(menuView).snapToLocation(mAvailableBounds.left, mAvailableBounds.top);
}
@Test
- public void accessibilityActionMove_moveTopRight_success() {
+ public void accessibilityActionMove_halfOval_moveTopRight_success() {
final AccessibilityFloatingMenuView menuView =
spy(new AccessibilityFloatingMenuView(mContext));
doReturn(mAvailableBounds).when(menuView).getAvailableBounds();
+ menuView.setShapeType(/* halfOvalShape */ 1);
final boolean isActionPerformed =
menuView.performAccessibilityAction(R.id.action_move_top_right, null);
assertThat(isActionPerformed).isTrue();
+ assertThat(menuView.mShapeType).isEqualTo(/* ovalShape */ 0);
verify(menuView).snapToLocation(mAvailableBounds.right, mAvailableBounds.top);
}
@Test
- public void accessibilityActionMove_moveBottomLeft_success() {
+ public void accessibilityActionMove_halfOval_moveBottomLeft_success() {
final AccessibilityFloatingMenuView menuView =
spy(new AccessibilityFloatingMenuView(mContext));
doReturn(mAvailableBounds).when(menuView).getAvailableBounds();
+ menuView.setShapeType(/* halfOvalShape */ 1);
final boolean isActionPerformed =
menuView.performAccessibilityAction(R.id.action_move_bottom_left, null);
assertThat(isActionPerformed).isTrue();
+ assertThat(menuView.mShapeType).isEqualTo(/* ovalShape */ 0);
verify(menuView).snapToLocation(mAvailableBounds.left, mAvailableBounds.bottom);
}
@Test
- public void accessibilityActionMove_moveBottomRight_success() {
+ public void accessibilityActionMove_halfOval_moveBottomRight_success() {
final AccessibilityFloatingMenuView menuView =
spy(new AccessibilityFloatingMenuView(mContext));
doReturn(mAvailableBounds).when(menuView).getAvailableBounds();
+ menuView.setShapeType(/* halfOvalShape */ 1);
final boolean isActionPerformed =
menuView.performAccessibilityAction(R.id.action_move_bottom_right, null);
assertThat(isActionPerformed).isTrue();
+ assertThat(menuView.mShapeType).isEqualTo(/* ovalShape */ 0);
verify(menuView).snapToLocation(mAvailableBounds.right, mAvailableBounds.bottom);
}
+ @Test
+ public void accessibilityActionMove_halfOval_moveOutEdgeAndShow_success() {
+ final AccessibilityFloatingMenuView menuView =
+ spy(new AccessibilityFloatingMenuView(mContext));
+ doReturn(mAvailableBounds).when(menuView).getAvailableBounds();
+ menuView.setShapeType(/* halfOvalShape */ 1);
+
+ final boolean isActionPerformed =
+ menuView.performAccessibilityAction(R.id.action_move_out_edge_and_show, null);
+
+ assertThat(isActionPerformed).isTrue();
+ assertThat(menuView.mShapeType).isEqualTo(/* ovalShape */ 0);
+ }
+
+ @Test
+ public void setupAccessibilityActions_oval_hasActionMoveToEdgeAndHide() {
+ final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext);
+ menuView.setShapeType(/* ovalShape */ 0);
+
+ final AccessibilityNodeInfo infos = new AccessibilityNodeInfo();
+ menuView.onInitializeAccessibilityNodeInfo(infos);
+
+ assertThat(infos.getActionList().stream().anyMatch(
+ action -> action.getId() == R.id.action_move_to_edge_and_hide)).isTrue();
+ }
+
@After
public void tearDown() {
mInterceptMotionEvent = null;
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 1f165bb..923cae8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -180,6 +180,17 @@
}
@Test
+ public void testIsFalseTap_EmptyRecentEvents() {
+ // Ensure we look at prior events if recent events has already been emptied.
+ when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(new ArrayList<>());
+ when(mFalsingDataProvider.getPriorMotionEvents()).thenReturn(mMotionEventList);
+
+ mBrightLineFalsingManager.isFalseTap(false, 0);
+ verify(mSingleTapClassfier).isTap(mMotionEventList);
+ }
+
+
+ @Test
public void testIsFalseTap_RobustCheck_NoFaceAuth() {
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 96eb4b0..e88c728 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -2,7 +2,6 @@
import android.app.Notification.MediaStyle
import android.app.PendingIntent
-import android.app.smartspace.SmartspaceTarget
import android.graphics.Bitmap
import android.media.MediaDescription
import android.media.MediaMetadata
@@ -40,8 +39,6 @@
private const val KEY = "KEY"
private const val KEY_2 = "KEY_2"
-private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
-private const val KEY_NONE_MEDIA_SMARTSPACE = "NONE_MEDIA_SMARTSPACE_ID"
private const val PACKAGE_NAME = "com.android.systemui"
private const val APP_NAME = "SystemUI"
private const val SESSION_ARTIST = "artist"
@@ -75,8 +72,6 @@
@Mock lateinit var listener: MediaDataManager.Listener
@Mock lateinit var pendingIntent: PendingIntent
@Mock lateinit var activityStarter: ActivityStarter
- lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
- @Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
lateinit var mediaDataManager: MediaDataManager
lateinit var mediaNotification: StatusBarNotification
@Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
@@ -85,7 +80,6 @@
fun setup() {
foregroundExecutor = FakeExecutor(FakeSystemClock())
backgroundExecutor = FakeExecutor(FakeSystemClock())
- smartspaceMediaDataProvider = SmartspaceMediaDataProvider()
mediaDataManager = MediaDataManager(
context = context,
backgroundExecutor = backgroundExecutor,
@@ -100,7 +94,6 @@
mediaDataCombineLatest = mediaDataCombineLatest,
mediaDataFilter = mediaDataFilter,
activityStarter = activityStarter,
- smartspaceMediaDataProvider = smartspaceMediaDataProvider,
useMediaResumption = true,
useQsMediaPlayer = true
)
@@ -124,9 +117,6 @@
// mock, it doesn't pass those events along the chain to the external listeners. So, just
// treat mediaSessionBasedFilter as a listener for testing.
listener = mediaSessionBasedFilter
-
- whenever(mediaSmartspaceTarget.smartspaceTargetId).thenReturn(KEY_MEDIA_SMARTSPACE)
- whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
}
@After
@@ -330,24 +320,4 @@
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor))
}
-
- @Test
- fun testOnSmartspaceMediaDataLoaded_hasNewMediaTarget_callsListener() {
- smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
- verify(listener).onSmartspaceMediaDataLoaded(
- eq(KEY_MEDIA_SMARTSPACE), eq(mediaSmartspaceTarget))
- }
-
- @Test
- fun testOnSmartspaceMediaDataLoaded_hasNoneMediaTarget_notCallsListener() {
- smartspaceMediaDataProvider.onTargetsAvailable(listOf())
- verify(listener, never()).onSmartspaceMediaDataLoaded(anyObject(), anyObject())
- }
-
- @Test
- fun testOnSmartspaceMediaDataLoaded_hasNoneMediaTarget_callsRemoveListener() {
- smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
- smartspaceMediaDataProvider.onTargetsAvailable(listOf())
- verify(listener).onSmartspaceMediaDataRemoved(KEY_MEDIA_SMARTSPACE)
- }
}
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/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..0f9ca7b 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
@@ -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/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/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/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/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..ac042a7 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;
@@ -2935,6 +2936,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 +2955,7 @@
synchronized(this) {
mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId,
- message, force);
+ message, force, exceptionTypeId);
}
}
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/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index ef43bc5..262cb36 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -259,6 +259,21 @@
this.confirmationRequested = confirmationRequested;
}
+ private Pair<BiometricSensor, Integer> calculateErrorByPriority() {
+ // If the caller requested STRONG, and the device contains both STRONG and non-STRONG
+ // sensors, prioritize BIOMETRIC_NOT_ENROLLED over the weak sensor's
+ // BIOMETRIC_INSUFFICIENT_STRENGTH error. Pretty sure we can always prioritize
+ // BIOMETRIC_NOT_ENROLLED over any other error (unless of course its calculation is
+ // wrong, in which case we should fix that instead).
+ for (Pair<BiometricSensor, Integer> pair : ineligibleSensors) {
+ if (pair.second == BIOMETRIC_NOT_ENROLLED) {
+ return pair;
+ }
+ }
+
+ return ineligibleSensors.get(0);
+ }
+
/**
* With {@link PreAuthInfo} generated with the requested authenticators from the public API
* surface, combined with the actual sensor/credential and user/system settings, calculate the
@@ -281,8 +296,9 @@
} else {
// Pick the first sensor error if it exists
if (!ineligibleSensors.isEmpty()) {
- modality |= ineligibleSensors.get(0).first.modality;
- status = ineligibleSensors.get(0).second;
+ final Pair<BiometricSensor, Integer> pair = calculateErrorByPriority();
+ modality |= pair.first.modality;
+ status = pair.second;
} else {
modality |= TYPE_CREDENTIAL;
status = CREDENTIAL_NOT_ENROLLED;
@@ -297,8 +313,9 @@
} else {
// Pick the first sensor error if it exists
if (!ineligibleSensors.isEmpty()) {
- modality |= ineligibleSensors.get(0).first.modality;
- status = ineligibleSensors.get(0).second;
+ final Pair<BiometricSensor, Integer> pair = calculateErrorByPriority();
+ modality |= pair.first.modality;
+ status = pair.second;
} else {
modality |= TYPE_NONE;
status = BIOMETRIC_NO_HARDWARE;
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/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/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/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4eafe51..a6d4ed9 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;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2dcc8d9..30ce57f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12271,19 +12271,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 +21455,8 @@
synchronized (mLock) {
if (outInfo != null) {
outInfo.uid = ps.appId;
+ outInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(ps,
+ allUserHandles, mSettings.getPackagesLocked());
}
}
@@ -23464,10 +23465,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/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d13babc..01a46b3 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1949,7 +1949,7 @@
boolean addStartingWindow(String pkg, int resolvedTheme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated) {
+ boolean allowTaskSnapshot, boolean activityCreated, boolean samePackage) {
// If the display is frozen, we won't do anything until the actual window is
// displayed so there is no reason to put in the starting window.
if (!okToDisplay()) {
@@ -1971,7 +1971,7 @@
false /* restoreFromDisk */, false /* isLowResolution */);
final int typeParameter = mWmService.mStartingSurfaceController
.makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning,
- allowTaskSnapshot, activityCreated);
+ allowTaskSnapshot, activityCreated, samePackage);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, snapshot);
@@ -6141,11 +6141,11 @@
void showStartingWindow(boolean taskSwitch) {
showStartingWindow(null /* prev */, false /* newTask */, taskSwitch,
- 0 /* splashScreenTheme */);
+ 0 /* splashScreenTheme */, true /* samePackage */);
}
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
- int splashScreenTheme) {
+ int splashScreenTheme, boolean samePackage) {
if (mTaskOverlay) {
// We don't show starting window for overlay activities.
return;
@@ -6165,7 +6165,8 @@
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
- mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal());
+ mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
+ samePackage);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 0efadcf..aa1f42e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1769,9 +1769,17 @@
mRootWindowContainer.startPowerModeLaunchIfNeeded(
false /* forceSend */, mStartActivity);
+ final boolean startFromSamePackage;
+ if (sourceRecord != null && sourceRecord.mActivityComponent != null) {
+ startFromSamePackage = mStartActivity.mActivityComponent
+ .getPackageName().equals(sourceRecord.mActivityComponent.getPackageName());
+ } else {
+ startFromSamePackage = false;
+ }
+
mTargetRootTask.startActivityLocked(mStartActivity,
topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
- mKeepCurTransition, mOptions);
+ mKeepCurTransition, mOptions, startFromSamePackage);
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index 0708569..140ae3e 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -20,6 +20,7 @@
import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_SAME_PACKAGE;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -66,7 +67,8 @@
}
int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch,
- boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated) {
+ boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated,
+ boolean samePackage) {
int parameter = 0;
if (newTask) {
parameter |= TYPE_PARAMETER_NEW_TASK;
@@ -83,6 +85,9 @@
if (activityCreated) {
parameter |= TYPE_PARAMETER_ACTIVITY_CREATED;
}
+ if (samePackage) {
+ parameter |= TYPE_PARAMETER_SAME_PACKAGE;
+ }
return parameter;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b36c25c..c293a15 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -6525,7 +6525,8 @@
}
void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity,
- boolean newTask, boolean keepCurTransition, ActivityOptions options) {
+ boolean newTask, boolean keepCurTransition, ActivityOptions options,
+ boolean samePackage) {
Task rTask = r.getTask();
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
final boolean isOrhasTask = rTask == this || hasChild(rTask);
@@ -6647,7 +6648,7 @@
final int splashScreenThemeResId = options != null
? options.getSplashScreenThemeResId() : 0;
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity),
- splashScreenThemeResId);
+ splashScreenThemeResId, samePackage);
}
} else {
// If this is the first activity, don't do any fancy animations,
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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index fbf677d..9b2a1e7 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.
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/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/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/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index ab9aa26..124f6dd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2349,7 +2349,7 @@
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false);
+ false, false);
waitUntilHandlersIdle();
assertHasStartingWindow(activity);
activity.removeStartingWindow();
@@ -2365,7 +2365,7 @@
for (int i = 0; i < 1000; i++) {
appToken.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false);
+ false, false);
appToken.removeStartingWindow();
waitUntilHandlersIdle();
assertNoStartingWindow(appToken);
@@ -2379,11 +2379,11 @@
final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false);
+ false, false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
- true, true, false, true, false);
+ true, true, false, true, false, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -2400,11 +2400,11 @@
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0,
activity1.appToken.asBinder(), true, true, false,
- true, false);
+ true, false, false);
});
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false);
+ false, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -2417,11 +2417,11 @@
final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false);
+ false, false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
- true, true, false, true, false);
+ true, true, false, true, false, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -2443,20 +2443,21 @@
"Test", 0 /* labelRes */, 0 /* icon */, 0 /* logo */, 0 /* windowFlags */,
null /* transferFrom */, true /* newTask */, true /* taskSwitch */,
false /* processRunning */, false /* allowTaskSnapshot */,
- false /* activityCreate */);
+ false /* activityCreate */, false /* samePackage */);
waitUntilHandlersIdle();
assertHasStartingWindow(activity);
activity.mStartingWindowState = ActivityRecord.STARTING_WINDOW_SHOWN;
doCallRealMethod().when(task).startActivityLocked(
- any(), any(), anyBoolean(), anyBoolean(), any());
+ any(), any(), anyBoolean(), anyBoolean(), any(), anyBoolean());
// In normal case, resumeFocusedTasksTopActivities() should be called after
// startActivityLocked(). So skip resumeFocusedTasksTopActivities() in ActivityBuilder.
doReturn(false).when(mRootWindowContainer).resumeFocusedTasksTopActivities();
// Make mVisibleSetFromTransferredStartingWindow true.
final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build();
task.startActivityLocked(middle, null /* focusedTopActivity */,
- false /* newTask */, false /* keepCurTransition */, null /* options */);
+ false /* newTask */, false /* keepCurTransition */, null /* options */,
+ false /* samePackage */);
middle.makeFinishingLocked();
assertNull(activity.mStartingWindow);
@@ -2468,7 +2469,8 @@
top.setVisible(false);
// The finishing middle should be able to transfer starting window to top.
task.startActivityLocked(top, null /* focusedTopActivity */,
- false /* newTask */, false /* keepCurTransition */, null /* options */);
+ false /* newTask */, false /* keepCurTransition */, null /* options */,
+ false /* samePackage */);
assertNull(middle.mStartingWindow);
assertHasStartingWindow(top);
@@ -2488,7 +2490,7 @@
task.positionChildAt(topActivity, POSITION_TOP);
activity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false);
+ false, false);
waitUntilHandlersIdle();
// Make activities to have different rotation from it display and set fixed rotation
@@ -2505,7 +2507,7 @@
// on activity2.
topActivity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity.appToken.asBinder(),
- false, false, false, true, false);
+ false, false, false, true, false, false);
waitUntilHandlersIdle();
assertTrue(topActivity.hasFixedRotationTransform());
}
@@ -2521,7 +2523,7 @@
// Add a starting window.
activityTop.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false);
+ false, false);
waitUntilHandlersIdle();
// Make the top one invisible, and try transferring the starting window from the top to the
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index e9e0c99..39fdb2d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1138,7 +1138,7 @@
spyOn(rootTask);
}
doNothing().when(rootTask).startActivityLocked(
- any(), any(), anyBoolean(), anyBoolean(), any());
+ any(), any(), anyBoolean(), anyBoolean(), any(), anyBoolean());
// Create child task with activity.
if (mCreateActivity) {
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/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/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 793d103..d8ac082 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -3493,8 +3493,8 @@
* @param subscriptionId the unique Subscription ID in database
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
- public void setDeviceToDeviceStatusSharingPreference(
- @DeviceToDeviceStatusSharingPreference int sharing, int subscriptionId) {
+ public void setDeviceToDeviceStatusSharingPreference(int subscriptionId,
+ @DeviceToDeviceStatusSharingPreference int sharing) {
if (VDBG) {
logd("[setDeviceToDeviceStatusSharing] + sharing: " + sharing + " subId: "
+ subscriptionId);
@@ -3525,8 +3525,8 @@
* @param subscriptionId The unique Subscription ID in database
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
- public void setDeviceToDeviceStatusSharingContacts(@NonNull List<Uri> contacts,
- int subscriptionId) {
+ public void setDeviceToDeviceStatusSharingContacts(int subscriptionId,
+ @NonNull List<Uri> contacts) {
String contactString = serializeUriLists(contacts);
if (VDBG) {
logd("[setDeviceToDeviceStatusSharingContacts] + contacts: " + contactString
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/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index a133ead..acfa133 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -282,20 +282,6 @@
* <p>
* Note: this is only populated if {@link #getCapabilityMechanism} is
* {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
- * @hide
- */
- public @NonNull List<String> getOptionsFeatureTags() {
- if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
- return Collections.emptyList();
- }
- return Collections.unmodifiableList(new ArrayList<>(mFeatureTags));
- }
-
- /**
- * @return The feature tags present in the OPTIONS response from the network.
- * <p>
- * Note: this is only populated if {@link #getCapabilityMechanism} is
- * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
*/
public @NonNull Set<String> getFeatureTags() {
if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
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/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index a117adc..57616d35 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -441,30 +441,6 @@
* @param contactUri The URI of the remote user that we wish to get the capabilities of.
* @param myCapabilities The capabilities of this device to send to the remote user.
* @param callback The callback of this request which is sent from the remote user.
- * @hide
- */
- // executor used is defined in the constructor.
- @SuppressLint("ExecutorRegistration")
- public void sendOptionsCapabilityRequest(@NonNull Uri contactUri,
- @NonNull List<String> myCapabilities, @NonNull OptionsResponseCallback callback) {
- // Stub - to be implemented by service
- Log.w(LOG_TAG, "sendOptionsCapabilityRequest called with no implementation.");
- try {
- callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
- } catch (ImsException e) {
- // Do not do anything, this is a stub implementation.
- }
- }
-
- /**
- * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
- * in order to receive the capabilities of the remote user in response.
- * <p>
- * The implementer must use {@link OptionsResponseCallback} to send the response of
- * this query from the network back to the framework.
- * @param contactUri The URI of the remote user that we wish to get the capabilities of.
- * @param myCapabilities The capabilities of this device to send to the remote user.
- * @param callback The callback of this request which is sent from the remote user.
*/
// executor used is defined in the constructor.
@SuppressLint("ExecutorRegistration")
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