Merge "Use a SLEEP transition to trigger failsafe animation cancelling" into udc-dev
diff --git a/OWNERS b/OWNERS
index 7bea58b..dad8bfe 100644
--- a/OWNERS
+++ b/OWNERS
@@ -30,6 +30,7 @@
# Support bulk translation updates
per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
+per-file **.bp,**.mk = hansson@google.com
per-file *.bp = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
per-file Android.mk = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
per-file framework-jarjar-rules.txt = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 79a2659..5de1172 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -5277,6 +5277,8 @@
pw.print(" mScreenLocked="); pw.println(mScreenLocked);
pw.print(" mNetworkConnected="); pw.println(mNetworkConnected);
pw.print(" mCharging="); pw.println(mCharging);
+ pw.print(" activeEmergencyCall=");
+ pw.println(mEmergencyCallListener.isEmergencyCallActive());
if (mConstraints.size() != 0) {
pw.println(" mConstraints={");
for (int i = 0; i < mConstraints.size(); i++) {
diff --git a/core/api/current.txt b/core/api/current.txt
index 53dcd75..ac63513 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10333,7 +10333,7 @@
field public static final int BIND_AUTO_CREATE = 1; // 0x1
field public static final int BIND_DEBUG_UNBIND = 2; // 0x2
field public static final int BIND_EXTERNAL_SERVICE = -2147483648; // 0x80000000
- field public static final long BIND_EXTERNAL_SERVICE_LONG = -9223372036854775808L; // 0x8000000000000000L
+ field public static final long BIND_EXTERNAL_SERVICE_LONG = 4611686018427387904L; // 0x4000000000000000L
field public static final int BIND_IMPORTANT = 64; // 0x40
field public static final int BIND_INCLUDE_CAPABILITIES = 4096; // 0x1000
field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
@@ -10441,7 +10441,6 @@
}
public static final class Context.BindServiceFlags {
- method public long getValue();
method @NonNull public static android.content.Context.BindServiceFlags of(long);
}
@@ -39766,6 +39765,7 @@
method @NonNull public android.service.autofill.Dataset.Builder setAuthentication(@Nullable android.content.IntentSender);
method @NonNull public android.service.autofill.Dataset.Builder setField(@NonNull android.view.autofill.AutofillId, @Nullable android.service.autofill.Field);
method @NonNull public android.service.autofill.Dataset.Builder setField(@NonNull String, @NonNull android.service.autofill.Field);
+ method @NonNull public android.service.autofill.Dataset.Builder setFieldForAllHints(@NonNull android.service.autofill.Field);
method @NonNull public android.service.autofill.Dataset.Builder setId(@Nullable String);
method @Deprecated @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation);
method @Deprecated @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation);
@@ -40549,7 +40549,7 @@
method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder addCreateEntry(@NonNull android.service.credentials.CreateEntry);
method @NonNull public android.service.credentials.BeginCreateCredentialResponse build();
method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setCreateEntries(@NonNull java.util.List<android.service.credentials.CreateEntry>);
- method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setRemoteCreateEntry(@Nullable android.service.credentials.RemoteEntry);
+ method @NonNull @RequiresPermission("android.permission.PROVIDE_REMOTE_CREDENTIALS") public android.service.credentials.BeginCreateCredentialResponse.Builder setRemoteCreateEntry(@Nullable android.service.credentials.RemoteEntry);
}
public class BeginGetCredentialOption implements android.os.Parcelable {
@@ -40598,7 +40598,7 @@
method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setActions(@NonNull java.util.List<android.service.credentials.Action>);
method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setAuthenticationActions(@NonNull java.util.List<android.service.credentials.Action>);
method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setCredentialEntries(@NonNull java.util.List<android.service.credentials.CredentialEntry>);
- method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setRemoteCredentialEntry(@Nullable android.service.credentials.RemoteEntry);
+ method @NonNull @RequiresPermission("android.permission.PROVIDE_REMOTE_CREDENTIALS") public android.service.credentials.BeginGetCredentialResponse.Builder setRemoteCredentialEntry(@Nullable android.service.credentials.RemoteEntry);
}
public final class CallingAppInfo implements android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 05f31a5..a8a48b7 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -254,7 +254,7 @@
field public static final String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
field public static final String POWER_SAVER = "android.permission.POWER_SAVER";
field public static final String PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE = "android.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE";
- field public static final String PROVIDE_HYBRID_CREDENTIAL_SERVICE = "android.permission.PROVIDE_HYBRID_CREDENTIAL_SERVICE";
+ field public static final String PROVIDE_REMOTE_CREDENTIALS = "android.permission.PROVIDE_REMOTE_CREDENTIALS";
field public static final String PROVIDE_RESOLVER_RANKER_SERVICE = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE";
field public static final String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
field public static final String PROVISION_DEMO_DEVICE = "android.permission.PROVISION_DEMO_DEVICE";
@@ -3362,7 +3362,7 @@
}
public static final class VirtualSensorConfig.Builder {
- ctor public VirtualSensorConfig.Builder(int, @NonNull String);
+ ctor public VirtualSensorConfig.Builder(@IntRange(from=1) int, @NonNull String);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig build();
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setDirectChannelTypesSupported(int);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setHighestDirectReportRateLevel(int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 777faa7..a9ae225 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2629,8 +2629,13 @@
method @Nullable public android.content.IntentSender getAuthentication();
method @Nullable public java.util.ArrayList<java.lang.String> getAutofillDatatypes();
method @Nullable public android.content.ClipData getFieldContent();
+ method @Nullable public android.widget.RemoteViews getFieldDialogPresentation(int);
method @Nullable public java.util.ArrayList<android.view.autofill.AutofillId> getFieldIds();
+ method @Nullable public android.service.autofill.InlinePresentation getFieldInlinePresentation(int);
+ method @Nullable public android.service.autofill.InlinePresentation getFieldInlineTooltipPresentation(int);
+ method @Nullable public android.widget.RemoteViews getFieldPresentation(int);
method @Nullable public java.util.ArrayList<android.view.autofill.AutofillValue> getFieldValues();
+ method @Nullable public android.service.autofill.Dataset.DatasetFieldFilter getFilter(int);
method @Nullable public String getId();
method public boolean isEmpty();
}
@@ -2639,6 +2644,13 @@
method @NonNull public android.service.autofill.Dataset.Builder setContent(@NonNull android.view.autofill.AutofillId, @Nullable android.content.ClipData);
}
+ public static final class Dataset.DatasetFieldFilter implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public java.util.regex.Pattern getPattern();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.Dataset.DatasetFieldFilter> CREATOR;
+ }
+
public final class DateTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public void apply(@NonNull android.service.autofill.ValueFinder, @NonNull android.widget.RemoteViews, int) throws java.lang.Exception;
}
@@ -3419,6 +3431,7 @@
}
public final class AutofillManager {
+ field public static final String ANY_HINT = "any";
field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
index ffbdff8..401e754 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
@@ -17,6 +17,7 @@
package android.companion.virtual.sensor;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -167,7 +168,10 @@
* @param name The name of the sensor. Must be unique among all sensors with the same type
* that belong to the same virtual device.
*/
- public Builder(int type, @NonNull String name) {
+ public Builder(@IntRange(from = 1) int type, @NonNull String name) {
+ if (type <= 0) {
+ throw new IllegalArgumentException("Virtual sensor type must be positive");
+ }
mType = type;
mName = Objects.requireNonNull(name);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a412560..36f7ff5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -316,10 +316,12 @@
BIND_ALLOW_ACTIVITY_STARTS,
BIND_INCLUDE_CAPABILITIES,
BIND_SHARED_ISOLATED_PROCESS,
- // Intentionally not included, because it'd cause sign-extension.
+ // Intentionally not include BIND_EXTERNAL_SERVICE, because it'd cause sign-extension.
// This would allow Android Studio to show a warning, if someone tries to use
// BIND_EXTERNAL_SERVICE BindServiceFlags.
- BIND_EXTERNAL_SERVICE_LONG
+ BIND_EXTERNAL_SERVICE_LONG,
+ // Make sure no flag uses the sign bit (most significant bit) of the long integer,
+ // to avoid future confusion.
})
@Retention(RetentionPolicy.SOURCE)
public @interface BindServiceFlagsLongBits {}
@@ -338,6 +340,7 @@
/**
* @return Return flags in 64 bits long integer.
+ * @hide
*/
public long getValue() {
return mValue;
@@ -678,13 +681,11 @@
*/
public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
-
/**
* Works in the same way as {@link #BIND_EXTERNAL_SERVICE}, but it's defined as a (@code long)
* value that is compatible to {@link BindServiceFlags}.
*/
- public static final long BIND_EXTERNAL_SERVICE_LONG = 0x8000_0000_0000_0000L;
-
+ public static final long BIND_EXTERNAL_SERVICE_LONG = 1L << 62;
/**
* These bind flags reduce the strength of the binding such that we shouldn't
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index e2af9b0..b749d69 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -420,6 +420,7 @@
// Guarded by NfcAdapter.class
static boolean sIsInitialized = false;
static boolean sHasNfcFeature;
+ static boolean sHasCeFeature;
// Final after first constructor, except for
// attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
@@ -616,11 +617,13 @@
PackageManager pm;
pm = context.getPackageManager();
sHasNfcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC);
- boolean hasHceFeature =
+ sHasCeFeature =
pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
- || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF);
+ || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)
+ || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)
+ || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE);
/* is this device meant to have NFC */
- if (!sHasNfcFeature && !hasHceFeature) {
+ if (!sHasNfcFeature && !sHasCeFeature) {
Log.v(TAG, "this device does not have NFC support");
throw new UnsupportedOperationException();
}
@@ -643,7 +646,7 @@
throw new UnsupportedOperationException();
}
}
- if (hasHceFeature) {
+ if (sHasCeFeature) {
try {
sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
} catch (RemoteException e) {
@@ -1669,7 +1672,7 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean enableSecureNfc(boolean enable) {
- if (!sHasNfcFeature) {
+ if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
try {
@@ -1694,10 +1697,13 @@
* Checks if the device supports Secure NFC functionality.
*
* @return True if device supports Secure NFC, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @throws UnsupportedOperationException if FEATURE_NFC,
+ * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+ * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+ * are unavailable
*/
public boolean isSecureNfcSupported() {
- if (!sHasNfcFeature) {
+ if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
try {
@@ -1723,11 +1729,14 @@
* such as their relative positioning on the device.
*
* @return Information on the nfc antenna(s) on the device.
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @throws UnsupportedOperationException if FEATURE_NFC,
+ * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+ * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+ * are unavailable
*/
@Nullable
public NfcAntennaInfo getNfcAntennaInfo() {
- if (!sHasNfcFeature) {
+ if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
try {
@@ -1752,12 +1761,15 @@
* Checks Secure NFC feature is enabled.
*
* @return True if Secure NFC is enabled, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @throws UnsupportedOperationException if FEATURE_NFC,
+ * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+ * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+ * are unavailable
* @throws UnsupportedOperationException if device doesn't support
* Secure NFC functionality. {@link #isSecureNfcSupported}
*/
public boolean isSecureNfcEnabled() {
- if (!sHasNfcFeature) {
+ if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
try {
@@ -2071,14 +2083,17 @@
* 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.
+ * @throws UnsupportedOperationException if FEATURE_NFC,
+ * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+ * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+ * are unavailable
* @return void
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
public boolean setControllerAlwaysOn(boolean value) {
- if (!sHasNfcFeature) {
+ if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
try {
@@ -2103,7 +2118,10 @@
* Checks NFC controller always on feature is enabled.
*
* @return True if NFC controller always on is enabled, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @throws UnsupportedOperationException if FEATURE_NFC,
+ * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+ * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+ * are unavailable
* @hide
*/
@SystemApi
@@ -2131,13 +2149,16 @@
* Checks if the device supports NFC controller always on functionality.
*
* @return True if device supports NFC controller always on, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @throws UnsupportedOperationException if FEATURE_NFC,
+ * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+ * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+ * are unavailable
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
public boolean isControllerAlwaysOnSupported() {
- if (!sHasNfcFeature) {
+ if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
try {
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index d943bf9..0ef8bb64 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -29,6 +29,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.widget.RemoteViews;
@@ -283,24 +284,28 @@
}
/** @hide */
- public RemoteViews getFieldPresentation(int index) {
+ @TestApi
+ public @Nullable RemoteViews getFieldPresentation(int index) {
final RemoteViews customPresentation = mFieldPresentations.get(index);
return customPresentation != null ? customPresentation : mPresentation;
}
/** @hide */
- public RemoteViews getFieldDialogPresentation(int index) {
+ @TestApi
+ public @Nullable RemoteViews getFieldDialogPresentation(int index) {
final RemoteViews customPresentation = mFieldDialogPresentations.get(index);
return customPresentation != null ? customPresentation : mDialogPresentation;
}
/** @hide */
+ @TestApi
public @Nullable InlinePresentation getFieldInlinePresentation(int index) {
final InlinePresentation inlinePresentation = mFieldInlinePresentations.get(index);
return inlinePresentation != null ? inlinePresentation : mInlinePresentation;
}
/** @hide */
+ @TestApi
public @Nullable InlinePresentation getFieldInlineTooltipPresentation(int index) {
final InlinePresentation inlineTooltipPresentation =
mFieldInlineTooltipPresentations.get(index);
@@ -309,6 +314,7 @@
}
/** @hide */
+ @TestApi
public @Nullable DatasetFieldFilter getFilter(int index) {
return mFieldFilters.get(index);
}
@@ -389,6 +395,9 @@
if (mAuthentication != null) {
builder.append(", hasAuthentication");
}
+ if (mAutofillDatatypes != null) {
+ builder.append(", autofillDatatypes=").append(mAutofillDatatypes);
+ }
return builder.append(']').toString();
}
@@ -1090,8 +1099,7 @@
*
* @return this builder.
*/
- public @NonNull Dataset.Builder setField(
- @NonNull String hint, @NonNull Field field) {
+ public @NonNull Dataset.Builder setField(@NonNull String hint, @NonNull Field field) {
throwIfDestroyed();
final DatasetFieldFilter filter = field.getDatasetFieldFilter();
@@ -1111,6 +1119,23 @@
}
/**
+ * Adds a field to this Dataset that is relevant to all applicable hints. This is used to
+ * provide field information when autofill with platform detections is enabled.
+ * Platform detections are on when receiving a populated list from
+ * FillRequest#getHints().
+ *
+ * @param field the fill information about the field.
+ *
+ * @throws IllegalStateException if {@link #build()} was already called
+ * or this builder also contains AutofillId information
+ *
+ * @return this builder.
+ */
+ public @NonNull Dataset.Builder setFieldForAllHints(@NonNull Field field) {
+ return setField(AutofillManager.ANY_HINT, field);
+ }
+
+ /**
* Sets the value of a field with an <a href="#Filtering">explicit filter</a>, and using an
* {@link InlinePresentation} to visualize it as an inline suggestion.
*
@@ -1304,7 +1329,7 @@
parcel.createTypedArrayList(InlinePresentation.CREATOR);
final ArrayList<DatasetFieldFilter> filters =
parcel.createTypedArrayList(DatasetFieldFilter.CREATOR);
- final ArrayList<String> datatypes =
+ final ArrayList<String> autofillDatatypes =
parcel.createStringArrayList();
final ClipData fieldContent = parcel.readParcelable(null,
android.content.ClipData.class);
@@ -1341,9 +1366,9 @@
}
final int inlinePresentationsSize = inlinePresentations.size();
- if (ids.size() == 0 && datatypes.size() > 0) {
- for (int i = 0; i < ids.size(); i++) {
- final String datatype = datatypes.get(i);
+ if (ids.size() == 0 && autofillDatatypes.size() > 0) {
+ for (int i = 0; i < autofillDatatypes.size(); i++) {
+ final String datatype = autofillDatatypes.get(i);
final AutofillValue value = values.get(i);
final RemoteViews fieldPresentation = presentations.get(i);
final RemoteViews fieldDialogPresentation = dialogPresentations.get(i);
@@ -1393,8 +1418,10 @@
*
* @hide
*/
+ @TestApi
public static final class DatasetFieldFilter implements Parcelable {
+ /** @hide */
@Nullable
public final Pattern pattern;
@@ -1402,6 +1429,10 @@
this.pattern = pattern;
}
+ public @Nullable Pattern getPattern() {
+ return pattern;
+ }
+
@Override
public String toString() {
if (!sDebug) return super.toString();
@@ -1416,7 +1447,7 @@
}
@Override
- public void writeToParcel(Parcel parcel, int flags) {
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeSerializable(pattern);
}
diff --git a/core/java/android/service/credentials/BeginCreateCredentialResponse.java b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
index eebd31c..cd53cb6 100644
--- a/core/java/android/service/credentials/BeginCreateCredentialResponse.java
+++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
@@ -16,8 +16,10 @@
package android.service.credentials;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.os.Parcel;
import android.os.Parcelable;
@@ -137,7 +139,17 @@
* result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the
* {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESPONSE} key should be populated
* with a {@link android.credentials.CreateCredentialResponse} object.
+ *
+ * <p> Note that as a provider service you will only be able to set a remote entry if :
+ * - Provider service possesses the
+ * {@link Manifest.permission.PROVIDE_REMOTE_CREDENTIALS} permission.
+ * - Provider service is configured as the provider that can provide remote entries.
+ *
+ * If the above conditions are not met, setting back {@link BeginCreateCredentialResponse}
+ * on the callback from {@link CredentialProviderService#onBeginCreateCredential}
+ * will throw a {@link SecurityException}.
*/
+ @RequiresPermission(Manifest.permission.PROVIDE_REMOTE_CREDENTIALS)
public @NonNull Builder setRemoteCreateEntry(@Nullable RemoteEntry remoteCreateEntry) {
mRemoteCreateEntry = remoteCreateEntry;
return this;
diff --git a/core/java/android/service/credentials/BeginGetCredentialResponse.java b/core/java/android/service/credentials/BeginGetCredentialResponse.java
index 97f5079..e25b686 100644
--- a/core/java/android/service/credentials/BeginGetCredentialResponse.java
+++ b/core/java/android/service/credentials/BeginGetCredentialResponse.java
@@ -16,8 +16,10 @@
package android.service.credentials;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.os.Parcel;
import android.os.Parcelable;
@@ -154,7 +156,17 @@
* result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the
* {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE} key should be populated
* with a {@link android.credentials.Credential} object.
+ *
+ * <p> Note that as a provider service you will only be able to set a remote entry if :
+ * - Provider service possesses the
+ * {@link Manifest.permission.PROVIDE_REMOTE_CREDENTIALS} permission.
+ * - Provider service is configured as the provider that can provide remote entries.
+ *
+ * If the above conditions are not met, setting back {@link BeginGetCredentialResponse}
+ * on the callback from {@link CredentialProviderService#onBeginGetCredential} will
+ * throw a {@link SecurityException}.
*/
+ @RequiresPermission(Manifest.permission.PROVIDE_REMOTE_CREDENTIALS)
public @NonNull Builder setRemoteCredentialEntry(@Nullable RemoteEntry
remoteCredentialEntry) {
mRemoteCredentialEntry = remoteCredentialEntry;
diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java
index d737f6b..e88474d 100644
--- a/core/java/android/service/credentials/CredentialProviderService.java
+++ b/core/java/android/service/credentials/CredentialProviderService.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import android.Manifest;
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
@@ -218,6 +219,11 @@
GetCredentialException>() {
@Override
public void onResult(BeginGetCredentialResponse result) {
+ // If provider service does not possess the HYBRID permission, this
+ // check will throw an exception in the provider process.
+ if (result.getRemoteCredentialEntry() != null) {
+ enforceRemoteEntryPermission();
+ }
try {
callback.onSuccess(result);
} catch (RemoteException e) {
@@ -236,6 +242,15 @@
));
return transport;
}
+ private void enforceRemoteEntryPermission() {
+ String permission =
+ Manifest.permission.PROVIDE_REMOTE_CREDENTIALS;
+ getApplicationContext().enforceCallingOrSelfPermission(
+ permission,
+ String.format("Provider must have %s, in order to set a "
+ + "remote entry", permission)
+ );
+ }
@Override
public ICancellationSignal onBeginCreateCredential(BeginCreateCredentialRequest request,
@@ -253,6 +268,11 @@
BeginCreateCredentialResponse, CreateCredentialException>() {
@Override
public void onResult(BeginCreateCredentialResponse result) {
+ // If provider service does not possess the HYBRID permission, this
+ // check will throw an exception in the provider process.
+ if (result.getRemoteCreateEntry() != null) {
+ enforceRemoteEntryPermission();
+ }
try {
callback.onSuccess(result);
} catch (RemoteException e) {
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 07ac597..b4675e0 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -81,7 +81,10 @@
// GC'd while the native peer of the receiver is using them.
private MessageQueue mMessageQueue;
+ private final VsyncEventData mVsyncEventData = new VsyncEventData();
+
private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
+ WeakReference<VsyncEventData> vsyncEventData,
MessageQueue messageQueue, int vsyncSource, int eventRegistration, long layerHandle);
private static native long nativeGetDisplayEventReceiverFinalizer();
@FastNative
@@ -124,7 +127,9 @@
}
mMessageQueue = looper.getQueue();
- mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
+ mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this),
+ new WeakReference<VsyncEventData>(mVsyncEventData),
+ mMessageQueue,
vsyncSource, eventRegistration, layerHandle);
mFreeNativeResources = sNativeAllocationRegistry.registerNativeAllocation(this,
mReceiverPtr);
@@ -142,9 +147,6 @@
}
static final class VsyncEventData {
-
- static final FrameTimeline[] INVALID_FRAME_TIMELINES =
- {new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)};
// The amount of frame timeline choices.
// Must be in sync with VsyncEventData::kFrameTimelinesLength in
// frameworks/native/libs/gui/include/gui/VsyncEventData.h. If they do not match, a runtime
@@ -152,6 +154,10 @@
static final int FRAME_TIMELINES_LENGTH = 7;
public static class FrameTimeline {
+ FrameTimeline() {}
+
+ // Called from native code.
+ @SuppressWarnings("unused")
FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline) {
this.vsyncId = vsyncId;
this.expectedPresentationTime = expectedPresentationTime;
@@ -160,14 +166,14 @@
// The frame timeline vsync id, used to correlate a frame
// produced by HWUI with the timeline data stored in Surface Flinger.
- public final long vsyncId;
+ public long vsyncId = FrameInfo.INVALID_VSYNC_ID;
// The frame timestamp for when the frame is expected to be presented.
- public final long expectedPresentationTime;
+ public long expectedPresentationTime = Long.MAX_VALUE;
// The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
// allotted for the frame to be completed.
- public final long deadline;
+ public long deadline = Long.MAX_VALUE;
}
/**
@@ -175,11 +181,18 @@
* {@link FrameInfo#VSYNC} to the current vsync in case Choreographer callback was heavily
* delayed by the app.
*/
- public final long frameInterval;
+ public long frameInterval = -1;
public final FrameTimeline[] frameTimelines;
- public final int preferredFrameTimelineIndex;
+ public int preferredFrameTimelineIndex = 0;
+
+ VsyncEventData() {
+ frameTimelines = new FrameTimeline[FRAME_TIMELINES_LENGTH];
+ for (int i = 0; i < frameTimelines.length; i++) {
+ frameTimelines[i] = new FrameTimeline();
+ }
+ }
// Called from native code.
@SuppressWarnings("unused")
@@ -190,12 +203,6 @@
this.frameInterval = frameInterval;
}
- VsyncEventData() {
- this.frameInterval = -1;
- this.frameTimelines = INVALID_FRAME_TIMELINES;
- this.preferredFrameTimelineIndex = 0;
- }
-
public FrameTimeline preferredFrameTimeline() {
return frameTimelines[preferredFrameTimelineIndex];
}
@@ -299,9 +306,8 @@
// Called from native code.
@SuppressWarnings("unused")
- private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
- VsyncEventData vsyncEventData) {
- onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData);
+ private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
+ onVsync(timestampNanos, physicalDisplayId, frame, mVsyncEventData);
}
// Called from native code.
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a208cb3..21fe87f 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -823,6 +823,11 @@
/** @hide */
public final void destroy() {
mDestroyed = true;
+ onDestroy();
+ }
+
+ /** @hide */
+ protected void onDestroy() {
}
/** @hide */
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index aef0e65..ab9f492 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -301,6 +301,14 @@
public static final String EXTRA_AUGMENTED_AUTOFILL_CLIENT =
"android.view.autofill.extra.AUGMENTED_AUTOFILL_CLIENT";
+ /**
+ * Autofill Hint to indicate that it can match any field.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String ANY_HINT = "any";
+
private static final String SESSION_ID_TAG = "android:sessionId";
private static final String STATE_TAG = "android:state";
private static final String LAST_AUTOFILLED_DATA_TAG = "android:lastAutoFilledData";
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index c41b822..9b9e010 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -295,6 +295,7 @@
private boolean mClosingActionMenu;
private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
+ private int mAudioMode = AudioManager.MODE_NORMAL;
private MediaController mMediaController;
private AudioManager mAudioManager;
@@ -317,6 +318,8 @@
}
};
+ private AudioManager.OnModeChangedListener mOnModeChangedListener;
+
private Transition mEnterTransition = null;
private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
private Transition mExitTransition = null;
@@ -1944,7 +1947,7 @@
case KeyEvent.KEYCODE_VOLUME_MUTE: {
// If we have a session and no active phone call send it the volume command,
// otherwise use the suggested stream.
- if (mMediaController != null && !isActivePhoneCallKnown()) {
+ if (mMediaController != null && !isActivePhoneCallOngoing()) {
getMediaSessionManager().dispatchVolumeKeyEventToSessionAsSystemService(event,
mMediaController.getSessionToken());
} else {
@@ -1995,16 +1998,9 @@
return false;
}
- private boolean isActivePhoneCallKnown() {
- boolean isActivePhoneCallKnown = false;
- AudioManager audioManager =
- (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
- int audioManagerMode = audioManager.getMode();
- if (audioManagerMode == AudioManager.MODE_IN_CALL
- || audioManagerMode == AudioManager.MODE_IN_COMMUNICATION) {
- isActivePhoneCallKnown = true;
- }
- return isActivePhoneCallKnown;
+ private boolean isActivePhoneCallOngoing() {
+ return mAudioMode == AudioManager.MODE_IN_CALL
+ || mAudioMode == AudioManager.MODE_IN_COMMUNICATION;
}
private KeyguardManager getKeyguardManager() {
@@ -2331,6 +2327,14 @@
}
}
+ @Override
+ protected void onDestroy() {
+ if (mOnModeChangedListener != null) {
+ getAudioManager().removeOnModeChangedListener(mOnModeChangedListener);
+ mOnModeChangedListener = null;
+ }
+ }
+
private class PanelMenuPresenterCallback implements MenuPresenter.Callback {
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
@@ -3229,6 +3233,15 @@
@Override
public void setMediaController(MediaController controller) {
mMediaController = controller;
+ if (controller != null && mOnModeChangedListener == null) {
+ mAudioMode = getAudioManager().getMode();
+ mOnModeChangedListener = mode -> mAudioMode = mode;
+ getAudioManager().addOnModeChangedListener(getContext().getMainExecutor(),
+ mOnModeChangedListener);
+ } else if (mOnModeChangedListener != null) {
+ getAudioManager().removeOnModeChangedListener(mOnModeChangedListener);
+ mOnModeChangedListener = null;
+ }
}
@Override
diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
index f2b0544..abe6c7c 100644
--- a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
@@ -72,11 +72,13 @@
private static final String TAG = "ProtoLog";
private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
static final String PROTOLOG_VERSION = "1.0.0";
+ private static final int DEFAULT_PER_CHUNK_SIZE = 0;
private final File mLogFile;
private final String mViewerConfigFilename;
private final TraceBuffer mBuffer;
protected final ProtoLogViewerConfigReader mViewerConfig;
+ private final int mPerChunkSize;
private boolean mProtoLogEnabled;
private boolean mProtoLogEnabledLockFree;
@@ -160,7 +162,7 @@
return;
}
try {
- ProtoOutputStream os = new ProtoOutputStream();
+ ProtoOutputStream os = new ProtoOutputStream(mPerChunkSize);
long token = os.start(LOG);
os.write(MESSAGE_HASH, messageHash);
os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
@@ -219,10 +221,16 @@
public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
ProtoLogViewerConfigReader viewerConfig) {
+ this(file, viewerConfigFilename, bufferCapacity, viewerConfig, DEFAULT_PER_CHUNK_SIZE);
+ }
+
+ public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
+ ProtoLogViewerConfigReader viewerConfig, int perChunkSize) {
mLogFile = file;
mBuffer = new TraceBuffer(bufferCapacity);
mViewerConfigFilename = viewerConfigFilename;
mViewerConfig = viewerConfig;
+ mPerChunkSize = perChunkSize;
}
/**
@@ -368,7 +376,7 @@
try {
long offset =
(System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000));
- ProtoOutputStream proto = new ProtoOutputStream();
+ ProtoOutputStream proto = new ProtoOutputStream(mPerChunkSize);
proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
proto.write(VERSION, PROTOLOG_VERSION);
proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset);
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 353c6c0..527cfdd 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -30,6 +30,7 @@
private static final int BUFFER_CAPACITY = 1024 * 1024;
private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope";
private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
+ private static final int PER_CHUNK_SIZE = 1024;
private static ProtoLogImpl sServiceInstance = null;
@@ -94,7 +95,10 @@
public static synchronized ProtoLogImpl getSingleInstance() {
if (sServiceInstance == null) {
sServiceInstance = new ProtoLogImpl(
- new File(LOG_FILENAME), BUFFER_CAPACITY, new ProtoLogViewerConfigReader());
+ new File(LOG_FILENAME)
+ , BUFFER_CAPACITY
+ , new ProtoLogViewerConfigReader()
+ , PER_CHUNK_SIZE);
}
return sServiceInstance;
}
@@ -105,8 +109,8 @@
}
public ProtoLogImpl(File logFile, int bufferCapacity,
- ProtoLogViewerConfigReader viewConfigReader) {
- super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader);
- }
+ ProtoLogViewerConfigReader viewConfigReader, int perChunkSize) {
+ super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader, perChunkSize);
+ }
}
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index b09a9c3..739055e 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -50,12 +50,22 @@
struct {
jclass clazz;
+
jmethodID init;
+
+ jfieldID vsyncId;
+ jfieldID expectedPresentationTime;
+ jfieldID deadline;
} frameTimelineClassInfo;
struct {
jclass clazz;
+
jmethodID init;
+
+ jfieldID frameInterval;
+ jfieldID preferredFrameTimelineIndex;
+ jfieldID frameTimelines;
} vsyncEventDataClassInfo;
} gDisplayEventReceiverClassInfo;
@@ -63,7 +73,7 @@
class NativeDisplayEventReceiver : public DisplayEventDispatcher {
public:
- NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
+ NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, jobject vsyncEventDataWeak,
const sp<MessageQueue>& messageQueue, jint vsyncSource,
jint eventRegistration, jlong layerHandle);
@@ -74,6 +84,7 @@
private:
jobject mReceiverWeakGlobal;
+ jobject mVsyncEventDataWeakGlobal;
sp<MessageQueue> mMessageQueue;
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
@@ -87,6 +98,7 @@
};
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
+ jobject vsyncEventDataWeak,
const sp<MessageQueue>& messageQueue,
jint vsyncSource, jint eventRegistration,
jlong layerHandle)
@@ -98,6 +110,7 @@
reinterpret_cast<IBinder*>(layerHandle))
: nullptr),
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
+ mVsyncEventDataWeakGlobal(env->NewGlobalRef(vsyncEventDataWeak)),
mMessageQueue(messageQueue) {
ALOGV("receiver %p ~ Initializing display event receiver.", this);
}
@@ -144,12 +157,39 @@
JNIEnv* env = AndroidRuntime::getJNIEnv();
ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
- if (receiverObj.get()) {
+ ScopedLocalRef<jobject> vsyncEventDataObj(env, GetReferent(env, mVsyncEventDataWeakGlobal));
+ if (receiverObj.get() && vsyncEventDataObj.get()) {
ALOGV("receiver %p ~ Invoking vsync handler.", this);
- jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData);
+ env->SetIntField(vsyncEventDataObj.get(),
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo
+ .preferredFrameTimelineIndex,
+ vsyncEventData.preferredFrameTimelineIndex);
+ env->SetLongField(vsyncEventDataObj.get(),
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval,
+ vsyncEventData.frameInterval);
+
+ jobjectArray frameTimelinesObj = reinterpret_cast<jobjectArray>(
+ env->GetObjectField(vsyncEventDataObj.get(),
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo
+ .frameTimelines));
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ VsyncEventData::FrameTimeline& frameTimeline = vsyncEventData.frameTimelines[i];
+ jobject frameTimelineObj = env->GetObjectArrayElement(frameTimelinesObj, i);
+ env->SetLongField(frameTimelineObj,
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId,
+ frameTimeline.vsyncId);
+ env->SetLongField(frameTimelineObj,
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo
+ .expectedPresentationTime,
+ frameTimeline.expectedPresentationTime);
+ env->SetLongField(frameTimelineObj,
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline,
+ frameTimeline.deadlineTimestamp);
+ }
+
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
- timestamp, displayId.value, count, javaVsyncEventData);
+ timestamp, displayId.value, count);
ALOGV("receiver %p ~ Returned from vsync handler.", this);
}
@@ -217,8 +257,9 @@
mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
}
-static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
- jint vsyncSource, jint eventRegistration, jlong layerHandle) {
+static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject vsyncEventDataWeak,
+ jobject messageQueueObj, jint vsyncSource, jint eventRegistration,
+ jlong layerHandle) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
@@ -226,8 +267,8 @@
}
sp<NativeDisplayEventReceiver> receiver =
- new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
- eventRegistration, layerHandle);
+ new NativeDisplayEventReceiver(env, receiverWeak, vsyncEventDataWeak, messageQueue,
+ vsyncSource, eventRegistration, layerHandle);
status_t status = receiver->initialize();
if (status) {
String8 message;
@@ -274,7 +315,9 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- {"nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;IIJ)J",
+ {"nativeInit",
+ "(Ljava/lang/ref/WeakReference;Ljava/lang/ref/WeakReference;Landroid/os/"
+ "MessageQueue;IIJ)J",
(void*)nativeInit},
{"nativeGetDisplayEventReceiverFinalizer", "()J",
(void*)nativeGetDisplayEventReceiverFinalizer},
@@ -291,8 +334,7 @@
gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gDisplayEventReceiverClassInfo.dispatchVsync =
- GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync",
- "(JJILandroid/view/DisplayEventReceiver$VsyncEventData;)V");
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V");
gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
gDisplayEventReceiverClassInfo.dispatchModeChanged =
@@ -318,6 +360,15 @@
gDisplayEventReceiverClassInfo.frameTimelineClassInfo.init =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
"<init>", "(JJJ)V");
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId =
+ GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
+ "vsyncId", "J");
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo.expectedPresentationTime =
+ GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
+ "expectedPresentationTime", "J");
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline =
+ GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
+ "deadline", "J");
jclass vsyncEventDataClazz =
FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData");
@@ -329,6 +380,17 @@
"([Landroid/view/"
"DisplayEventReceiver$VsyncEventData$FrameTimeline;IJ)V");
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.preferredFrameTimelineIndex =
+ GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
+ "preferredFrameTimelineIndex", "I");
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval =
+ GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
+ "frameInterval", "J");
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelines =
+ GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
+ "frameTimelines",
+ "[Landroid/view/DisplayEventReceiver$VsyncEventData$FrameTimeline;");
+
return res;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b736230..5a0ac0f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4482,8 +4482,8 @@
<!-- Allows an application to be able to store and retrieve credentials from a remote
device.
@hide @SystemApi -->
- <permission android:name="android.permission.PROVIDE_HYBRID_CREDENTIAL_SERVICE"
- android:protectionLevel="signature|privileged" />
+ <permission android:name="android.permission.PROVIDE_REMOTE_CREDENTIALS"
+ android:protectionLevel="signature|privileged|role" />
<!-- ========================================= -->
<!-- Permissions for special development tools -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 47d771f..07f3530 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4746,8 +4746,7 @@
<string name="accessibility_shortcut_disabling_service">Held volume keys. <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> turned off.</string>
<!-- Text spoken when accessibility shortcut warning dialog is shown. [CHAR LIMIT=none] -->
- <string name="accessibility_shortcut_spoken_feedback">Press and hold both volume keys for three seconds to use
- <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g></string>
+ <string name="accessibility_shortcut_spoken_feedback">Release the volume keys. To turn on <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g>, press and hold both volume keys again for 3 seconds.</string>
<!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. [CHAR LIMIT=none]-->
<string name="accessibility_button_prompt_text">Choose a feature to use when you tap the accessibility button:</string>
diff --git a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
index 16ed3ef..17b064c 100644
--- a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
+++ b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
@@ -26,6 +26,7 @@
import static org.testng.Assert.assertThrows;
+import android.hardware.Sensor;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -67,6 +68,24 @@
}
@Test
+ public void virtualSensorConfig_invalidName_throwsException() {
+ assertThrows(
+ NullPointerException.class,
+ () -> new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, null));
+ }
+
+ @Test
+ public void virtualSensorConfig_invalidType_throwsException() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new VirtualSensorConfig.Builder(Sensor.TYPE_ALL, SENSOR_NAME));
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new VirtualSensorConfig.Builder(0, SENSOR_NAME));
+ }
+
+ @Test
public void hardwareBufferDirectChannelTypeSupported_throwsException() {
assertThrows(
IllegalArgumentException.class,
diff --git a/core/tests/coretests/src/android/provider/NameValueCacheTest.java b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
index b6fc137..ccf8085 100644
--- a/core/tests/coretests/src/android/provider/NameValueCacheTest.java
+++ b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
@@ -91,7 +91,7 @@
mConfigsCacheGenerationStore = new MemoryIntArray(2);
mConfigsCacheGenerationStore.set(0, 123);
mConfigsCacheGenerationStore.set(1, 456);
- mSettingsCacheGenerationStore = new MemoryIntArray(2);
+ mSettingsCacheGenerationStore = new MemoryIntArray(3);
mSettingsCacheGenerationStore.set(0, 234);
mSettingsCacheGenerationStore.set(1, 567);
mConfigsStorage = new HashMap<>();
@@ -163,6 +163,10 @@
Bundle incomingBundle = invocationOnMock.getArgument(4);
String key = invocationOnMock.getArgument(3);
String value = incomingBundle.getString(Settings.NameValueTable.VALUE);
+ boolean newSetting = false;
+ if (!mSettingsStorage.containsKey(key)) {
+ newSetting = true;
+ }
mSettingsStorage.put(key, value);
int currentGeneration;
// Different settings have different generation codes
@@ -173,12 +177,18 @@
currentGeneration = mSettingsCacheGenerationStore.get(1);
mSettingsCacheGenerationStore.set(1, ++currentGeneration);
}
+ if (newSetting) {
+ // Tracking the generation of all unset settings.
+ // Increment when a new setting is inserted
+ currentGeneration = mSettingsCacheGenerationStore.get(2);
+ mSettingsCacheGenerationStore.set(2, ++currentGeneration);
+ }
return null;
});
// Returns the value corresponding to a setting, or null if the setting
- // doesn't have a value stored for it. Returns the generation key if the value isn't null
- // and the caller asked for the generation key.
+ // doesn't have a value stored for it. Returns the generation key
+ // if the caller asked for the generation key.
when(mMockIContentProvider.call(any(), eq(Settings.Secure.CONTENT_URI.getAuthority()),
eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class))).thenAnswer(
invocationOnMock -> {
@@ -189,9 +199,15 @@
Bundle bundle = new Bundle();
bundle.putSerializable(Settings.NameValueTable.VALUE, value);
- if (value != null && incomingBundle.containsKey(
+ if (incomingBundle.containsKey(
Settings.CALL_METHOD_TRACK_GENERATION_KEY)) {
- int index = key.equals(SETTING) ? 0 : 1;
+ int index;
+ if (value != null) {
+ index = key.equals(SETTING) ? 0 : 1;
+ } else {
+ // special index for unset settings
+ index = 2;
+ }
bundle.putParcelable(Settings.CALL_METHOD_TRACK_GENERATION_KEY,
mSettingsCacheGenerationStore);
bundle.putInt(Settings.CALL_METHOD_GENERATION_INDEX_KEY, index);
@@ -361,16 +377,38 @@
}
@Test
- public void testCaching_nullSetting() throws Exception {
+ public void testCaching_unsetSetting() throws Exception {
String returnedValue = Settings.Secure.getString(mMockContentResolver, SETTING);
verify(mMockIContentProvider, times(1)).call(any(), any(),
eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class));
assertThat(returnedValue).isNull();
String cachedValue = Settings.Secure.getString(mMockContentResolver, SETTING);
- // Empty list won't be cached
+ // The first unset setting's generation number is cached
+ verifyNoMoreInteractions(mMockIContentProvider);
+ assertThat(cachedValue).isNull();
+
+ String returnedValue2 = Settings.Secure.getString(mMockContentResolver, SETTING2);
verify(mMockIContentProvider, times(2)).call(any(), any(),
eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class));
- assertThat(cachedValue).isNull();
+ assertThat(returnedValue2).isNull();
+
+ String cachedValue2 = Settings.Secure.getString(mMockContentResolver, SETTING);
+ // The second unset setting's generation number is cached
+ verifyNoMoreInteractions(mMockIContentProvider);
+ assertThat(cachedValue2).isNull();
+
+ Settings.Secure.putString(mMockContentResolver, SETTING, "a");
+ // The generation for unset settings should have changed
+ returnedValue2 = Settings.Secure.getString(mMockContentResolver, SETTING2);
+ verify(mMockIContentProvider, times(3)).call(any(), any(),
+ eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class));
+ assertThat(returnedValue2).isNull();
+
+ // The generation tracker for the first setting should have change because it's set now
+ returnedValue = Settings.Secure.getString(mMockContentResolver, SETTING);
+ verify(mMockIContentProvider, times(4)).call(any(), any(),
+ eq(Settings.CALL_METHOD_GET_SECURE), any(), any(Bundle.class));
+ assertThat(returnedValue).isEqualTo("a");
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 36c0cb6..852fae6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -61,6 +61,7 @@
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.NotificationListenerService;
@@ -129,6 +130,15 @@
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
+ // TODO(b/256873975) Should use proper flag when available to shell/launcher
+ /**
+ * Whether bubbles are showing in the bubble bar from launcher. This is only available
+ * on large screens and {@link BubbleController#isShowingAsBubbleBar()} should be used
+ * to check all conditions that indicate if the bubble bar is in use.
+ */
+ private static final boolean BUBBLE_BAR_ENABLED =
+ SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
+
private final Context mContext;
private final BubblesImpl mImpl = new BubblesImpl();
private Bubbles.BubbleExpandListener mExpandListener;
@@ -155,9 +165,6 @@
private final ShellExecutor mBackgroundExecutor;
- // Whether or not we should show bubbles pinned at the bottom of the screen.
- private boolean mIsBubbleBarEnabled;
-
private BubbleLogger mLogger;
private BubbleData mBubbleData;
@Nullable private BubbleStackView mStackView;
@@ -540,10 +547,10 @@
mDataRepository.removeBubblesForUser(removedUserId, parentUserId);
}
- // TODO(b/256873975): Should pass this into the constructor once flags are available to shell.
- /** Sets whether the bubble bar is enabled (i.e. bubbles pinned to bottom on large screens). */
- public void setBubbleBarEnabled(boolean enabled) {
- mIsBubbleBarEnabled = enabled;
+ /** Whether bubbles are showing in the bubble bar. */
+ public boolean isShowingAsBubbleBar() {
+ // TODO(b/269670598): should also check that we're in gesture nav
+ return BUBBLE_BAR_ENABLED && mBubblePositioner.isLargeScreen();
}
/** Whether this userId belongs to the current user. */
@@ -612,12 +619,6 @@
mStackView.setUnbubbleConversationCallback(mSysuiProxy::onUnbubbleConversation);
}
- if (mIsBubbleBarEnabled && mBubblePositioner.isLargeScreen()) {
- mBubblePositioner.setUsePinnedLocation(true);
- } else {
- mBubblePositioner.setUsePinnedLocation(false);
- }
-
addToWindowManagerMaybe();
}
@@ -1918,13 +1919,6 @@
}
@Override
- public void setBubbleBarEnabled(boolean enabled) {
- mMainExecutor.execute(() -> {
- BubbleController.this.setBubbleBarEnabled(enabled);
- });
- }
-
- @Override
public void onNotificationPanelExpandedChanged(boolean expanded) {
mMainExecutor.execute(
() -> BubbleController.this.onNotificationPanelExpandedChanged(expanded));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 6230d22..3fd0967 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -283,7 +283,7 @@
}
boolean isShowingOverflow() {
- return mShowingOverflow && (isExpanded() || mPositioner.showingInTaskbar());
+ return mShowingOverflow && isExpanded();
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 07c5852..5ea2450 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -18,9 +18,6 @@
import static android.view.View.LAYOUT_DIRECTION_RTL;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -39,8 +36,6 @@
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.R;
-import java.lang.annotation.Retention;
-
/**
* Keeps track of display size, configuration, and specific bubble sizes. One place for all
* placement and positioning calculations to refer to.
@@ -50,15 +45,6 @@
? "BubblePositioner"
: BubbleDebugConfig.TAG_BUBBLES;
- @Retention(SOURCE)
- @IntDef({TASKBAR_POSITION_NONE, TASKBAR_POSITION_RIGHT, TASKBAR_POSITION_LEFT,
- TASKBAR_POSITION_BOTTOM})
- @interface TaskbarPosition {}
- public static final int TASKBAR_POSITION_NONE = -1;
- public static final int TASKBAR_POSITION_RIGHT = 0;
- public static final int TASKBAR_POSITION_LEFT = 1;
- public static final int TASKBAR_POSITION_BOTTOM = 2;
-
/** When the bubbles are collapsed in a stack only some of them are shown, this is how many. **/
public static final int NUM_VISIBLE_WHEN_RESTING = 2;
/** Indicates a bubble's height should be the maximum available space. **/
@@ -108,15 +94,9 @@
private int mOverflowHeight;
private int mMinimumFlyoutWidthLargeScreen;
- private PointF mPinLocation;
private PointF mRestingStackPosition;
private int[] mPaddings = new int[4];
- private boolean mShowingInTaskbar;
- private @TaskbarPosition int mTaskbarPosition = TASKBAR_POSITION_NONE;
- private int mTaskbarIconSize;
- private int mTaskbarSize;
-
public BubblePositioner(Context context, WindowManager windowManager) {
mContext = context;
mWindowManager = windowManager;
@@ -153,27 +133,11 @@
+ " insets: " + insets
+ " isLargeScreen: " + mIsLargeScreen
+ " isSmallTablet: " + mIsSmallTablet
- + " bounds: " + bounds
- + " showingInTaskbar: " + mShowingInTaskbar);
+ + " bounds: " + bounds);
}
updateInternal(mRotation, insets, bounds);
}
- /**
- * Updates position information to account for taskbar state.
- *
- * @param taskbarPosition which position the taskbar is displayed in.
- * @param showingInTaskbar whether the taskbar is being shown.
- */
- public void updateForTaskbar(int iconSize,
- @TaskbarPosition int taskbarPosition, boolean showingInTaskbar, int taskbarSize) {
- mShowingInTaskbar = showingInTaskbar;
- mTaskbarIconSize = iconSize;
- mTaskbarPosition = taskbarPosition;
- mTaskbarSize = taskbarSize;
- update();
- }
-
@VisibleForTesting
public void updateInternal(int rotation, Insets insets, Rect bounds) {
mRotation = rotation;
@@ -232,10 +196,6 @@
R.dimen.bubbles_flyout_min_width_large_screen);
mMaxBubbles = calculateMaxBubbles();
-
- if (mShowingInTaskbar) {
- adjustForTaskbar();
- }
}
/**
@@ -260,30 +220,6 @@
return mDefaultMaxBubbles;
}
- /**
- * Taskbar insets appear as navigationBar insets, however, unlike navigationBar this should
- * not inset bubbles UI as bubbles floats above the taskbar. This adjust the available space
- * and insets to account for the taskbar.
- */
- // TODO(b/171559950): When the insets are reported correctly we can remove this logic
- private void adjustForTaskbar() {
- // When bar is showing on edges... subtract that inset because we appear on top
- if (mShowingInTaskbar && mTaskbarPosition != TASKBAR_POSITION_BOTTOM) {
- WindowInsets metricInsets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
- Insets navBarInsets = metricInsets.getInsetsIgnoringVisibility(
- WindowInsets.Type.navigationBars());
- int newInsetLeft = mInsets.left;
- int newInsetRight = mInsets.right;
- if (mTaskbarPosition == TASKBAR_POSITION_LEFT) {
- mPositionRect.left -= navBarInsets.left;
- newInsetLeft -= navBarInsets.left;
- } else if (mTaskbarPosition == TASKBAR_POSITION_RIGHT) {
- mPositionRect.right += navBarInsets.right;
- newInsetRight -= navBarInsets.right;
- }
- mInsets = Insets.of(newInsetLeft, mInsets.top, newInsetRight, mInsets.bottom);
- }
- }
/**
* @return a rect of available screen space accounting for orientation, system bars and cutouts.
@@ -327,14 +263,12 @@
* to the left or right side.
*/
public boolean showBubblesVertically() {
- return isLandscape() || mShowingInTaskbar || mIsLargeScreen;
+ return isLandscape() || mIsLargeScreen;
}
/** Size of the bubble. */
public int getBubbleSize() {
- return (mShowingInTaskbar && mTaskbarIconSize > 0)
- ? mTaskbarIconSize
- : mBubbleSize;
+ return mBubbleSize;
}
/** The amount of padding at the top of the screen that the bubbles avoid when being placed. */
@@ -699,9 +633,6 @@
/** The position the bubble stack should rest at when collapsed. */
public PointF getRestingPosition() {
- if (mPinLocation != null) {
- return mPinLocation;
- }
if (mRestingStackPosition == null) {
return getDefaultStartPosition();
}
@@ -713,9 +644,6 @@
* is being shown.
*/
public PointF getDefaultStartPosition() {
- if (mPinLocation != null) {
- return mPinLocation;
- }
// Start on the left if we're in LTR, right otherwise.
final boolean startOnLeft =
mContext.getResources().getConfiguration().getLayoutDirection()
@@ -730,7 +658,6 @@
1 /* default starts with 1 bubble */));
}
-
/**
* Returns the region that the stack position must stay within. This goes slightly off the left
* and right sides of the screen, below the status bar/cutout and above the navigation bar.
@@ -751,39 +678,6 @@
}
/**
- * @return whether the bubble stack is pinned to the taskbar.
- */
- public boolean showingInTaskbar() {
- return mShowingInTaskbar;
- }
-
- /**
- * @return the taskbar position if set.
- */
- public int getTaskbarPosition() {
- return mTaskbarPosition;
- }
-
- public int getTaskbarSize() {
- return mTaskbarSize;
- }
-
- /**
- * In some situations bubbles will be pinned to a specific onscreen location. This sets whether
- * bubbles should be pinned or not.
- */
- public void setUsePinnedLocation(boolean usePinnedLocation) {
- if (usePinnedLocation) {
- mShowingInTaskbar = true;
- mPinLocation = new PointF(mPositionRect.right - mBubbleSize,
- mPositionRect.bottom - mBubbleSize);
- } else {
- mPinLocation = null;
- mShowingInTaskbar = false;
- }
- }
-
- /**
* Navigation bar has an area where system gestures can be started from.
*
* @return {@link Rect} for system navigation bar gesture zone
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index abe42ee..7d71089e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -680,8 +680,6 @@
// Re-show the expanded view if we hid it.
showExpandedViewIfNeeded();
- } else if (mPositioner.showingInTaskbar()) {
- mStackAnimationController.snapStackBack();
} else {
// Fling the stack to the edge, and save whether or not it's going to end up on
// the left side of the screen.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 1753cda..4c0a93f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -273,11 +273,6 @@
*/
void onUserRemoved(int removedUserId);
- /**
- * Sets whether bubble bar should be enabled or not.
- */
- void setBubbleBarEnabled(boolean enabled);
-
/** Listener to find out about stack expansion / collapse events. */
interface BubbleExpandListener {
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 0ee0ea6..5533842 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -417,23 +417,9 @@
}
/**
- * Snaps the stack back to the previous resting position.
- */
- public void snapStackBack() {
- if (mLayout == null) {
- return;
- }
- PointF p = getStackPositionAlongNearestHorizontalEdge();
- springStackAfterFling(p.x, p.y);
- }
-
- /**
* Where the stack would be if it were snapped to the nearest horizontal edge (left or right).
*/
public PointF getStackPositionAlongNearestHorizontalEdge() {
- if (mPositioner.showingInTaskbar()) {
- return mPositioner.getRestingPosition();
- }
final PointF stackPos = getStackPosition();
final boolean onLeft = mLayout.isFirstChildXLeftOfCenter(stackPos.x);
final RectF bounds = mPositioner.getAllowableStackPositionRegion(getBubbleCount());
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 7e9443b..c39a6db 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -32,6 +32,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.NullPointerException;
import java.util.concurrent.Executor;
/**
@@ -271,7 +272,12 @@
mExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
- mCallback.onFilterStatusChanged(this, status);
+ try {
+ mCallback.onFilterStatusChanged(this, status);
+ }
+ catch (NullPointerException e) {
+ Log.d(TAG, "catch exception:" + e);
+ }
}
}
});
@@ -285,7 +291,12 @@
mExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
- mCallback.onFilterEvent(this, events);
+ try {
+ mCallback.onFilterEvent(this, events);
+ }
+ catch (NullPointerException e) {
+ Log.d(TAG, "catch exception:" + e);
+ }
} else {
for (FilterEvent event : events) {
if (event instanceof MediaEvent) {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt
index 1a3c0ab..47bf85d 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.content.pm.ApplicationInfo
import android.text.format.Formatter
+import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
@@ -30,18 +31,26 @@
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
+private const val TAG = "AppStorageSize"
+
@Composable
fun ApplicationInfo.getStorageSize(): State<String> {
val context = LocalContext.current
return produceState(initialValue = stringResource(R.string.summary_placeholder)) {
withContext(Dispatchers.IO) {
- value = Formatter.formatFileSize(context, calculateSizeBytes(context))
+ val sizeBytes = calculateSizeBytes(context)
+ value = if (sizeBytes != null) Formatter.formatFileSize(context, sizeBytes) else ""
}
}
}
-private fun ApplicationInfo.calculateSizeBytes(context: Context): Long {
+private fun ApplicationInfo.calculateSizeBytes(context: Context): Long? {
val storageStatsManager = context.storageStatsManager
- val stats = storageStatsManager.queryStatsForPackage(storageUuid, packageName, userHandle)
- return stats.codeBytes + stats.dataBytes
+ return try {
+ val stats = storageStatsManager.queryStatsForPackage(storageUuid, packageName, userHandle)
+ stats.codeBytes + stats.dataBytes
+ } catch (e: Exception) {
+ Log.w(TAG, "Failed to query stats: $e")
+ null
+ }
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
index fcacc34..e3af587 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
@@ -20,6 +20,7 @@
import android.app.usage.StorageStatsManager
import android.content.Context
import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager.NameNotFoundException
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.junit4.createComposeRule
@@ -60,9 +61,11 @@
@Before
fun setUp() {
whenever(context.storageStatsManager).thenReturn(storageStatsManager)
- whenever(storageStatsManager.queryStatsForPackage(
- app.storageUuid, app.packageName, app.userHandle
- )).thenReturn(STATS)
+ whenever(
+ storageStatsManager.queryStatsForPackage(
+ app.storageUuid, app.packageName, app.userHandle
+ )
+ ).thenReturn(STATS)
}
@Test
@@ -78,6 +81,24 @@
composeTestRule.waitUntil { storageSize.value == "120 B" }
}
+ @Test
+ fun getStorageSize_throwException() {
+ var storageSize = stateOf("Computing")
+ whenever(
+ storageStatsManager.queryStatsForPackage(
+ app.storageUuid, app.packageName, app.userHandle
+ )
+ ).thenThrow(NameNotFoundException())
+
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) {
+ storageSize = app.getStorageSize()
+ }
+ }
+
+ composeTestRule.waitUntil { storageSize.value == "" }
+ }
+
companion object {
private val STATS = StorageStats().apply {
codeBytes = 100
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
index 7f3b0ff..db6cc1a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
@@ -16,6 +16,7 @@
package com.android.providers.settings;
+import android.annotation.NonNull;
import android.os.Bundle;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -59,6 +60,10 @@
// Maximum size of an individual backing store
static final int MAX_BACKING_STORE_SIZE = MemoryIntArray.getMaxSize();
+ // Use an empty string to track the generation number of all non-predefined, unset settings
+ // The generation number is only increased when a new non-predefined setting is inserted
+ private static final String DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS = "";
+
public GenerationRegistry(Object lock) {
mLock = lock;
}
@@ -72,6 +77,10 @@
(SettingsState.getTypeFromKey(key) == SettingsState.SETTINGS_TYPE_CONFIG);
// Only store the prefix if the mutated setting is a config
final String indexMapKey = isConfig ? (name.split("/")[0] + "/") : name;
+ incrementGenerationInternal(key, indexMapKey);
+ }
+
+ private void incrementGenerationInternal(int key, @NonNull String indexMapKey) {
synchronized (mLock) {
final MemoryIntArray backingStore = getBackingStoreLocked(key,
/* createIfNotExist= */ false);
@@ -87,7 +96,8 @@
final int generation = backingStore.get(index) + 1;
backingStore.set(index, generation);
if (DEBUG) {
- Slog.i(LOG_TAG, "Incremented generation for setting:" + indexMapKey
+ Slog.i(LOG_TAG, "Incremented generation for "
+ + (indexMapKey.isEmpty() ? "unset settings" : "setting:" + indexMapKey)
+ " key:" + SettingsState.keyToString(key)
+ " at index:" + index);
}
@@ -98,6 +108,18 @@
}
}
+ // A new, non-predefined setting has been inserted, increment the tracking number for all unset
+ // settings
+ public void incrementGenerationForUnsetSettings(int key) {
+ final boolean isConfig =
+ (SettingsState.getTypeFromKey(key) == SettingsState.SETTINGS_TYPE_CONFIG);
+ if (isConfig) {
+ // No need to track new settings for configs
+ return;
+ }
+ incrementGenerationInternal(key, DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS);
+ }
+
/**
* Return the backing store's reference, the index and the current generation number
* of a cached setting. If it was not in the backing store, first create the entry in it before
@@ -124,8 +146,8 @@
bundle.putInt(Settings.CALL_METHOD_GENERATION_KEY,
backingStore.get(index));
if (DEBUG) {
- Slog.i(LOG_TAG, "Exported index:" + index
- + " for setting:" + indexMapKey
+ Slog.i(LOG_TAG, "Exported index:" + index + " for "
+ + (indexMapKey.isEmpty() ? "unset settings" : "setting:" + indexMapKey)
+ " key:" + SettingsState.keyToString(key));
}
} catch (IOException e) {
@@ -135,6 +157,10 @@
}
}
+ public void addGenerationDataForUnsetSettings(Bundle bundle, int key) {
+ addGenerationData(bundle, key, /* indexMapKey= */ DEFAULT_MAP_KEY_FOR_UNSET_SETTINGS);
+ }
+
public void onUserRemoved(int userId) {
final int secureKey = SettingsState.makeKey(
SettingsState.SETTINGS_TYPE_SECURE, userId);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ba275eb..418011a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2327,11 +2327,15 @@
result.putString(Settings.NameValueTable.VALUE,
(setting != null && !setting.isNull()) ? setting.getValue() : null);
- if ((setting != null && !setting.isNull()) || isSettingPreDefined(name, type)) {
- // Don't track generation for non-existent settings unless the name is predefined
- synchronized (mLock) {
+ synchronized (mLock) {
+ if ((setting != null && !setting.isNull()) || isSettingPreDefined(name, type)) {
+ // Individual generation tracking for predefined settings even if they are unset
mSettingsRegistry.mGenerationRegistry.addGenerationData(result,
SettingsState.makeKey(type, userId), name);
+ } else {
+ // All non-predefined, unset settings are tracked using the same generation number
+ mSettingsRegistry.mGenerationRegistry.addGenerationDataForUnsetSettings(result,
+ SettingsState.makeKey(type, userId));
}
}
return result;
@@ -2345,7 +2349,8 @@
} else if (type == SETTINGS_TYPE_SYSTEM) {
return sAllSystemSettings.contains(name);
} else {
- return false;
+ // Consider all config settings predefined because they are used by system apps only
+ return type == SETTINGS_TYPE_CONFIG;
}
}
@@ -2354,14 +2359,13 @@
Bundle result = new Bundle();
result.putSerializable(Settings.NameValueTable.VALUE, keyValues);
if (trackingGeneration) {
- // Track generation even if the namespace is empty because this is for system apps
synchronized (mLock) {
+ // Track generation even if namespace is empty because this is for system apps only
mSettingsRegistry.mGenerationRegistry.addGenerationData(result,
- mSettingsRegistry.getSettingsLocked(SETTINGS_TYPE_CONFIG,
- UserHandle.USER_SYSTEM).mKey, prefix);
+ SettingsState.makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM),
+ prefix);
}
}
-
return result;
}
@@ -3052,10 +3056,15 @@
final int key = makeKey(type, userId);
boolean success = false;
+ boolean isNewSetting = false;
SettingsState settingsState = peekSettingsStateLocked(key);
if (settingsState != null) {
+ if (!settingsState.hasSetting(name)) {
+ isNewSetting = true;
+ }
success = settingsState.insertSettingLocked(name, value,
- tag, makeDefault, forceNonSystemPackage, packageName, overrideableByRestore);
+ tag, makeDefault, forceNonSystemPackage, packageName,
+ overrideableByRestore);
}
if (success && criticalSettings != null && criticalSettings.contains(name)) {
@@ -3064,6 +3073,11 @@
if (forceNotify || success) {
notifyForSettingsChange(key, name);
+ if (isNewSetting && !isSettingPreDefined(name, type)) {
+ // Increment the generation number for all null settings because a new
+ // non-predefined setting has been inserted
+ mGenerationRegistry.incrementGenerationForUnsetSettings(key);
+ }
}
if (success) {
logSettingChanged(userId, name, type, CHANGE_TYPE_INSERT);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index c388826..4d8705f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -759,6 +759,12 @@
mPackageToMemoryUsage.put(packageName, newSize);
}
+ public boolean hasSetting(String name) {
+ synchronized (mLock) {
+ return hasSettingLocked(name);
+ }
+ }
+
@GuardedBy("mLock")
private boolean hasSettingLocked(String name) {
return mSettings.indexOfKey(name) >= 0;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java
index d34fe694..6ec8146 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/GenerationRegistryTest.java
@@ -151,6 +151,26 @@
checkBundle(b, 0, 1, false);
}
+ @Test
+ public void testUnsetSettings() throws IOException {
+ final GenerationRegistry generationRegistry = new GenerationRegistry(new Object());
+ final int secureKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_SECURE, 0);
+ final String testSecureSetting = "test_secure_setting";
+ Bundle b = new Bundle();
+ generationRegistry.addGenerationData(b, secureKey, testSecureSetting);
+ checkBundle(b, 0, 1, false);
+ generationRegistry.addGenerationDataForUnsetSettings(b, secureKey);
+ checkBundle(b, 1, 1, false);
+ generationRegistry.addGenerationDataForUnsetSettings(b, secureKey);
+ // Test that unset settings always have the same index
+ checkBundle(b, 1, 1, false);
+ generationRegistry.incrementGenerationForUnsetSettings(secureKey);
+ // Test that the generation number of the unset settings have increased
+ generationRegistry.addGenerationDataForUnsetSettings(b, secureKey);
+ checkBundle(b, 1, 2, false);
+ }
+
+
private void checkBundle(Bundle b, int expectedIndex, int expectedGeneration, boolean isNull)
throws IOException {
final MemoryIntArray array = getArray(b);
diff --git a/packages/SystemUI/animation/.gitignore b/packages/SystemUI/animation/.gitignore
new file mode 100644
index 0000000..f9a33db
--- /dev/null
+++ b/packages/SystemUI/animation/.gitignore
@@ -0,0 +1,9 @@
+.idea/
+.gradle/
+gradle/
+build/
+gradlew*
+local.properties
+*.iml
+android.properties
+buildSrc
\ No newline at end of file
diff --git a/packages/SystemUI/animation/build.gradle b/packages/SystemUI/animation/build.gradle
new file mode 100644
index 0000000..939455f
--- /dev/null
+++ b/packages/SystemUI/animation/build.gradle
@@ -0,0 +1,37 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+
+// TODO: Pull out surfaceeffects outside of src and have separate build files there.
+android {
+ sourceSets {
+ main {
+ java.srcDirs = ["${SYS_UI_DIR}/animation/src/com/android/systemui/surfaceeffects/"]
+ manifest.srcFile "${SYS_UI_DIR}/animation/AndroidManifest.xml"
+ }
+ }
+
+ compileSdk 33
+
+ defaultConfig {
+ minSdk 33
+ targetSdk 33
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+ tasks.lint.enabled = false
+ tasks.withType(JavaCompile) {
+ options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ freeCompilerArgs = ["-Xjvm-default=all"]
+ }
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0"
+ implementation 'androidx.core:core-animation:1.0.0-alpha02'
+ implementation 'androidx.core:core-ktx:1.9.0'
+}
diff --git a/packages/SystemUI/res/drawable/accessibility_window_magnification_background.xml b/packages/SystemUI/res/drawable/accessibility_window_magnification_background.xml
index 58fe368..97bd18e 100644
--- a/packages/SystemUI/res/drawable/accessibility_window_magnification_background.xml
+++ b/packages/SystemUI/res/drawable/accessibility_window_magnification_background.xml
@@ -27,7 +27,7 @@
<shape android:shape="rectangle">
<corners android:radius="@dimen/magnifier_outer_corner_radius" />
<stroke
- android:color="@android:color/black"
+ android:color="@color/magnification_drag_handle_stroke"
android:width="@dimen/magnifier_stroke_width"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background.xml b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background.xml
index a52e805..66617e1 100644
--- a/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background.xml
+++ b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background.xml
@@ -16,7 +16,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
- android:color="@android:color/black"
+ android:color="@color/magnification_drag_handle_stroke"
android:width="@dimen/magnifier_stroke_width"/>
<corners android:radius="@dimen/magnifier_corner_radius" />
<solid android:color="@color/magnification_border_color" />
diff --git a/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_change.xml b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_change.xml
new file mode 100644
index 0000000..e367f50
--- /dev/null
+++ b/packages/SystemUI/res/drawable/accessibility_window_magnification_drag_handle_background_change.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="@color/magnification_border_color"
+ android:width="@dimen/magnifier_stroke_width"/>
+ <corners android:radius="@dimen/magnifier_corner_radius" />
+ <solid android:color="@color/magnification_drag_handle_background_change" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_move_magnification.xml b/packages/SystemUI/res/drawable/ic_move_magnification.xml
index 641bb43..0796007 100644
--- a/packages/SystemUI/res/drawable/ic_move_magnification.xml
+++ b/packages/SystemUI/res/drawable/ic_move_magnification.xml
@@ -20,6 +20,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="@color/magnification_drag_handle_tint"
+ android:fillColor="@color/magnification_drag_handle_stroke"
android:pathData="M12,15Q10.75,15 9.875,14.125Q9,13.25 9,12Q9,10.75 9.875,9.875Q10.75,9 12,9Q13.25,9 14.125,9.875Q15,10.75 15,12Q15,13.25 14.125,14.125Q13.25,15 12,15ZM12,22 L7.75,17.75 9.15,16.35 12,19.15 14.85,16.35 16.25,17.75ZM6.25,16.25 L2,12 6.25,7.75 7.65,9.15 4.85,12 7.65,14.85ZM9.15,7.65 L7.75,6.25 12,2 16.25,6.25 14.85,7.65 12,4.85ZM17.75,16.25 L16.35,14.85 19.15,12 16.35,9.15 17.75,7.75 22,12Z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml
new file mode 100644
index 0000000..de0a620
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <!-- gradient from 25% in the center to 100% at edges -->
+ <gradient
+ android:type="radial"
+ android:gradientRadius="40%p"
+ android:startColor="#AE000000"
+ android:endColor="#00000000" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_recommendation_view.xml b/packages/SystemUI/res/layout/media_recommendation_view.xml
index c54c4e4..a4aeba1 100644
--- a/packages/SystemUI/res/layout/media_recommendation_view.xml
+++ b/packages/SystemUI/res/layout/media_recommendation_view.xml
@@ -22,9 +22,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:translationZ="0dp"
- android:scaleType="centerCrop"
+ android:scaleType="matrix"
android:adjustViewBounds="true"
android:clipToOutline="true"
+ android:layerType="hardware"
android:background="@drawable/bg_smartspace_media_item"/>
<!-- App icon -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index c6cc0bc..d4ebd10 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -163,8 +163,8 @@
<color name="magnification_border_color">#F29900</color>
<color name="magnification_switch_button_color">#7F000000</color>
<color name="magnification_drag_corner_background">#E5FFFFFF</color>
- <color name="magnification_drag_handle_color">#B3000000</color>
- <color name="magnification_drag_handle_tint">#111111</color>
+ <color name="magnification_drag_handle_stroke">#000000</color>
+ <color name="magnification_drag_handle_background_change">#111111</color>
<color name="accessibility_magnifier_bg">#FCFCFC</color>
<color name="accessibility_magnifier_bg_stroke">#E0E0E0</color>
<color name="accessibility_magnifier_icon_color">#252525</color>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 6dd359c..45a5ce3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -18,7 +18,6 @@
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityTaskManager.getService;
import android.annotation.NonNull;
@@ -45,6 +44,7 @@
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
+import android.view.Display;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
@@ -112,6 +112,13 @@
}
/**
+ * @see #getRunningTasks(boolean , int)
+ */
+ public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
+ return getRunningTasks(filterOnlyVisibleRecents, Display.INVALID_DISPLAY);
+ }
+
+ /**
* We ask for {@link #NUM_RECENT_ACTIVITIES_REQUEST} activities because when in split screen,
* we'll get back 2 activities for each split app and one for launcher. Launcher might be more
* "recently" used than one of the split apps so if we only request 2 tasks, then we might miss
@@ -120,10 +127,12 @@
* @return an array of up to {@link #NUM_RECENT_ACTIVITIES_REQUEST} running tasks
* filtering only for tasks that can be visible in the recent tasks list.
*/
- public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
+ public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents,
+ int displayId) {
// Note: The set of running tasks from the system is ordered by recency
List<ActivityManager.RunningTaskInfo> tasks =
- mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, filterOnlyVisibleRecents);
+ mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST,
+ filterOnlyVisibleRecents, /* keepInExtras= */ false, displayId);
return tasks.toArray(new RunningTaskInfo[tasks.size()]);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 21d35c9..30e2a0b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -877,7 +877,10 @@
private void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
mBackgroundExecutor.execute(
- () -> mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId));
+ () -> {
+ mLogger.logReportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+ mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+ });
}
private void handleFingerprintAuthFailed() {
@@ -2530,11 +2533,13 @@
// If this message exists, we should not authenticate again until this message is
// consumed by the handler
if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
+ mLogger.logHandlerHasAuthContinueMsgs(action);
return;
}
// don't start running fingerprint until they're registered
if (!mAuthController.areAllFingerprintAuthenticatorsRegistered()) {
+ mLogger.d("All FP authenticators not registered, skipping FP listening state update");
return;
}
final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported());
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
index bc0bd8c..20f9007 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
@@ -16,6 +16,7 @@
package com.android.keyguard.logging
+import android.hardware.biometrics.BiometricSourceType
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.BiometricLog
import com.android.systemui.plugins.log.LogBuffer
@@ -157,6 +158,36 @@
}
)
}
+
+ fun deferringAuthenticationDueToSleep(
+ userId: Int,
+ biometricSourceType: BiometricSourceType,
+ alreadyPendingAuth: Boolean
+ ) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ str1 = biometricSourceType.name
+ bool2 = alreadyPendingAuth
+ },
+ {
+ "onBiometricAuthenticated, deferring auth: userId: $int1, " +
+ "biometricSourceType: $str1, " +
+ "goingToSleep: true, " +
+ "mPendingAuthentication != null: $bool2"
+ }
+ )
+ }
+
+ fun finishedGoingToSleepWithPendingAuth() {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ "onFinishedGoingToSleep with pendingAuthenticated != null"
+ )
+ }
}
private fun wakeAndUnlockModeToString(mode: Int): String {
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index 379c78a..51aca07 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -16,6 +16,7 @@
package com.android.keyguard.logging
+import com.android.systemui.biometrics.AuthRippleController
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController
import com.android.systemui.log.dagger.KeyguardLog
import com.android.systemui.plugins.log.LogBuffer
@@ -120,4 +121,29 @@
"type=${KeyguardIndicationRotateTextViewController.indicationTypeToString(type)}"
}
}
+
+ fun notShowingUnlockRipple(keyguardNotShowing: Boolean, unlockNotAllowed: Boolean) {
+ buffer.log(
+ AuthRippleController.TAG,
+ LogLevel.DEBUG,
+ {
+ bool1 = keyguardNotShowing
+ bool2 = unlockNotAllowed
+ },
+ { "Not showing unlock ripple: keyguardNotShowing: $bool1, unlockNotAllowed: $bool2" }
+ )
+ }
+
+ fun showingUnlockRippleAt(x: Int, y: Int, context: String) {
+ buffer.log(
+ AuthRippleController.TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = x
+ int2 = y
+ str1 = context
+ },
+ { "Showing unlock ripple with center (x, y): ($int1, $int2), context: $str1" }
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index fb2c02a..2403d11 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -584,6 +584,30 @@
)
}
+ fun logReportSuccessfulBiometricUnlock(isStrongBiometric: Boolean, userId: Int) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = isStrongBiometric
+ int1 = userId
+ },
+ { "reporting successful biometric unlock: isStrongBiometric: $bool1, userId: $int1" }
+ )
+ }
+
+ fun logHandlerHasAuthContinueMsgs(action: Int) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = action },
+ {
+ "MSG_BIOMETRIC_AUTHENTICATION_CONTINUE already queued up, " +
+ "ignoring updating FP listening state to $int1"
+ }
+ )
+ }
+
fun logFaceEnrolledUpdated(oldValue: Boolean, newValue: Boolean) {
logBuffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index d35c77c..d811d30 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -37,6 +37,8 @@
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
@@ -1398,6 +1400,11 @@
mWindowMagnifierCallback.onPerformScaleAction(mDisplayId,
A11Y_ACTION_SCALE_RANGE.clamp(scale));
}
+
+ @Override
+ public void onSettingsPanelVisibilityChanged(boolean shown) {
+ updateDragHandleResourcesIfNeeded(/* settingsPanelIsShown= */ shown);
+ }
};
@Override
@@ -1436,6 +1443,20 @@
}
}
+ private void updateDragHandleResourcesIfNeeded(boolean settingsPanelIsShown) {
+ mDragView.setBackground(mContext.getResources().getDrawable(settingsPanelIsShown
+ ? R.drawable.accessibility_window_magnification_drag_handle_background_change
+ : R.drawable.accessibility_window_magnification_drag_handle_background));
+
+ PorterDuffColorFilter filter = new PorterDuffColorFilter(
+ mContext.getColor(settingsPanelIsShown
+ ? R.color.magnification_border_color
+ : R.color.magnification_drag_handle_stroke),
+ PorterDuff.Mode.SRC_ATOP);
+
+ mDragView.setColorFilter(filter);
+ }
+
private void animateBounceEffect() {
final ObjectAnimator scaleAnimator = ObjectAnimator.ofPropertyValuesHolder(mMirrorView,
PropertyValuesHolder.ofFloat(View.SCALE_X, 1, mBounceEffectAnimationScale, 1),
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index e1f3c6c..9ad64e29 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -323,6 +323,7 @@
}
mContext.unregisterReceiver(mScreenOffReceiver);
+ mCallback.onSettingsPanelVisibilityChanged(/* shown= */ false);
}
public void showSettingPanel() {
@@ -361,6 +362,7 @@
// Exclude magnification switch button from system gesture area.
setSystemGestureExclusion();
mIsVisible = true;
+ mCallback.onSettingsPanelVisibilityChanged(/* shown= */ true);
}
mContext.registerReceiver(mScreenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java
index 22ec650..1d83340 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java
@@ -61,4 +61,11 @@
* 1 : ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, 2 : ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
*/
void onModeSwitch(int newMode);
+
+ /**
+ * Called when the visibility of the magnification settings panel changed.
+ *
+ * @param shown The visibility of the magnification settings panel.
+ */
+ void onSettingsPanelVisibilityChanged(boolean shown);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index d561cd7..93b57dc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -26,6 +26,7 @@
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.keyguard.logging.KeyguardLogger
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
@@ -74,6 +75,7 @@
private val udfpsControllerProvider: Provider<UdfpsController>,
private val statusBarStateController: StatusBarStateController,
private val featureFlags: FeatureFlags,
+ private val logger: KeyguardLogger,
rippleView: AuthRippleView?
) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback,
WakefulnessLifecycle.Observer {
@@ -120,8 +122,11 @@
}
fun showUnlockRipple(biometricSourceType: BiometricSourceType) {
- if (!keyguardStateController.isShowing ||
- !keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(biometricSourceType)) {
+ val keyguardNotShowing = !keyguardStateController.isShowing
+ val unlockNotAllowed = !keyguardUpdateMonitor
+ .isUnlockingWithBiometricAllowed(biometricSourceType)
+ if (keyguardNotShowing || unlockNotAllowed) {
+ logger.notShowingUnlockRipple(keyguardNotShowing, unlockNotAllowed)
return
}
@@ -138,6 +143,7 @@
Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
)
)
+ logger.showingUnlockRippleAt(it.x, it.y, "FP sensor radius: $udfpsRadius")
showUnlockedRipple()
}
} else if (biometricSourceType == BiometricSourceType.FACE) {
@@ -155,6 +161,7 @@
Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
)
)
+ logger.showingUnlockRippleAt(it.x, it.y, "Face unlock ripple")
showUnlockedRipple()
}
}
@@ -391,5 +398,6 @@
companion object {
const val RIPPLE_ANIMATION_DURATION: Long = 1533
+ const val TAG = "AuthRippleController"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index bc0f995..f83885b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -38,6 +38,7 @@
public class FalsingDataProvider {
private static final long MOTION_EVENT_AGE_MS = 1000;
+ private static final long DROP_EVENT_THRESHOLD_MS = 50;
private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI);
private final int mWidthPixels;
@@ -60,6 +61,7 @@
private float mAngle = 0;
private MotionEvent mFirstRecentMotionEvent;
private MotionEvent mLastMotionEvent;
+ private boolean mDropLastEvent;
private boolean mJustUnlockedWithFace;
private boolean mA11YAction;
@@ -95,6 +97,12 @@
// Ensure prior gesture was completed. May be a no-op.
completePriorGesture();
}
+
+ // Drop the gesture closing event if it is close in time to a previous ACTION_MOVE event.
+ // The reason is that the closing ACTION_UP event of a swipe can be a bit offseted from the
+ // previous ACTION_MOVE event and when it happens, it makes some classifiers fail.
+ mDropLastEvent = shouldDropEvent(motionEvent);
+
mRecentMotionEvents.addAll(motionEvents);
FalsingClassifier.logVerbose("Size: " + mRecentMotionEvents.size());
@@ -129,6 +137,7 @@
mPriorMotionEvents = mRecentMotionEvents;
mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS);
}
+ mDropLastEvent = false;
mA11YAction = false;
}
@@ -150,8 +159,18 @@
return mYdpi;
}
+ /**
+ * Get the {@link MotionEvent}s of the most recent gesture.
+ *
+ * Note that this list may not include the last recorded event.
+ * @see #mDropLastEvent
+ */
public List<MotionEvent> getRecentMotionEvents() {
- return mRecentMotionEvents;
+ if (!mDropLastEvent || mRecentMotionEvents.isEmpty()) {
+ return mRecentMotionEvents;
+ } else {
+ return mRecentMotionEvents.subList(0, mRecentMotionEvents.size() - 1);
+ }
}
public List<MotionEvent> getPriorMotionEvents() {
@@ -169,7 +188,12 @@
return mFirstRecentMotionEvent;
}
- /** Get the last recorded {@link MotionEvent}. */
+ /**
+ * Get the last {@link MotionEvent} of the most recent gesture.
+ *
+ * Note that this may be the event prior to the last recorded event.
+ * @see #mDropLastEvent
+ */
public MotionEvent getLastMotionEvent() {
recalculateData();
return mLastMotionEvent;
@@ -236,12 +260,13 @@
return;
}
- if (mRecentMotionEvents.isEmpty()) {
+ List<MotionEvent> recentMotionEvents = getRecentMotionEvents();
+ if (recentMotionEvents.isEmpty()) {
mFirstRecentMotionEvent = null;
mLastMotionEvent = null;
} else {
- mFirstRecentMotionEvent = mRecentMotionEvents.get(0);
- mLastMotionEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
+ mFirstRecentMotionEvent = recentMotionEvents.get(0);
+ mLastMotionEvent = recentMotionEvents.get(recentMotionEvents.size() - 1);
}
calculateAngleInternal();
@@ -249,6 +274,17 @@
mDirty = false;
}
+ private boolean shouldDropEvent(MotionEvent event) {
+ if (mRecentMotionEvents.size() < 3) return false;
+
+ MotionEvent lastEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
+ boolean isCompletingGesture = event.getActionMasked() == MotionEvent.ACTION_UP
+ && lastEvent.getActionMasked() == MotionEvent.ACTION_MOVE;
+ boolean isRecentEvent =
+ event.getEventTime() - lastEvent.getEventTime() < DROP_EVENT_THRESHOLD_MS;
+ return isCompletingGesture && isRecentEvent;
+ }
+
private void calculateAngleInternal() {
if (mRecentMotionEvents.size() < 2) {
mAngle = Float.MAX_VALUE;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
index 4773f2a..51aede7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
@@ -183,7 +183,7 @@
@Override
public List<MotionEvent> subList(int fromIndex, int toIndex) {
- throw new UnsupportedOperationException();
+ return mMotionEvents.subList(fromIndex, toIndex);
}
class Iter implements ListIterator<MotionEvent> {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index c214f53..2501be9 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -263,10 +263,11 @@
@Override // ClipboardListener.ClipboardOverlay
public void setClipData(ClipData data, String source) {
ClipboardModel model = ClipboardModel.fromClipData(mContext, mClipboardUtils, data, source);
- if (mExitAnimator != null && mExitAnimator.isRunning()) {
+ boolean wasExiting = (mExitAnimator != null && mExitAnimator.isRunning());
+ if (wasExiting) {
mExitAnimator.cancel();
}
- boolean shouldAnimate = !model.dataMatches(mClipboardModel);
+ boolean shouldAnimate = !model.dataMatches(mClipboardModel) || wasExiting;
mClipboardModel = model;
mClipboardLogger.setClipSource(mClipboardModel.getSource());
if (shouldAnimate) {
@@ -313,15 +314,19 @@
mOnPreviewTapped = this::editText;
break;
case IMAGE:
- if (model.isSensitive() || model.loadThumbnail(mContext) != null) {
- mView.showImagePreview(
- model.isSensitive() ? null : model.loadThumbnail(mContext));
- mView.setEditAccessibilityAction(true);
- mOnPreviewTapped = () -> editImage(model.getUri());
- } else {
- // image loading failed
- mView.showDefaultTextPreview();
- }
+ mBgExecutor.execute(() -> {
+ if (model.isSensitive() || model.loadThumbnail(mContext) != null) {
+ mView.post(() -> {
+ mView.showImagePreview(
+ model.isSensitive() ? null : model.loadThumbnail(mContext));
+ mView.setEditAccessibilityAction(true);
+ });
+ mOnPreviewTapped = () -> editImage(model.getUri());
+ } else {
+ // image loading failed
+ mView.post(mView::showDefaultTextPreview);
+ }
+ });
break;
case URI:
case OTHER:
@@ -363,15 +368,15 @@
private void classifyText(ClipboardModel model) {
mBgExecutor.execute(() -> {
- Optional<RemoteAction> remoteAction = mClipboardUtils.getAction(
- model.getText(), model.getTextLinks(), model.getSource());
+ Optional<RemoteAction> remoteAction =
+ mClipboardUtils.getAction(model.getTextLinks(), model.getSource());
if (model.equals(mClipboardModel)) {
remoteAction.ifPresent(action -> {
mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN);
- mView.setActionChip(action, () -> {
+ mView.post(() -> mView.setActionChip(action, () -> {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
animateOut();
- });
+ }));
});
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
index a85f8b9..25caaea 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
@@ -39,6 +39,9 @@
class ClipboardOverlayUtils {
+ // minimum proportion of entire text an entity must take up, to be considered for smart actions
+ private static final float MINIMUM_ENTITY_PROPORTION = .8f;
+
private final TextClassifier mTextClassifier;
@Inject
@@ -65,19 +68,23 @@
return false;
}
- public Optional<RemoteAction> getAction(CharSequence text, TextLinks textLinks, String source) {
- return getActions(text, textLinks).stream().filter(remoteAction -> {
+ public Optional<RemoteAction> getAction(TextLinks textLinks, String source) {
+ return getActions(textLinks).stream().filter(remoteAction -> {
ComponentName component = remoteAction.getActionIntent().getIntent().getComponent();
return component != null && !TextUtils.equals(source, component.getPackageName());
}).findFirst();
}
- private ArrayList<RemoteAction> getActions(CharSequence text, TextLinks textLinks) {
+ private ArrayList<RemoteAction> getActions(TextLinks textLinks) {
ArrayList<RemoteAction> actions = new ArrayList<>();
for (TextLinks.TextLink link : textLinks.getLinks()) {
- TextClassification classification = mTextClassifier.classifyText(
- text, link.getStart(), link.getEnd(), null);
- actions.addAll(classification.getActions());
+ // skip classification for incidental entities
+ if (link.getEnd() - link.getStart()
+ >= textLinks.getText().length() * MINIMUM_ENTITY_PROPORTION) {
+ TextClassification classification = mTextClassifier.classifyText(
+ textLinks.getText(), link.getStart(), link.getEnd(), null);
+ actions.addAll(classification.getActions());
+ }
}
return actions;
}
@@ -92,9 +99,13 @@
private ArrayList<RemoteAction> getActions(ClipData.Item item) {
ArrayList<RemoteAction> actions = new ArrayList<>();
for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
- TextClassification classification = mTextClassifier.classifyText(
- item.getText(), link.getStart(), link.getEnd(), null);
- actions.addAll(classification.getActions());
+ // skip classification for incidental entities
+ if (link.getEnd() - link.getStart()
+ >= item.getText().length() * MINIMUM_ENTITY_PROPORTION) {
+ TextClassification classification = mTextClassifier.classifyText(
+ item.getText(), link.getStart(), link.getEnd(), null);
+ actions.addAll(classification.getActions());
+ }
}
return actions;
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 5817415..95b37ac 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -438,7 +438,9 @@
)
// TODO(b/256873975): Tracking Bug
- @JvmField @Keep val WM_BUBBLE_BAR = unreleasedFlag(1111, "wm_bubble_bar")
+ @JvmField
+ @Keep
+ val WM_BUBBLE_BAR = sysPropBooleanFlag(1111, "persist.wm.debug.bubble_bar", default = false)
// TODO(b/260271148): Tracking bug
@Keep
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
index b0f9c4e..d078688 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
@@ -21,6 +21,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyboard.backlight.ui.KeyboardBacklightDialogCoordinator
import javax.inject.Inject
/** A [CoreStartable] that launches components interested in physical keyboard interaction. */
@@ -28,11 +29,12 @@
class PhysicalKeyboardCoreStartable
@Inject
constructor(
+ private val keyboardBacklightDialogCoordinator: KeyboardBacklightDialogCoordinator,
private val featureFlags: FeatureFlags,
) : CoreStartable {
override fun start() {
if (featureFlags.isEnabled(Flags.KEYBOARD_BACKLIGHT_INDICATOR)) {
- // TODO(b/268645743) start listening for keyboard backlight brightness
+ keyboardBacklightDialogCoordinator.startListening()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt
new file mode 100644
index 0000000..65e70b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.data.repository.KeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+
+/** Allows listening to changes to keyboard backlight level */
+@SysUISingleton
+class KeyboardBacklightInteractor
+@Inject
+constructor(
+ private val keyboardRepository: KeyboardRepository,
+) {
+
+ /** Emits current backlight level as [BacklightModel] or null if keyboard is not connected */
+ val backlight: Flow<BacklightModel?> =
+ keyboardRepository.keyboardConnected.flatMapLatest { connected ->
+ if (connected) keyboardRepository.backlight else flowOf(null)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
new file mode 100644
index 0000000..85d0379
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui
+
+import android.content.Context
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyboard.backlight.ui.view.KeyboardBacklightDialog
+import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Based on the state produced from [BacklightDialogViewModel] shows or hides keyboard backlight
+ * indicator
+ */
+@SysUISingleton
+class KeyboardBacklightDialogCoordinator
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val context: Context,
+ private val viewModel: BacklightDialogViewModel,
+) {
+
+ var dialog: KeyboardBacklightDialog? = null
+
+ fun startListening() {
+ applicationScope.launch {
+ viewModel.dialogContent.collect { dialogViewModel ->
+ if (dialogViewModel != null) {
+ if (dialog == null) {
+ dialog = KeyboardBacklightDialog(context, dialogViewModel)
+ // pass viewModel and show
+ }
+ } else {
+ dialog?.dismiss()
+ dialog = null
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
new file mode 100644
index 0000000..b68a2a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui.view
+
+import android.app.Dialog
+import android.content.Context
+import android.os.Bundle
+import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogContentViewModel
+
+class KeyboardBacklightDialog(context: Context, val viewModel: BacklightDialogContentViewModel) :
+ Dialog(context) {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // TODO(b/268650355) Implement the dialog
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
similarity index 68%
copy from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
copy to packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
index ea15a9f..3ef0ca3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
@@ -15,10 +15,6 @@
*
*/
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.keyboard.backlight.ui.viewmodel
-/**
- * Model for current state of keyboard backlight brightness. [level] indicates current level of
- * backlight brightness and [maxLevel] its max possible value.
- */
-data class BacklightModel(val level: Int, val maxLevel: Int)
+data class BacklightDialogContentViewModel(val currentValue: Int, val maxValue: Int)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt
new file mode 100644
index 0000000..86abca5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui.viewmodel
+
+import android.view.accessibility.AccessibilityManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import javax.inject.Inject
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Responsible for dialog visibility and content - emits [BacklightDialogContentViewModel] if dialog
+ * should be shown and hidden otherwise
+ */
+@SysUISingleton
+class BacklightDialogViewModel
+@Inject
+constructor(
+ interactor: KeyboardBacklightInteractor,
+ private val accessibilityManagerWrapper: AccessibilityManagerWrapper,
+) {
+
+ private val timeoutMillis: Long
+ get() =
+ accessibilityManagerWrapper
+ .getRecommendedTimeoutMillis(
+ DEFAULT_DIALOG_TIMEOUT_MILLIS,
+ AccessibilityManager.FLAG_CONTENT_ICONS
+ )
+ .toLong()
+
+ val dialogContent: Flow<BacklightDialogContentViewModel?> =
+ interactor.backlight
+ .filterNotNull()
+ .map { BacklightDialogContentViewModel(it.level, it.maxLevel) }
+ .timeout(timeoutMillis, emitAfterTimeout = null)
+
+ private fun <T> Flow<T>.timeout(timeoutMillis: Long, emitAfterTimeout: T): Flow<T> {
+ return flatMapLatest {
+ flow {
+ emit(it)
+ delay(timeoutMillis)
+ emit(emitAfterTimeout)
+ }
+ }
+ }
+
+ private companion object {
+ const val DEFAULT_DIALOG_TIMEOUT_MILLIS = 3000
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
index dd5c5d3..b86083a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
@@ -25,7 +25,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.keyboard.data.model.BacklightModel
+import com.android.systemui.keyboard.shared.model.BacklightModel
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
rename to packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
index ea15a9f..4a32f79 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
@@ -15,7 +15,7 @@
*
*/
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.keyboard.shared.model
/**
* Model for current state of keyboard backlight brightness. [level] indicates current level of
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 288f0cc..377a136 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1929,20 +1929,24 @@
// If the keyguard is already showing, see if we don't need to bother re-showing it. Check
// flags in both files to account for the hiding animation which results in a delay and
- // discrepancy between flags.
+ // discrepancy between flags. If we're in the middle of hiding, do not short circuit so that
+ // we explicitly re-set state.
if (mShowing && mKeyguardStateController.isShowing()) {
- if (mPM.isInteractive()) {
+ if (mPM.isInteractive() && !mHiding) {
// It's already showing, and we're not trying to show it while the screen is off.
// We can simply reset all of the views.
- if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
+ if (DEBUG) Log.d(TAG, "doKeyguard: not showing (instead, resetting) because it is "
+ + "already showing, we're interactive, and we were not previously hiding. "
+ + "It should be safe to short-circuit here.");
resetStateLocked();
return;
} else {
- // We are trying to show the keyguard while the screen is off - this results from
- // race conditions involving locking while unlocking. Don't short-circuit here and
- // ensure the keyguard is fully re-shown.
+ // We are trying to show the keyguard while the screen is off or while we were in
+ // the middle of hiding - this results from race conditions involving locking while
+ // unlocking. Don't short-circuit here and ensure the keyguard is fully re-shown.
Log.e(TAG,
- "doKeyguard: already showing, but re-showing since we're not interactive");
+ "doKeyguard: already showing, but re-showing because we're interactive or "
+ + "were in the middle of hiding.");
}
}
@@ -2436,11 +2440,19 @@
if (DEBUG) Log.d(TAG, "handleShow");
}
- mHiding = false;
mKeyguardExitAnimationRunner = null;
mWakeAndUnlocking = false;
setPendingLock(false);
- setShowingLocked(true);
+
+ // Force if we we're showing in the middle of hiding, to ensure we end up in the correct
+ // state.
+ setShowingLocked(true, mHiding /* force */);
+ if (mHiding) {
+ Log.d(TAG, "Forcing setShowingLocked because mHiding=true, which means we're "
+ + "showing in the middle of hiding.");
+ }
+ mHiding = false;
+
mKeyguardViewControllerLazy.get().show(options);
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 1fafd7f..2dc8fee 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -45,7 +45,6 @@
override fun start() {
listenForOccludedToLockscreen()
- listenForOccludedToGone()
listenForOccludedToDreaming()
listenForOccludedToAodOrDozing()
}
@@ -73,22 +72,11 @@
private fun listenForOccludedToLockscreen() {
scope.launch {
keyguardInteractor.isKeyguardOccluded
- .sample(
- combine(
- keyguardInteractor.isKeyguardShowing,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
- ::Pair
- ),
- ::toTriple
- )
- .collect { (isOccluded, isShowing, lastStartedKeyguardState) ->
+ .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (isOccluded, lastStartedKeyguardState) ->
// Occlusion signals come from the framework, and should interrupt any
// existing transition
- if (
- !isOccluded &&
- isShowing &&
- lastStartedKeyguardState.to == KeyguardState.OCCLUDED
- ) {
+ if (!isOccluded && lastStartedKeyguardState.to == KeyguardState.OCCLUDED) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
@@ -102,38 +90,6 @@
}
}
- private fun listenForOccludedToGone() {
- scope.launch {
- keyguardInteractor.isKeyguardOccluded
- .sample(
- combine(
- keyguardInteractor.isKeyguardShowing,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
- ::Pair
- ),
- ::toTriple
- )
- .collect { (isOccluded, isShowing, lastStartedKeyguardState) ->
- // Occlusion signals come from the framework, and should interrupt any
- // existing transition
- if (
- !isOccluded &&
- !isShowing &&
- lastStartedKeyguardState.to == KeyguardState.OCCLUDED
- ) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.OCCLUDED,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
- }
- }
- }
- }
-
private fun listenForOccludedToAodOrDozing() {
scope.launch {
keyguardInteractor.wakefulnessModel
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 097cc3e..a31c1e5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -32,12 +32,15 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
@@ -63,7 +66,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
-import androidx.appcompat.content.res.AppCompatResources;
import androidx.constraintlayout.widget.ConstraintSet;
import com.android.internal.annotations.VisibleForTesting;
@@ -146,6 +148,12 @@
private static final int SMARTSPACE_CARD_CLICK_EVENT = 760;
protected static final int SMARTSPACE_CARD_DISMISS_EVENT = 761;
+ private static final float REC_MEDIA_COVER_SCALE_FACTOR = 1.25f;
+ private static final float MEDIA_SCRIM_START_ALPHA = 0.25f;
+ private static final float MEDIA_REC_SCRIM_START_ALPHA = 0.15f;
+ private static final float MEDIA_PLAYER_SCRIM_END_ALPHA = 0.9f;
+ private static final float MEDIA_REC_SCRIM_END_ALPHA = 1.0f;
+
private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
// Buttons to show in small player when using semantic actions
@@ -779,7 +787,7 @@
WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon);
if (wallpaperColors != null) {
mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
- artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height);
+ artwork = addGradientToPlayerAlbum(artworkIcon, mutableColorScheme, width, height);
isArtworkBound = true;
} else {
// If there's no artwork, use colors from the app icon
@@ -869,8 +877,9 @@
Trace.beginAsyncSection(traceName, traceCookie);
// Capture width & height from views in foreground for artwork scaling in background
- int width = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredWidth();
- int height = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredHeight();
+ int width = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_rec_album_width);
+ int height = mContext.getResources().getDimensionPixelSize(
+ R.dimen.qs_media_rec_album_height_expanded);
mBackgroundExecutor.execute(() -> {
// Album art
@@ -880,7 +889,8 @@
WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon);
if (wallpaperColors != null) {
mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
- artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height);
+ artwork = addGradientToRecommendationAlbum(artworkIcon, mutableColorScheme, width,
+ height);
} else {
artwork = new ColorDrawable(Color.TRANSPARENT);
}
@@ -889,6 +899,11 @@
// Bind the artwork drawable to media cover.
ImageView mediaCover =
mRecommendationViewHolder.getMediaCoverItems().get(itemIndex);
+ // Rescale media cover
+ Matrix coverMatrix = new Matrix(mediaCover.getImageMatrix());
+ coverMatrix.postScale(REC_MEDIA_COVER_SCALE_FACTOR, REC_MEDIA_COVER_SCALE_FACTOR,
+ 0.5f * width, 0.5f * height);
+ mediaCover.setImageMatrix(coverMatrix);
mediaCover.setImageDrawable(artwork);
// Set up the app icon.
@@ -910,40 +925,62 @@
// This method should be called from a background thread. WallpaperColors.fromBitmap takes a
// good amount of time. We do that work on the background executor to avoid stalling animations
// on the UI Thread.
- private WallpaperColors getWallpaperColor(Icon artworkIcon) {
+ @VisibleForTesting
+ protected WallpaperColors getWallpaperColor(Icon artworkIcon) {
if (artworkIcon != null) {
if (artworkIcon.getType() == Icon.TYPE_BITMAP
|| artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
// Avoids extra processing if this is already a valid bitmap
- return WallpaperColors
- .fromBitmap(artworkIcon.getBitmap());
+ Bitmap artworkBitmap = artworkIcon.getBitmap();
+ if (artworkBitmap.isRecycled()) {
+ Log.d(TAG, "Cannot load wallpaper color from a recycled bitmap");
+ return null;
+ }
+ return WallpaperColors.fromBitmap(artworkBitmap);
} else {
Drawable artworkDrawable = artworkIcon.loadDrawable(mContext);
if (artworkDrawable != null) {
- return WallpaperColors
- .fromDrawable(artworkIcon.loadDrawable(mContext));
+ return WallpaperColors.fromDrawable(artworkDrawable);
}
}
}
return null;
}
- private LayerDrawable addGradientToIcon(
- Icon artworkIcon,
- ColorScheme mutableColorScheme,
- int width,
- int height
- ) {
+ @VisibleForTesting
+ protected LayerDrawable addGradientToPlayerAlbum(Icon artworkIcon,
+ ColorScheme mutableColorScheme, int width, int height) {
Drawable albumArt = getScaledBackground(artworkIcon, width, height);
- GradientDrawable gradient = (GradientDrawable) AppCompatResources
- .getDrawable(mContext, R.drawable.qs_media_scrim);
+ GradientDrawable gradient = (GradientDrawable) mContext.getDrawable(
+ R.drawable.qs_media_scrim).mutate();
+ return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme,
+ MEDIA_SCRIM_START_ALPHA, MEDIA_PLAYER_SCRIM_END_ALPHA);
+ }
+
+ @VisibleForTesting
+ protected LayerDrawable addGradientToRecommendationAlbum(Icon artworkIcon,
+ ColorScheme mutableColorScheme, int width, int height) {
+ // First try scaling rec card using bitmap drawable.
+ // If returns null, set drawable bounds.
+ Drawable albumArt = getScaledRecommendationCover(artworkIcon, width, height);
+ if (albumArt == null) {
+ albumArt = getScaledBackground(artworkIcon, width, height);
+ }
+ GradientDrawable gradient = (GradientDrawable) mContext.getDrawable(
+ R.drawable.qs_media_rec_scrim).mutate();
+ return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme,
+ MEDIA_REC_SCRIM_START_ALPHA, MEDIA_REC_SCRIM_END_ALPHA);
+ }
+
+ private LayerDrawable setupGradientColorOnDrawable(Drawable albumArt, GradientDrawable gradient,
+ ColorScheme mutableColorScheme, float startAlpha, float endAlpha) {
gradient.setColors(new int[] {
ColorUtilKt.getColorWithAlpha(
MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme),
- 0.25f),
+ startAlpha),
ColorUtilKt.getColorWithAlpha(
MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme),
- 0.9f),
+ endAlpha),
});
return new LayerDrawable(new Drawable[] { albumArt, gradient });
}
@@ -1589,6 +1626,29 @@
}
/**
+ * Scale artwork to fill the background of media covers in recommendation card.
+ */
+ @UiThread
+ private Drawable getScaledRecommendationCover(Icon artworkIcon, int width, int height) {
+ if (width == 0 || height == 0) {
+ return null;
+ }
+ if (artworkIcon != null) {
+ Bitmap bitmap;
+ if (artworkIcon.getType() == Icon.TYPE_BITMAP
+ || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
+ Bitmap artworkBitmap = artworkIcon.getBitmap();
+ if (artworkBitmap != null) {
+ bitmap = Bitmap.createScaledBitmap(artworkIcon.getBitmap(), width,
+ height, false);
+ return new BitmapDrawable(mContext.getResources(), bitmap);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Get the current media controller
*
* @return the controller
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 7855cdf..cf5ecdd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -389,6 +389,9 @@
boolean isStrongBiometric) {
Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated");
if (mUpdateMonitor.isGoingToSleep()) {
+ mLogger.deferringAuthenticationDueToSleep(userId,
+ biometricSourceType,
+ mPendingAuthenticated != null);
mPendingAuthenticated = new PendingAuthenticated(userId, biometricSourceType,
isStrongBiometric);
Trace.endSection();
@@ -795,6 +798,7 @@
public void onFinishedGoingToSleep() {
Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
if (mPendingAuthenticated != null) {
+ mLogger.finishedGoingToSleepWithPendingAuth();
PendingAuthenticated pendingAuthenticated = mPendingAuthenticated;
// Post this to make sure it's executed after the device is fully locked.
mHandler.post(() -> onBiometricAuthenticated(pendingAuthenticated.userId,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index b88531e..ae715b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -429,7 +429,6 @@
}
dispatchAlwaysOnEvent();
- mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn());
}
@Override
@@ -469,6 +468,7 @@
for (Callback callback : mCallbacks) {
callback.onAlwaysOnChange();
}
+ mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn());
}
private boolean getPostureSpecificBool(
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 726b234..edfc95f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -16,11 +16,13 @@
package com.android.systemui.statusbar.phone;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
import static com.android.systemui.statusbar.phone.CentralSurfaces.getActivityOptions;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -579,8 +581,14 @@
EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
entry.getKey());
mCentralSurfaces.wakeUpForFullScreenIntent();
- fullScreenIntent.send();
+
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityStartMode(
+ MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ fullScreenIntent.sendAndReturnResult(null, 0, null, null, null, null,
+ options.toBundle());
entry.notifyFullScreenIntentLaunched();
+
mMetricsLogger.count("note_fullscreen", 1);
String activityName;
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index 81ae6e8..c72853e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -115,6 +115,17 @@
}
/**
+ * Provide a Long running Executor.
+ */
+ @Provides
+ @SysUISingleton
+ @LongRunning
+ public static DelayableExecutor provideLongRunningDelayableExecutor(
+ @LongRunning Looper looper) {
+ return new ExecutorImpl(looper);
+ }
+
+ /**
* Provide a Background-Thread Executor.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 76a01b9..54b3030 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -41,7 +41,7 @@
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -71,17 +71,16 @@
private HandlerThread mWorker;
// used for most tasks (call canvas.drawBitmap, load/unload the bitmap)
- @Background
- private final DelayableExecutor mBackgroundExecutor;
+ @LongRunning
+ private final DelayableExecutor mLongExecutor;
// wait at least this duration before unloading the bitmap
private static final int DELAY_UNLOAD_BITMAP = 2000;
@Inject
- public ImageWallpaper(@Background DelayableExecutor backgroundExecutor,
- UserTracker userTracker) {
+ public ImageWallpaper(@LongRunning DelayableExecutor longExecutor, UserTracker userTracker) {
super();
- mBackgroundExecutor = backgroundExecutor;
+ mLongExecutor = longExecutor;
mUserTracker = userTracker;
}
@@ -131,7 +130,7 @@
setFixedSizeAllowed(true);
setShowForAllUsers(true);
mWallpaperLocalColorExtractor = new WallpaperLocalColorExtractor(
- mBackgroundExecutor,
+ mLongExecutor,
new WallpaperLocalColorExtractor.WallpaperLocalColorExtractorCallback() {
@Override
public void onColorsProcessed(List<RectF> regions,
@@ -230,7 +229,7 @@
}
private void drawFrame() {
- mBackgroundExecutor.execute(this::drawFrameSynchronized);
+ mLongExecutor.execute(this::drawFrameSynchronized);
}
private void drawFrameSynchronized() {
@@ -285,7 +284,7 @@
}
private void unloadBitmapIfNotUsed() {
- mBackgroundExecutor.execute(this::unloadBitmapIfNotUsedSynchronized);
+ mLongExecutor.execute(this::unloadBitmapIfNotUsedSynchronized);
}
private void unloadBitmapIfNotUsedSynchronized() {
@@ -381,7 +380,7 @@
* - the mini bitmap from color extractor is recomputed
* - the DELAY_UNLOAD_BITMAP has passed
*/
- mBackgroundExecutor.executeDelayed(
+ mLongExecutor.executeDelayed(
this::unloadBitmapIfNotUsedSynchronized, DELAY_UNLOAD_BITMAP);
}
// even if the bitmap cannot be loaded, call reportEngineShown
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
index 988fd71..1e8446f 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
@@ -29,7 +29,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.util.Assert;
import java.io.FileDescriptor;
@@ -66,8 +66,8 @@
private final List<RectF> mPendingRegions = new ArrayList<>();
private final Set<RectF> mProcessedRegions = new ArraySet<>();
- @Background
- private final Executor mBackgroundExecutor;
+ @LongRunning
+ private final Executor mLongExecutor;
private final WallpaperLocalColorExtractorCallback mWallpaperLocalColorExtractorCallback;
@@ -101,13 +101,13 @@
/**
* Creates a new color extractor.
- * @param backgroundExecutor the executor on which the color extraction will be performed
+ * @param longExecutor the executor on which the color extraction will be performed
* @param wallpaperLocalColorExtractorCallback an interface to handle the callbacks from
* the color extractor.
*/
- public WallpaperLocalColorExtractor(@Background Executor backgroundExecutor,
+ public WallpaperLocalColorExtractor(@LongRunning Executor longExecutor,
WallpaperLocalColorExtractorCallback wallpaperLocalColorExtractorCallback) {
- mBackgroundExecutor = backgroundExecutor;
+ mLongExecutor = longExecutor;
mWallpaperLocalColorExtractorCallback = wallpaperLocalColorExtractorCallback;
}
@@ -117,7 +117,7 @@
* not recomputed.
*/
public void setDisplayDimensions(int displayWidth, int displayHeight) {
- mBackgroundExecutor.execute(() ->
+ mLongExecutor.execute(() ->
setDisplayDimensionsSynchronized(displayWidth, displayHeight));
}
@@ -144,7 +144,7 @@
* @param bitmap the new wallpaper
*/
public void onBitmapChanged(@NonNull Bitmap bitmap) {
- mBackgroundExecutor.execute(() -> onBitmapChangedSynchronized(bitmap));
+ mLongExecutor.execute(() -> onBitmapChangedSynchronized(bitmap));
}
private void onBitmapChangedSynchronized(@NonNull Bitmap bitmap) {
@@ -167,7 +167,7 @@
* @param pages the total number of pages of the launcher
*/
public void onPageChanged(int pages) {
- mBackgroundExecutor.execute(() -> onPageChangedSynchronized(pages));
+ mLongExecutor.execute(() -> onPageChangedSynchronized(pages));
}
private void onPageChangedSynchronized(int pages) {
@@ -194,7 +194,7 @@
*/
public void addLocalColorsAreas(@NonNull List<RectF> regions) {
if (regions.size() > 0) {
- mBackgroundExecutor.execute(() -> addLocalColorsAreasSynchronized(regions));
+ mLongExecutor.execute(() -> addLocalColorsAreasSynchronized(regions));
} else {
Log.w(TAG, "Attempt to add colors with an empty list");
}
@@ -218,7 +218,7 @@
* @param regions The areas of interest in our wallpaper (in screen pixel coordinates)
*/
public void removeLocalColorAreas(@NonNull List<RectF> regions) {
- mBackgroundExecutor.execute(() -> removeLocalColorAreasSynchronized(regions));
+ mLongExecutor.execute(() -> removeLocalColorAreasSynchronized(regions));
}
private void removeLocalColorAreasSynchronized(@NonNull List<RectF> regions) {
@@ -236,7 +236,7 @@
* Clean up the memory (in particular, the mini bitmap) used by this class.
*/
public void cleanUp() {
- mBackgroundExecutor.execute(this::cleanUpSynchronized);
+ mLongExecutor.execute(this::cleanUpSynchronized);
}
private void cleanUpSynchronized() {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 9600fd8..08f7eae 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -25,7 +25,6 @@
import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import static com.android.systemui.flags.Flags.WM_BUBBLE_BAR;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -364,7 +363,6 @@
});
}
};
- mBubbles.setBubbleBarEnabled(featureFlags.isEnabled(WM_BUBBLE_BAR));
mBubbles.setSysuiProxy(mSysuiProxy);
}
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 b765ab3..a245c01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -25,7 +25,9 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.keyguard.logging.KeyguardLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -109,6 +111,7 @@
udfpsControllerProvider,
statusBarStateController,
featureFlags,
+ KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)),
rippleView
)
controller.init()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
index faa5db4..ab6d5b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
@@ -94,7 +94,9 @@
mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3));
mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300));
mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301));
- mClassifier.onTouchEvent(appendUpEvent(1, 19, 501));
+ mClassifier.onTouchEvent(appendMoveEvent(1, 19, 501));
+ mClassifier.onTouchEvent(appendUpEvent(1, 19, 501)); //event will be dropped
+
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index 2edc3d3..8eadadf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -75,16 +75,17 @@
}
@Test
- public void test_trackMotionEvents() {
+ public void test_trackMotionEvents_dropUpEvent() {
mDataProvider.onMotionEvent(appendDownEvent(2, 9));
mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
- mDataProvider.onMotionEvent(appendUpEvent(6, 5));
+ mDataProvider.onMotionEvent(appendMoveEvent(6, 5));
+ mDataProvider.onMotionEvent(appendUpEvent(0, 0)); // event will be dropped
List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
assertThat(motionEventList.size()).isEqualTo(3);
assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN);
assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
- assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP);
+ assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L);
assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L);
assertThat(motionEventList.get(2).getEventTime()).isEqualTo(3L);
@@ -97,6 +98,28 @@
}
@Test
+ public void test_trackMotionEvents_keepUpEvent() {
+ mDataProvider.onMotionEvent(appendDownEvent(2, 9));
+ mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
+ mDataProvider.onMotionEvent(appendUpEvent(0, 0, 100));
+ List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
+
+ assertThat(motionEventList.size()).isEqualTo(3);
+ assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN);
+ assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
+ assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP);
+ assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L);
+ assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L);
+ assertThat(motionEventList.get(2).getEventTime()).isEqualTo(100);
+ assertThat(motionEventList.get(0).getX()).isEqualTo(2f);
+ assertThat(motionEventList.get(1).getX()).isEqualTo(4f);
+ assertThat(motionEventList.get(2).getX()).isEqualTo(0f);
+ assertThat(motionEventList.get(0).getY()).isEqualTo(9f);
+ assertThat(motionEventList.get(1).getY()).isEqualTo(7f);
+ assertThat(motionEventList.get(2).getY()).isEqualTo(0f);
+ }
+
+ @Test
public void test_trackRecentMotionEvents() {
mDataProvider.onMotionEvent(appendDownEvent(2, 9, 1));
mDataProvider.onMotionEvent(appendMoveEvent(4, 7, 800));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
index c343c20..ae2b8bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
@@ -68,6 +68,15 @@
}
@Test
+ public void testPass_dropClosingUpEvent() {
+ appendMoveEvent(0, 0);
+ appendMoveEvent(0, 100);
+ appendMoveEvent(0, 200);
+ appendUpEvent(0, 180); // this event would push us over the maxDevianceY
+ assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
+ }
+
+ @Test
public void testPass_fewTouchesHorizontal() {
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
appendMoveEvent(0, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index 2099281..c2fb904 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -446,7 +446,7 @@
mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString()))
.thenReturn(true);
- when(mClipboardUtils.getAction(any(CharSequence.class), any(TextLinks.class), anyString()))
+ when(mClipboardUtils.getAction(any(TextLinks.class), anyString()))
.thenReturn(Optional.of(Mockito.mock(RemoteAction.class)));
when(mClipboardOverlayView.post(any(Runnable.class))).thenAnswer(new Answer<Object>() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
index aea6be3..3d8f04e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.when;
@@ -77,6 +78,74 @@
@Test
public void test_getAction_noLinks_returnsEmptyOptional() {
+ Optional<RemoteAction> action =
+ mClipboardUtils.getAction(Mockito.mock(TextLinks.class), "abc");
+
+ assertTrue(action.isEmpty());
+ }
+
+ @Test
+ public void test_getAction_returnsFirstLink() {
+ TextLinks links = getFakeTextLinksBuilder().build();
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
+ classificationA, classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(links, "test").orElse(null);
+
+ assertEquals(actionA, result);
+ }
+
+ @Test
+ public void test_getAction_skipsMatchingComponent() {
+ TextLinks links = getFakeTextLinksBuilder().build();
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
+ classificationA, classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(links, "abc").orElse(null);
+
+ assertEquals(actionB, result);
+ }
+
+ @Test
+ public void test_getAction_skipsShortEntity() {
+ TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
+ final Map<String, Float> scores = new ArrayMap<>();
+ scores.put(TextClassifier.TYPE_EMAIL, 1f);
+ textLinks.addLink(20, 22, scores);
+ textLinks.addLink(0, 22, scores);
+
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
+ classificationA);
+ when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
+ classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(textLinks.build(), "test").orElse(null);
+
+ assertEquals(actionB, result);
+ }
+
+ // TODO(b/267162944): Next four tests (marked "legacy") are obsolete once
+ // CLIPBOARD_MINIMIZED_LAYOUT flag is released and removed
+ @Test
+ public void test_getAction_noLinks_returnsEmptyOptional_legacy() {
ClipData.Item item = new ClipData.Item("no text links");
item.setTextLinks(Mockito.mock(TextLinks.class));
@@ -86,8 +155,8 @@
}
@Test
- public void test_getAction_returnsFirstLink() {
- when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
+ public void test_getAction_returnsFirstLink_legacy() {
+ when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
when(mClipDataItem.getText()).thenReturn("");
RemoteAction actionA = constructRemoteAction("abc");
RemoteAction actionB = constructRemoteAction("def");
@@ -98,14 +167,14 @@
when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
classificationA, classificationB);
- RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "def").orElse(null);
+ RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);
assertEquals(actionA, result);
}
@Test
- public void test_getAction_skipsMatchingComponent() {
- when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
+ public void test_getAction_skipsMatchingComponent_legacy() {
+ when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
when(mClipDataItem.getText()).thenReturn("");
RemoteAction actionA = constructRemoteAction("abc");
RemoteAction actionB = constructRemoteAction("def");
@@ -122,6 +191,33 @@
}
@Test
+ public void test_getAction_skipsShortEntity_legacy() {
+ TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
+ final Map<String, Float> scores = new ArrayMap<>();
+ scores.put(TextClassifier.TYPE_EMAIL, 1f);
+ textLinks.addLink(20, 22, scores);
+ textLinks.addLink(0, 22, scores);
+
+ when(mClipDataItem.getTextLinks()).thenReturn(textLinks.build());
+ when(mClipDataItem.getText()).thenReturn(textLinks.build().getText());
+
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
+ classificationA);
+ when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
+ classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);
+
+ assertEquals(actionB, result);
+ }
+
+ @Test
public void test_extra_withPackage_returnsTrue() {
PersistableBundle b = new PersistableBundle();
b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true);
@@ -184,12 +280,12 @@
return action;
}
- private static TextLinks getFakeTextLinks() {
- TextLinks.Builder textLinks = new TextLinks.Builder("test");
+ private static TextLinks.Builder getFakeTextLinksBuilder() {
+ TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
final Map<String, Float> scores = new ArrayMap<>();
scores.put(TextClassifier.TYPE_EMAIL, 1f);
- textLinks.addLink(0, 0, scores);
- textLinks.addLink(0, 0, scores);
- return textLinks.build();
+ textLinks.addLink(0, 22, scores);
+ textLinks.addLink(0, 22, scores);
+ return textLinks;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
new file mode 100644
index 0000000..ec94cde
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyboardBacklightInteractorTest : SysuiTestCase() {
+
+ private val keyboardRepository = FakeKeyboardRepository()
+ private lateinit var underTest: KeyboardBacklightInteractor
+
+ @Before
+ fun setUp() {
+ underTest = KeyboardBacklightInteractor(keyboardRepository)
+ }
+
+ @Test
+ fun emitsNull_whenKeyboardJustConnected() = runTest {
+ val latest by collectLastValue(underTest.backlight)
+ keyboardRepository.setKeyboardConnected(true)
+
+ assertThat(latest).isNull()
+ }
+
+ @Test
+ fun emitsBacklight_whenKeyboardConnectedAndBacklightChanged() = runTest {
+ keyboardRepository.setKeyboardConnected(true)
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ assertThat(underTest.backlight.first()).isEqualTo(BacklightModel(1, 5))
+ }
+
+ @Test
+ fun emitsNull_afterKeyboardDisconnecting() = runTest {
+ val latest by collectLastValue(underTest.backlight)
+ keyboardRepository.setKeyboardConnected(true)
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ keyboardRepository.setKeyboardConnected(false)
+
+ assertThat(latest).isNull()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt
new file mode 100644
index 0000000..ec05d10
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
+import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BacklightDialogViewModelTest : SysuiTestCase() {
+
+ private val keyboardRepository = FakeKeyboardRepository()
+ private lateinit var underTest: BacklightDialogViewModel
+ @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper
+ private val timeoutMillis = 3000L
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(accessibilityManagerWrapper.getRecommendedTimeoutMillis(any(), any()))
+ .thenReturn(timeoutMillis.toInt())
+ underTest =
+ BacklightDialogViewModel(
+ KeyboardBacklightInteractor(keyboardRepository),
+ accessibilityManagerWrapper
+ )
+ keyboardRepository.setKeyboardConnected(true)
+ }
+
+ @Test
+ fun emitsViewModel_whenBacklightChanged() = runTest {
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ assertThat(underTest.dialogContent.first()).isEqualTo(BacklightDialogContentViewModel(1, 5))
+ }
+
+ @Test
+ fun emitsNull_afterTimeout() = runTest {
+ val latest by collectLastValue(underTest.dialogContent)
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
+ advanceTimeBy(timeoutMillis + 1)
+ assertThat(latest).isNull()
+ }
+
+ @Test
+ fun emitsNull_after5secDelay_fromLastBacklightChange() = runTest {
+ val latest by collectLastValue(underTest.dialogContent)
+ keyboardRepository.setKeyboardConnected(true)
+
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // timeout yet to pass, no new emission
+ keyboardRepository.setBacklight(BacklightModel(2, 5))
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // timeout refreshed because of last `setBacklight`, still content present
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // finally timeout reached and null emitted
+ assertThat(latest).isNull()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 2209852..fe9098f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -358,92 +358,6 @@
}
@Test
- fun `OCCLUDED to GONE`() =
- testScope.runTest {
- // GIVEN a device on lockscreen
- keyguardRepository.setKeyguardShowing(true)
- runCurrent()
-
- // GIVEN a prior transition has run to OCCLUDED
- runner.startTransition(
- testScope,
- TransitionInfo(
- ownerName = "",
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.OCCLUDED,
- animator =
- ValueAnimator().apply {
- duration = 10
- interpolator = Interpolators.LINEAR
- },
- )
- )
- keyguardRepository.setKeyguardOccluded(true)
- runCurrent()
- reset(mockTransitionRepository)
-
- // WHEN keyguard goes away
- keyguardRepository.setKeyguardShowing(false)
- // AND occlusion ends
- keyguardRepository.setKeyguardOccluded(false)
- runCurrent()
-
- val info =
- withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
- }
- // THEN a transition to GONE should occur
- assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.to).isEqualTo(KeyguardState.GONE)
- assertThat(info.animator).isNotNull()
-
- coroutineContext.cancelChildren()
- }
-
- @Test
- fun `OCCLUDED to LOCKSCREEN`() =
- testScope.runTest {
- // GIVEN a device on lockscreen
- keyguardRepository.setKeyguardShowing(true)
- runCurrent()
-
- // GIVEN a prior transition has run to OCCLUDED
- runner.startTransition(
- testScope,
- TransitionInfo(
- ownerName = "",
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.OCCLUDED,
- animator =
- ValueAnimator().apply {
- duration = 10
- interpolator = Interpolators.LINEAR
- },
- )
- )
- keyguardRepository.setKeyguardOccluded(true)
- runCurrent()
- reset(mockTransitionRepository)
-
- // WHEN occlusion ends
- keyguardRepository.setKeyguardOccluded(false)
- runCurrent()
-
- val info =
- withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
- }
- // THEN a transition to LOCKSCREEN should occur
- assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
-
- coroutineContext.cancelChildren()
- }
-
- @Test
fun `LOCKSCREEN to DOZING`() =
testScope.runTest {
// GIVEN a device with AOD not available
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index 55a33b6..fd353af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -27,6 +27,7 @@
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
+import android.graphics.Matrix
import android.graphics.drawable.Animatable2
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
@@ -78,6 +79,8 @@
import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.media.dialog.MediaOutputDialogFactory
+import com.android.systemui.monet.ColorScheme
+import com.android.systemui.monet.Style
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -214,6 +217,7 @@
@Mock private lateinit var recSubtitleMock2: TextView
@Mock private lateinit var recSubtitleMock3: TextView
@Mock private lateinit var coverItem: ImageView
+ @Mock private lateinit var matrix: Matrix
private lateinit var coverItem1: ImageView
private lateinit var coverItem2: ImageView
private lateinit var coverItem3: ImageView
@@ -700,6 +704,46 @@
}
@Test
+ fun addTwoPlayerGradients_differentStates() {
+ // Setup redArtwork and its color scheme.
+ val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val redCanvas = Canvas(redBmp)
+ redCanvas.drawColor(Color.RED)
+ val redArt = Icon.createWithBitmap(redBmp)
+ val redWallpaperColor = player.getWallpaperColor(redArt)
+ val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT)
+
+ // Setup greenArt and its color scheme.
+ val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val greenCanvas = Canvas(greenBmp)
+ greenCanvas.drawColor(Color.GREEN)
+ val greenArt = Icon.createWithBitmap(greenBmp)
+ val greenWallpaperColor = player.getWallpaperColor(greenArt)
+ val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT)
+
+ // Add gradient to both icons.
+ val redArtwork = player.addGradientToPlayerAlbum(redArt, redColorScheme, 10, 10)
+ val greenArtwork = player.addGradientToPlayerAlbum(greenArt, greenColorScheme, 10, 10)
+
+ // They should have different constant states as they have different gradient color.
+ assertThat(redArtwork.getDrawable(1).constantState)
+ .isNotEqualTo(greenArtwork.getDrawable(1).constantState)
+ }
+
+ @Test
+ fun getWallpaperColor_recycledBitmap_notCrashing() {
+ // Setup redArt icon.
+ val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val redArt = Icon.createWithBitmap(redBmp)
+
+ // Recycle bitmap of redArt icon.
+ redArt.bitmap.recycle()
+
+ // get wallpaperColor without illegal exception.
+ player.getWallpaperColor(redArt)
+ }
+
+ @Test
fun bind_seekBarDisabled_hasActions_seekBarVisibilityIsSetToInvisible() {
useRealConstraintSets()
@@ -2092,6 +2136,7 @@
.thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3))
whenever(recommendationViewHolder.mediaSubtitles)
.thenReturn(listOf(recSubtitleMock1, recSubtitleMock2, recSubtitleMock3))
+ whenever(coverItem.imageMatrix).thenReturn(matrix)
val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bmp)
@@ -2127,6 +2172,7 @@
verify(recCardTitle).setTextColor(any<Int>())
verify(recAppIconItem, times(3)).setImageDrawable(any(Drawable::class.java))
verify(coverItem, times(3)).setImageDrawable(any(Drawable::class.java))
+ verify(coverItem, times(3)).imageMatrix = any()
}
@Test
@@ -2189,6 +2235,34 @@
}
@Test
+ fun addTwoRecommendationGradients_differentStates() {
+ // Setup redArtwork and its color scheme.
+ val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val redCanvas = Canvas(redBmp)
+ redCanvas.drawColor(Color.RED)
+ val redArt = Icon.createWithBitmap(redBmp)
+ val redWallpaperColor = player.getWallpaperColor(redArt)
+ val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT)
+
+ // Setup greenArt and its color scheme.
+ val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val greenCanvas = Canvas(greenBmp)
+ greenCanvas.drawColor(Color.GREEN)
+ val greenArt = Icon.createWithBitmap(greenBmp)
+ val greenWallpaperColor = player.getWallpaperColor(greenArt)
+ val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT)
+
+ // Add gradient to both icons.
+ val redArtwork = player.addGradientToRecommendationAlbum(redArt, redColorScheme, 10, 10)
+ val greenArtwork =
+ player.addGradientToRecommendationAlbum(greenArt, greenColorScheme, 10, 10)
+
+ // They should have different constant states as they have different gradient color.
+ assertThat(redArtwork.getDrawable(1).constantState)
+ .isNotEqualTo(greenArtwork.getDrawable(1).constantState)
+ }
+
+ @Test
fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() {
fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
val semanticActions =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index eb5edbc..f5b7ca8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -180,6 +180,7 @@
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
+ verify(mScreenOffAnimationController).onAlwaysOnChanged(false);
assertThat(mDozeParameters.getAlwaysOn()).isFalse();
}
@@ -196,13 +197,16 @@
mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
verify(callback, times(2)).onAlwaysOnChange();
+ verify(mScreenOffAnimationController, times(2)).onAlwaysOnChanged(false);
assertThat(mDozeParameters.getAlwaysOn()).isFalse();
+ reset(mScreenOffAnimationController);
reset(callback);
when(mBatteryController.isAodPowerSave()).thenReturn(false);
mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
verify(callback).onAlwaysOnChange();
+ verify(mScreenOffAnimationController).onAlwaysOnChanged(true);
assertThat(mDozeParameters.getAlwaysOn()).isTrue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
index 85cfef7..fd368eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
@@ -16,22 +16,24 @@
package com.android.systemui.unfold.updates
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Looper
import android.testing.AndroidTestingRunner
-import android.view.IRotationWatcher
-import android.view.IWindowManager
+import android.view.Display
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.utils.os.FakeHandler
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
@@ -42,19 +44,23 @@
private lateinit var rotationChangeProvider: RotationChangeProvider
- @Mock lateinit var windowManagerInterface: IWindowManager
+ @Mock lateinit var displayManager: DisplayManager
@Mock lateinit var listener: RotationListener
- @Captor lateinit var rotationWatcher: ArgumentCaptor<IRotationWatcher>
- private val fakeExecutor = FakeExecutor(FakeSystemClock())
+ @Mock lateinit var display: Display
+ @Captor lateinit var displayListener: ArgumentCaptor<DisplayManager.DisplayListener>
+ private val fakeHandler = FakeHandler(Looper.getMainLooper())
+
+ private lateinit var spyContext: Context
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- rotationChangeProvider =
- RotationChangeProvider(windowManagerInterface, context, fakeExecutor)
+ spyContext = spy(context)
+ whenever(spyContext.display).thenReturn(display)
+ rotationChangeProvider = RotationChangeProvider(displayManager, spyContext, fakeHandler)
rotationChangeProvider.addCallback(listener)
- fakeExecutor.runAllReady()
- verify(windowManagerInterface).watchRotation(rotationWatcher.capture(), anyInt())
+ fakeHandler.dispatchQueuedMessages()
+ verify(displayManager).registerDisplayListener(displayListener.capture(), any())
}
@Test
@@ -70,15 +76,16 @@
verify(listener).onRotationChanged(42)
rotationChangeProvider.removeCallback(listener)
- fakeExecutor.runAllReady()
+ fakeHandler.dispatchQueuedMessages()
sendRotationUpdate(43)
- verify(windowManagerInterface).removeRotationWatcher(any())
+ verify(displayManager).unregisterDisplayListener(any())
verifyNoMoreInteractions(listener)
}
private fun sendRotationUpdate(newRotation: Int) {
- rotationWatcher.value.onRotationChanged(newRotation)
- fakeExecutor.runAllReady()
+ whenever(display.rotation).thenReturn(newRotation)
+ displayListener.allValues.forEach { it.onDisplayChanged(display.displayId) }
+ fakeHandler.dispatchQueuedMessages()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index 31cce4f..468c5a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -88,7 +88,7 @@
@Mock
private Bitmap mWallpaperBitmap;
FakeSystemClock mFakeSystemClock = new FakeSystemClock();
- FakeExecutor mFakeBackgroundExecutor = new FakeExecutor(mFakeSystemClock);
+ FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
@Before
public void setUp() throws Exception {
@@ -125,7 +125,7 @@
@Test
public void testBitmapWallpaper_normal() {
- // Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
+ // Will use an image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
// Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH.
int bitmapSide = DISPLAY_WIDTH;
testSurfaceHelper(
@@ -137,7 +137,7 @@
@Test
public void testBitmapWallpaper_low_resolution() {
- // Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
+ // Will use an image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
// Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT.
testSurfaceHelper(LOW_BMP_WIDTH /* bitmapWidth */,
LOW_BMP_HEIGHT /* bitmapHeight */,
@@ -161,13 +161,13 @@
ImageWallpaper.CanvasEngine spyEngine = getSpyEngine();
spyEngine.onCreate(mSurfaceHolder);
spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
- assertThat(mFakeBackgroundExecutor.numPending()).isAtLeast(1);
+ assertThat(mFakeExecutor.numPending()).isAtLeast(1);
int n = 0;
- while (mFakeBackgroundExecutor.numPending() >= 1) {
+ while (mFakeExecutor.numPending() >= 1) {
n++;
assertThat(n).isAtMost(10);
- mFakeBackgroundExecutor.runNextReady();
+ mFakeExecutor.runNextReady();
mFakeSystemClock.advanceTime(1000);
}
@@ -176,7 +176,7 @@
}
private ImageWallpaper createImageWallpaper() {
- return new ImageWallpaper(mFakeBackgroundExecutor, mUserTracker) {
+ return new ImageWallpaper(mFakeExecutor, mUserTracker) {
@Override
public Engine onCreateEngine() {
return new CanvasEngine() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt
new file mode 100644
index 0000000..4e43546
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.data.repository
+
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+
+class FakeKeyboardRepository : KeyboardRepository {
+
+ private val _keyboardConnected = MutableStateFlow(false)
+ override val keyboardConnected: Flow<Boolean> = _keyboardConnected
+
+ private val _backlightState: MutableStateFlow<BacklightModel?> = MutableStateFlow(null)
+ // filtering to make sure backlight doesn't have default initial value
+ override val backlight: Flow<BacklightModel> = _backlightState.filterNotNull()
+
+ fun setBacklight(state: BacklightModel) {
+ _backlightState.value = state
+ }
+
+ fun setKeyboardConnected(connected: Boolean) {
+ _keyboardConnected.value = connected
+ }
+}
diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp
index 180b611..2e0a946 100644
--- a/packages/SystemUI/unfold/Android.bp
+++ b/packages/SystemUI/unfold/Android.bp
@@ -35,6 +35,7 @@
],
kotlincflags: ["-Xjvm-default=enable"],
java_version: "1.8",
+ sdk_version: "current",
min_sdk_version: "current",
plugins: ["dagger2-compiler"],
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 068347c..a079668 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -19,8 +19,8 @@
import android.content.ContentResolver
import android.content.Context
import android.hardware.SensorManager
+import android.hardware.display.DisplayManager
import android.os.Handler
-import android.view.IWindowManager
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg
@@ -61,7 +61,7 @@
@BindsInstance @UnfoldMain executor: Executor,
@BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
- @BindsInstance windowManager: IWindowManager,
+ @BindsInstance displayManager: DisplayManager,
@BindsInstance contentResolver: ContentResolver = context.contentResolver
): UnfoldSharedComponent
}
@@ -84,8 +84,9 @@
@BindsInstance context: Context,
@BindsInstance config: UnfoldTransitionConfig,
@BindsInstance @UnfoldMain executor: Executor,
+ @BindsInstance @UnfoldMain handler: Handler,
@BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
- @BindsInstance windowManager: IWindowManager,
+ @BindsInstance displayManager: DisplayManager,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
): RemoteUnfoldSharedComponent
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 8eb79df..1839919 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -19,8 +19,8 @@
import android.content.Context
import android.hardware.SensorManager
+import android.hardware.display.DisplayManager
import android.os.Handler
-import android.view.IWindowManager
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
@@ -47,7 +47,7 @@
mainExecutor: Executor,
singleThreadBgExecutor: Executor,
tracingTagPrefix: String,
- windowManager: IWindowManager,
+ displayManager: DisplayManager,
): UnfoldSharedComponent =
DaggerUnfoldSharedComponent.factory()
.create(
@@ -61,7 +61,7 @@
mainExecutor,
singleThreadBgExecutor,
tracingTagPrefix,
- windowManager,
+ displayManager,
)
/**
@@ -73,16 +73,18 @@
context: Context,
config: UnfoldTransitionConfig,
mainExecutor: Executor,
+ mainHandler: Handler,
singleThreadBgExecutor: Executor,
tracingTagPrefix: String,
- windowManager: IWindowManager,
+ displayManager: DisplayManager,
): RemoteUnfoldSharedComponent =
DaggerRemoteUnfoldSharedComponent.factory()
.create(
context,
config,
mainExecutor,
+ mainHandler,
singleThreadBgExecutor,
- windowManager,
+ displayManager,
tracingTagPrefix,
)
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index d19b414..28e4936 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -16,7 +16,6 @@
package com.android.systemui.unfold.progress
import android.os.Trace
-import android.os.Trace.TRACE_TAG_APP
import android.util.Log
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
@@ -110,7 +109,7 @@
if (DEBUG) {
Log.d(TAG, "onFoldUpdate = ${update.name()}")
- Trace.traceCounter(Trace.TRACE_TAG_APP, "fold_update", update)
+ Trace.setCounter("fold_update", update.toLong())
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 82fd225..d653fc7 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -119,7 +119,7 @@
"lastHingeAngle: $lastHingeAngle, " +
"lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition"
)
- Trace.traceCounter(Trace.TRACE_TAG_APP, "hinge_angle", angle.toInt())
+ Trace.setCounter( "hinge_angle", angle.toLong())
}
val currentDirection =
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index 0cf8224..ce8f1a1 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -17,36 +17,32 @@
package com.android.systemui.unfold.updates
import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Handler
import android.os.RemoteException
-import android.view.IRotationWatcher
-import android.view.IWindowManager
-import android.view.Surface.Rotation
import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.util.CallbackController
-import java.util.concurrent.Executor
import javax.inject.Inject
/**
- * Allows to subscribe to rotation changes.
- *
- * This is needed as rotation updates from [IWindowManager] are received in a binder thread, while
- * most of the times we want them in the main one. Updates are provided for the display associated
+ * Allows to subscribe to rotation changes. Updates are provided for the display associated
* to [context].
*/
class RotationChangeProvider
@Inject
constructor(
- private val windowManagerInterface: IWindowManager,
+ private val displayManager: DisplayManager,
private val context: Context,
- @UnfoldMain private val mainExecutor: Executor,
+ @UnfoldMain private val mainHandler: Handler,
) : CallbackController<RotationChangeProvider.RotationListener> {
private val listeners = mutableListOf<RotationListener>()
- private val rotationWatcher = RotationWatcher()
+ private val displayListener = RotationDisplayListener()
+ private var lastRotation: Int? = null
override fun addCallback(listener: RotationListener) {
- mainExecutor.execute {
+ mainHandler.post {
if (listeners.isEmpty()) {
subscribeToRotation()
}
@@ -55,17 +51,18 @@
}
override fun removeCallback(listener: RotationListener) {
- mainExecutor.execute {
+ mainHandler.post {
listeners -= listener
if (listeners.isEmpty()) {
unsubscribeToRotation()
+ lastRotation = null
}
}
}
private fun subscribeToRotation() {
try {
- windowManagerInterface.watchRotation(rotationWatcher, context.displayId)
+ displayManager.registerDisplayListener(displayListener, mainHandler)
} catch (e: RemoteException) {
throw e.rethrowFromSystemServer()
}
@@ -73,7 +70,7 @@
private fun unsubscribeToRotation() {
try {
- windowManagerInterface.removeRotationWatcher(rotationWatcher)
+ displayManager.unregisterDisplayListener(displayListener)
} catch (e: RemoteException) {
throw e.rethrowFromSystemServer()
}
@@ -82,12 +79,25 @@
/** Gets notified of rotation changes. */
fun interface RotationListener {
/** Called once rotation changes. */
- fun onRotationChanged(@Rotation newRotation: Int)
+ fun onRotationChanged(newRotation: Int)
}
- private inner class RotationWatcher : IRotationWatcher.Stub() {
- override fun onRotationChanged(rotation: Int) {
- mainExecutor.execute { listeners.forEach { it.onRotationChanged(rotation) } }
+ private inner class RotationDisplayListener : DisplayManager.DisplayListener {
+
+ override fun onDisplayChanged(displayId: Int) {
+ val display = context.display ?: return
+
+ if (displayId == display.displayId) {
+ val currentRotation = display.rotation
+ if (lastRotation == null || lastRotation != currentRotation) {
+ listeners.forEach { it.onRotationChanged(currentRotation) }
+ lastRotation = currentRotation
+ }
+ }
}
+
+ override fun onDisplayAdded(displayId: Int) {}
+
+ override fun onDisplayRemoved(displayId: Int) {}
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
index 06ca153..ce5c5f9 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
@@ -79,10 +79,9 @@
companion object {
fun ContentResolver.areAnimationsEnabled(): Boolean {
val animationScale =
- Settings.Global.getStringForUser(
+ Settings.Global.getString(
this,
Settings.Global.ANIMATOR_DURATION_SCALE,
- this.userId
)
?.toFloatOrNull()
?: 1f
diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java
index 864fe0f..7df0d86 100644
--- a/services/companion/java/com/android/server/companion/virtual/SensorController.java
+++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java
@@ -99,6 +99,9 @@
private int createSensorInternal(IBinder sensorToken, VirtualSensorConfig config)
throws SensorCreationException {
+ if (config.getType() <= 0) {
+ throw new SensorCreationException("Received an invalid virtual sensor type.");
+ }
final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId,
config.getType(), config.getName(),
config.getVendor() == null ? "" : config.getVendor(), config.getFlags(),
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index e3f00ded..9e95e5f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -995,7 +995,7 @@
private static final String KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION =
"enable_wait_for_finish_attach_application";
- private static final boolean DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION = true;
+ private static final boolean DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION = false;
/** @see #KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION */
public volatile boolean mEnableWaitForFinishAttachApplication =
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1960c33..4ba6854 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -101,7 +101,7 @@
import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
-import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH;
import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
@@ -5588,8 +5588,11 @@
boolean isChangeEnabled = CompatChanges.isChangeEnabled(
PendingIntent.BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT,
owningUid);
- logUnsafeMutableImplicitPi(packageName, resolvedTypes, owningUid, i, intent,
- isChangeEnabled);
+ String resolvedType = resolvedTypes == null
+ || i >= resolvedTypes.length ? null : resolvedTypes[i];
+ ActivityManagerUtils.logUnsafeIntentEvent(
+ UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED,
+ owningUid, intent, resolvedType, isChangeEnabled);
if (isChangeEnabled) {
String msg = packageName + ": Targeting U+ (version "
+ Build.VERSION_CODES.UPSIDE_DOWN_CAKE + " and above) disallows"
@@ -5655,24 +5658,6 @@
}
}
- private void logUnsafeMutableImplicitPi(String packageName, String[] resolvedTypes,
- int owningUid, int i, Intent intent, boolean isChangeEnabled) {
- String[] categories = intent.getCategories() == null ? new String[0]
- : intent.getCategories().toArray(String[]::new);
- String resolvedType = resolvedTypes == null || i >= resolvedTypes.length ? null
- : resolvedTypes[i];
- FrameworkStatsLog.write(UNSAFE_INTENT_EVENT_REPORTED,
- UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED,
- owningUid,
- null,
- packageName,
- intent.getAction(),
- categories,
- resolvedType,
- intent.getScheme(),
- isChangeEnabled);
- }
-
@Override
public int sendIntentSender(IApplicationThread caller, IIntentSender target,
IBinder allowlistToken, int code, Intent intent, String resolvedType,
@@ -12912,18 +12897,9 @@
boolean hasToBeExportedToMatch = platformCompat.isChangeEnabledByUid(
ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS,
callingUid);
- String[] categories = intent.getCategories() == null ? new String[0]
- : intent.getCategories().toArray(String[]::new);
- FrameworkStatsLog.write(UNSAFE_INTENT_EVENT_REPORTED,
- FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH,
- callingUid,
- componentInfo,
- callerPackage,
- intent.getAction(),
- categories,
- resolvedType,
- intent.getScheme(),
- hasToBeExportedToMatch);
+ ActivityManagerUtils.logUnsafeIntentEvent(
+ UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH,
+ callingUid, intent, resolvedType, hasToBeExportedToMatch);
if (!hasToBeExportedToMatch) {
return;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerUtils.java b/services/core/java/com/android/server/am/ActivityManagerUtils.java
index 9be553c..01466b8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerUtils.java
+++ b/services/core/java/com/android/server/am/ActivityManagerUtils.java
@@ -17,11 +17,13 @@
import android.app.ActivityThread;
import android.content.ContentResolver;
+import android.content.Intent;
import android.provider.Settings;
import android.util.ArrayMap;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -133,4 +135,25 @@
public static int hashComponentNameForAtom(String shortInstanceName) {
return getUnsignedHashUnCached(shortInstanceName) ^ getAndroidIdHash();
}
+
+ /**
+ * Helper method to log an unsafe intent event.
+ */
+ public static void logUnsafeIntentEvent(int event, int callingUid,
+ Intent intent, String resolvedType, boolean blocked) {
+ String[] categories = intent.getCategories() == null ? new String[0]
+ : intent.getCategories().toArray(String[]::new);
+ String component = intent.getComponent() == null ? null
+ : intent.getComponent().flattenToString();
+ FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED,
+ event,
+ callingUid,
+ component,
+ intent.getPackage(),
+ intent.getAction(),
+ categories,
+ resolvedType,
+ intent.getScheme(),
+ blocked);
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
index 42be95b..ecb7e7c 100644
--- a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
+++ b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
@@ -20,8 +20,13 @@
import android.annotation.Nullable;
import android.content.Intent;
import android.hardware.biometrics.IBiometricContextListener;
+import android.hardware.biometrics.common.AuthenticateReason;
import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.common.OperationReason;
+import android.hardware.biometrics.common.WakeReason;
+import android.hardware.face.FaceAuthenticateOptions;
+import android.hardware.fingerprint.FingerprintAuthenticateOptions;
+import android.os.PowerManager;
import android.view.Surface;
/**
@@ -50,12 +55,127 @@
mAidlContext = context;
}
- /** Gets the subset of the context that can be shared with the HAL. */
+ /**
+ * Gets the subset of the context that can be shared with the HAL.
+ *
+ * When starting a new operation use methods like to update & fetch the context:
+ * <ul>
+ * <li>{@link #toAidlContext(FaceAuthenticateOptions)}
+ * <li>{@link #toAidlContext(FingerprintAuthenticateOptions)}
+ * </ul>
+ *
+ * Use this method for any subsequent calls to the HAL or for operations that do
+ * not accept any options.
+ *
+ * @return the underlying AIDL context
+ */
@NonNull
public OperationContext toAidlContext() {
return mAidlContext;
}
+ /**
+ * Gets the subset of the context that can be shared with the HAL and updates
+ * it with the given options.
+ *
+ * @param options authenticate options
+ * @return the underlying AIDL context
+ */
+ @NonNull
+ public OperationContext toAidlContext(@NonNull FaceAuthenticateOptions options) {
+ mAidlContext.authenticateReason = AuthenticateReason
+ .faceAuthenticateReason(getAuthReason(options));
+ mAidlContext.wakeReason = getWakeReason(options);
+
+ return mAidlContext;
+ }
+
+ /**
+ * Gets the subset of the context that can be shared with the HAL and updates
+ * it with the given options.
+ *
+ * @param options authenticate options
+ * @return the underlying AIDL context
+ */
+ @NonNull
+ public OperationContext toAidlContext(@NonNull FingerprintAuthenticateOptions options) {
+ mAidlContext.authenticateReason = AuthenticateReason
+ .fingerprintAuthenticateReason(getAuthReason(options));
+ mAidlContext.wakeReason = getWakeReason(options);
+
+ return mAidlContext;
+ }
+
+ @AuthenticateReason.Face
+ private int getAuthReason(@NonNull FaceAuthenticateOptions options) {
+ switch (options.getAuthenticateReason()) {
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_STARTED_WAKING_UP:
+ return AuthenticateReason.Face.STARTED_WAKING_UP;
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN:
+ return AuthenticateReason.Face.PRIMARY_BOUNCER_SHOWN;
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_ASSISTANT_VISIBLE:
+ return AuthenticateReason.Face.ASSISTANT_VISIBLE;
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN:
+ return AuthenticateReason.Face.ALTERNATE_BIOMETRIC_BOUNCER_SHOWN;
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_NOTIFICATION_PANEL_CLICKED:
+ return AuthenticateReason.Face.NOTIFICATION_PANEL_CLICKED;
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED:
+ return AuthenticateReason.Face.OCCLUDING_APP_REQUESTED;
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_PICK_UP_GESTURE_TRIGGERED:
+ return AuthenticateReason.Face.PICK_UP_GESTURE_TRIGGERED;
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_QS_EXPANDED:
+ return AuthenticateReason.Face.QS_EXPANDED;
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_SWIPE_UP_ON_BOUNCER:
+ return AuthenticateReason.Face.SWIPE_UP_ON_BOUNCER;
+ case FaceAuthenticateOptions.AUTHENTICATE_REASON_UDFPS_POINTER_DOWN:
+ return AuthenticateReason.Face.UDFPS_POINTER_DOWN;
+ default:
+ return AuthenticateReason.Face.UNKNOWN;
+ }
+ }
+
+ @WakeReason
+ private int getWakeReason(@NonNull FaceAuthenticateOptions options) {
+ switch (options.getWakeReason()) {
+ case PowerManager.WAKE_REASON_POWER_BUTTON:
+ return WakeReason.POWER_BUTTON;
+ case PowerManager.WAKE_REASON_GESTURE:
+ return WakeReason.GESTURE;
+ case PowerManager.WAKE_REASON_WAKE_KEY:
+ return WakeReason.WAKE_KEY;
+ case PowerManager.WAKE_REASON_WAKE_MOTION:
+ return WakeReason.WAKE_MOTION;
+ case PowerManager.WAKE_REASON_DISPLAY_GROUP_ADDED:
+ return WakeReason.DISPLAY_GROUP_ADDED;
+ case PowerManager.WAKE_REASON_TAP:
+ return WakeReason.TAP;
+ case PowerManager.WAKE_REASON_LIFT:
+ return WakeReason.LIFT;
+ case PowerManager.WAKE_REASON_BIOMETRIC:
+ return WakeReason.BIOMETRIC;
+ case PowerManager.WAKE_REASON_CAMERA_LAUNCH:
+ case PowerManager.WAKE_REASON_HDMI:
+ case PowerManager.WAKE_REASON_DISPLAY_GROUP_TURNED_ON:
+ case PowerManager.WAKE_REASON_UNFOLD_DEVICE:
+ case PowerManager.WAKE_REASON_DREAM_FINISHED:
+ case PowerManager.WAKE_REASON_TILT:
+ case PowerManager.WAKE_REASON_APPLICATION:
+ case PowerManager.WAKE_REASON_PLUGGED_IN:
+ default:
+ return WakeReason.UNKNOWN;
+ }
+ }
+
+ @AuthenticateReason.Fingerprint
+ private int getAuthReason(@NonNull FingerprintAuthenticateOptions options) {
+ return AuthenticateReason.Fingerprint.UNKNOWN;
+ }
+
+ @WakeReason
+ private int getWakeReason(@NonNull FingerprintAuthenticateOptions options) {
+ return WakeReason.UNKNOWN;
+ }
+
/** {@link OperationContext#id}. */
public int getId() {
return mAidlContext.id;
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 005ad20..7b9fc36 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -74,6 +74,7 @@
@Nullable
private final TaskStackListener mTaskStackListener;
private final LockoutTracker mLockoutTracker;
+ private final O mOptions;
private final boolean mIsRestricted;
private final boolean mAllowBackgroundAuthentication;
// TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update
@@ -110,6 +111,7 @@
mAllowBackgroundAuthentication = allowBackgroundAuthentication;
mShouldUseLockoutTracker = lockoutTracker != null;
mSensorStrength = sensorStrength;
+ mOptions = options;
}
@LockoutTracker.LockoutMode
@@ -151,6 +153,11 @@
return Utils.isSettings(getContext(), getOwnerString());
}
+ /** The options requested at the start of the operation. */
+ protected O getOptions() {
+ return mOptions;
+ }
+
@Override
protected boolean isCryptoOperation() {
return mOperationId != 0;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 976f1cb..84e2fb4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -166,7 +166,7 @@
if (session.hasContextMethods()) {
return session.getSession().authenticateWithContext(
- mOperationId, getOperationContext().toAidlContext());
+ mOperationId, getOperationContext().toAidlContext(getOptions()));
} else {
return session.getSession().authenticate(mOperationId);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index e65202d..fa23ccd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -47,6 +47,7 @@
private static final String TAG = "FaceDetectClient";
private final boolean mIsStrongBiometric;
+ private final FaceAuthenticateOptions mOptions;
@Nullable private ICancellationSignal mCancellationSignal;
@Nullable private SensorPrivacyManager mSensorPrivacyManager;
@@ -74,6 +75,7 @@
setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric;
mSensorPrivacyManager = sensorPrivacyManager;
+ mOptions = options;
}
@Override
@@ -118,7 +120,7 @@
if (session.hasContextMethods()) {
return session.getSession().detectInteractionWithContext(
- getOperationContext().toAidlContext());
+ getOperationContext().toAidlContext(mOptions));
} else {
return session.getSession().detectInteraction();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 0f81f9f..435e81d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -285,7 +285,7 @@
if (session.hasContextMethods()) {
return session.getSession().authenticateWithContext(
- mOperationId, opContext.toAidlContext());
+ mOperationId, opContext.toAidlContext(getOptions()));
} else {
return session.getSession().authenticate(mOperationId);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 376d231..16d16fc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -48,6 +48,7 @@
private static final String TAG = "FingerprintDetectClient";
private final boolean mIsStrongBiometric;
+ private final FingerprintAuthenticateOptions mOptions;
@NonNull private final SensorOverlays mSensorOverlays;
@Nullable private ICancellationSignal mCancellationSignal;
@@ -66,6 +67,7 @@
mIsStrongBiometric = isStrongBiometric;
mSensorOverlays = new SensorOverlays(udfpsOverlayController,
null /* sideFpsController*/, udfpsOverlay);
+ mOptions = options;
}
@Override
@@ -105,7 +107,7 @@
if (session.hasContextMethods()) {
return session.getSession().detectInteractionWithContext(
- getOperationContext().toAidlContext());
+ getOperationContext().toAidlContext(mOptions));
} else {
return session.getSession().detectInteraction();
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 4f28432..cc41207 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -3101,6 +3101,16 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, printWriter)) return;
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ dumpInternal(printWriter);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void dumpInternal(PrintWriter printWriter) {
IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
pw.println("Current lock settings service state:");
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 9329f06..0d417e4 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -136,9 +136,7 @@
}
/**
- * @param isolated indicates if this object should <em>not</em> connect to
- * the real {@code installd}. All remote calls will be ignored
- * unless you extend this class and intercept them.
+ * @param isolated Make the installer isolated. See {@link isIsolated}.
*/
public Installer(Context context, boolean isolated) {
super(context);
@@ -153,6 +151,15 @@
mWarnIfHeld = warnIfHeld;
}
+ /**
+ * Returns true if the installer is isolated, i.e. if this object should <em>not</em> connect to
+ * the real {@code installd}. All remote calls will be ignored unless you extend this class and
+ * intercept them.
+ */
+ public boolean isIsolated() {
+ return mIsolated;
+ }
+
@Override
public void onStart() {
if (mIsolated) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 767c0a7..6a2ddc8 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import static com.android.server.pm.DexOptHelper.useArtService;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
@@ -301,6 +302,15 @@
throws InstallerException {
final StringBuilder builder = new StringBuilder();
+ if (useArtService()) {
+ if ((dexFlags & DEXOPT_SECONDARY_DEX) != 0) {
+ // installd may change the reference profile in place for secondary dex
+ // files, which isn't safe with the lock free approach in ART Service.
+ throw new IllegalArgumentException(
+ "Invalid OTA dexopt call for secondary dex");
+ }
+ }
+
// The current version. For v10, see b/115993344.
builder.append("10 ");
@@ -353,7 +363,6 @@
PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
collectingInstaller, mPackageManagerService.mInstallLock, mContext);
- // TODO(b/251903639): Allow this use of legacy dexopt code even when ART Service is enabled.
try {
optimizer.performDexOpt(pkg, pkgSetting, null /* ISAs */,
null /* CompilerStats.PackageStats */,
@@ -362,9 +371,19 @@
new DexoptOptions(pkg.getPackageName(), compilationReason,
DexoptOptions.DEXOPT_BOOT_COMPLETE));
} catch (LegacyDexoptDisabledException e) {
- throw new RuntimeException(e);
+ // OTA is still allowed to use the legacy dexopt code even when ART Service is enabled.
+ // The installer is isolated and won't call into installd, and the dexopt() method is
+ // overridden to only collect the command above. Hence we shouldn't go into any code
+ // path where this exception is thrown.
+ Slog.wtf(TAG, e);
}
+ // ART Service compat note: These commands are consumed by the otapreopt binary, which uses
+ // the same legacy dexopt code as installd to invoke dex2oat. It provides output path
+ // implementations (see calculate_odex_file_path and create_cache_path in
+ // frameworks/native/cmds/installd/otapreopt.cpp) to write to different odex files than
+ // those used by ART Service in its ordinary operations, so it doesn't interfere with ART
+ // Service even when dalvik.vm.useartservice is true.
return commands;
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 0a90e7a3..8a4080f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -18,6 +18,7 @@
import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED;
+import static com.android.server.pm.DexOptHelper.useArtService;
import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS;
@@ -329,8 +330,22 @@
String profileName = ArtManager.getProfileName(
i == 0 ? null : pkg.getSplitNames()[i - 1]);
- final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
- || packageUseInfo.isUsedByOtherApps(path);
+
+ final boolean isUsedByOtherApps;
+ if (options.isDexoptAsSharedLibrary()) {
+ isUsedByOtherApps = true;
+ } else if (useArtService()) {
+ // We get here when collecting dexopt commands in OTA preopt, even when ART Service
+ // is in use. packageUseInfo isn't useful in that case since the legacy dex use
+ // database hasn't been updated. So we'd have to query ART Service instead, but it
+ // doesn't provide that API. Just cop-out and bypass the cloud profile handling.
+ // That means such apps will get preopted wrong, and we'll leave it to a later
+ // background dexopt after reboot instead.
+ isUsedByOtherApps = false;
+ } else {
+ isUsedByOtherApps = packageUseInfo.isUsedByOtherApps(path);
+ }
+
String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter());
// If the app is used by other apps, we must not use the existing profile because it
// may contain user data, unless the profile is newly created on install.
@@ -446,6 +461,14 @@
private boolean prepareCloudProfile(AndroidPackage pkg, String profileName, String path,
@Nullable String dexMetadataPath) throws LegacyDexoptDisabledException {
if (dexMetadataPath != null) {
+ if (mInstaller.isIsolated()) {
+ // If the installer is isolated, the two calls to it below will return immediately,
+ // so this only short-circuits that a bit. We need to do it to avoid the
+ // LegacyDexoptDisabledException getting thrown first, when we get here during OTA
+ // preopt and ART Service is enabled.
+ return true;
+ }
+
try {
// Make sure we don't keep any existing contents.
mInstaller.deleteReferenceProfile(pkg.getPackageName(), profileName);
@@ -879,7 +902,12 @@
private int getDexoptNeeded(String packageName, String path, String isa, String compilerFilter,
String classLoaderContext, int profileAnalysisResult, boolean downgrade,
int dexoptFlags, String oatDir) throws LegacyDexoptDisabledException {
- Installer.checkLegacyDexoptDisabled();
+ // Allow calls from OtaDexoptService even when ART Service is in use. The installer is
+ // isolated in that case so later calls to it won't call into installd anyway.
+ if (!mInstaller.isIsolated()) {
+ Installer.checkLegacyDexoptDisabled();
+ }
+
final boolean shouldBePublic = (dexoptFlags & DEXOPT_PUBLIC) != 0;
final boolean isProfileGuidedFilter = (dexoptFlags & DEXOPT_PROFILE_GUIDED) != 0;
boolean newProfile = profileAnalysisResult == PROFILE_ANALYSIS_OPTIMIZE;
@@ -948,6 +976,8 @@
*/
private int analyseProfiles(AndroidPackage pkg, int uid, String profileName,
String compilerFilter) throws LegacyDexoptDisabledException {
+ Installer.checkLegacyDexoptDisabled();
+
// Check if we are allowed to merge and if the compiler filter is profile guided.
if (!isProfileGuidedCompilerFilter(compilerFilter)) {
return PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 928ffa7..3f9a0bc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -24,6 +24,7 @@
import static android.system.OsConstants.O_RDWR;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH;
import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
@@ -94,6 +95,7 @@
import com.android.server.IntentResolver;
import com.android.server.LocalManagerRegistry;
import com.android.server.Watchdog;
+import com.android.server.am.ActivityManagerUtils;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.pkg.AndroidPackage;
@@ -1186,12 +1188,6 @@
continue;
}
- // Only enforce filter matching if target app's target SDK >= T
- if (!compat.isChangeEnabledInternal(
- ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, info.applicationInfo)) {
- continue;
- }
-
final ParsedMainComponent comp;
if (info instanceof ActivityInfo) {
if (isReceiver) {
@@ -1210,6 +1206,10 @@
continue;
}
+ // Only enforce filter matching if target app's target SDK >= T
+ final boolean enforce = compat.isChangeEnabledInternal(
+ ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, info.applicationInfo);
+
boolean match = false;
for (int j = 0, size = comp.getIntents().size(); j < size; ++j) {
IntentFilter intentFilter = comp.getIntents().get(j).getIntentFilter();
@@ -1219,14 +1219,19 @@
}
}
if (!match) {
- Slog.w(TAG, "Intent does not match component's intent filter: " + intent);
- Slog.w(TAG, "Access blocked: " + comp.getComponentName());
- if (DEBUG_INTENT_MATCHING) {
- Slog.v(TAG, "Component intent filters:");
- comp.getIntents().forEach(f -> f.getIntentFilter().dump(logPrinter, " "));
- Slog.v(TAG, "-----------------------------");
+ ActivityManagerUtils.logUnsafeIntentEvent(
+ UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH,
+ filterCallingUid, intent, resolvedType, enforce);
+ if (enforce) {
+ Slog.w(TAG, "Intent does not match component's intent filter: " + intent);
+ Slog.w(TAG, "Access blocked: " + comp.getComponentName());
+ if (DEBUG_INTENT_MATCHING) {
+ Slog.v(TAG, "Component intent filters:");
+ comp.getIntents().forEach(f -> f.getIntentFilter().dump(logPrinter, " "));
+ Slog.v(TAG, "-----------------------------");
+ }
+ resolveInfos.remove(i);
}
- resolveInfos.remove(i);
}
}
}
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index a13c568..7ed10a4 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -18,6 +18,7 @@
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTANT;
import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING;
import static com.android.server.pm.PackageManagerService.TAG;
@@ -55,9 +56,9 @@
import com.android.internal.app.ResolverActivity;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService;
+import com.android.server.am.ActivityManagerUtils;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -130,18 +131,9 @@
boolean hasToBeExportedToMatch = platformCompat.isChangeEnabledByUid(
ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS,
filterCallingUid);
- String[] categories = intent.getCategories() == null ? new String[0]
- : intent.getCategories().toArray(String[]::new);
- FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED,
- FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH,
- filterCallingUid,
- query.get(i).getComponentInfo().getComponentName().flattenToShortString(),
- callerPackage,
- intent.getAction(),
- categories,
- resolvedType,
- intent.getScheme(),
- hasToBeExportedToMatch);
+ ActivityManagerUtils.logUnsafeIntentEvent(
+ UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH,
+ filterCallingUid, intent, resolvedType, hasToBeExportedToMatch);
if (callback != null) {
handler.post(() -> {
try {
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index f11c864..bc23020 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -12688,8 +12688,8 @@
energy = info.getControllerEnergyUsed();
if (!info.getUidTraffic().isEmpty()) {
for (UidTraffic traffic : info.getUidTraffic()) {
- uidRxBytes.incrementValue(traffic.getUid(), traffic.getRxBytes());
- uidTxBytes.incrementValue(traffic.getUid(), traffic.getTxBytes());
+ uidRxBytes.put(traffic.getUid(), traffic.getRxBytes());
+ uidTxBytes.put(traffic.getUid(), traffic.getTxBytes());
}
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 97b7811..370d21f 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -137,7 +137,8 @@
remoteCredentialService);
mCompleteRequest = completeCreateRequest;
setStatus(Status.PENDING);
- mProviderResponseDataHandler = new ProviderResponseDataHandler(hybridService);
+ mProviderResponseDataHandler = new ProviderResponseDataHandler(
+ ComponentName.unflattenFromString(hybridService));
}
@Override
@@ -297,21 +298,23 @@
}
private class ProviderResponseDataHandler {
- private final ComponentName mExpectedRemoteEntryProviderService;
+ @Nullable private final ComponentName mExpectedRemoteEntryProviderService;
@NonNull
private final Map<String, Pair<CreateEntry, Entry>> mUiCreateEntries = new HashMap<>();
@Nullable private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null;
- ProviderResponseDataHandler(String hybridService) {
- mExpectedRemoteEntryProviderService = ComponentName.unflattenFromString(hybridService);
+ ProviderResponseDataHandler(@Nullable ComponentName expectedRemoteEntryProviderService) {
+ mExpectedRemoteEntryProviderService = expectedRemoteEntryProviderService;
}
public void addResponseContent(List<CreateEntry> createEntries,
RemoteEntry remoteEntry) {
createEntries.forEach(this::addCreateEntry);
- setRemoteEntry(remoteEntry);
+ if (remoteEntry != null) {
+ setRemoteEntry(remoteEntry);
+ }
}
public void addCreateEntry(CreateEntry createEntry) {
String id = generateUniqueId();
@@ -321,13 +324,13 @@
}
public void setRemoteEntry(@Nullable RemoteEntry remoteEntry) {
- if (remoteEntry == null) {
- mUiRemoteEntry = null;
+ if (!enforceRemoteEntryRestrictions(mExpectedRemoteEntryProviderService)) {
+ Log.i(TAG, "Remote entry being dropped as it does not meet the restriction"
+ + "checks.");
return;
}
- if (!mComponentName.equals(mExpectedRemoteEntryProviderService)) {
- Log.i(TAG, "Remote entry being dropped as it is not from the service "
- + "configured by the OEM.");
+ if (remoteEntry == null) {
+ mUiRemoteEntry = null;
return;
}
String id = generateUniqueId();
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index ee813e9..80a61b9 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -181,7 +181,6 @@
/** Called when the provider response has been updated by an external source. */
@Override // Callback from the remote provider
public void onProviderResponseSuccess(@Nullable BeginGetCredentialResponse response) {
- Log.i(TAG, "in onProviderResponseSuccess");
onSetInitialRemoteResponse(response);
}
@@ -393,7 +392,7 @@
.extractResponseContent(providerPendingIntentResponse
.getResultData());
if (response != null && !mProviderResponseDataHandler.isEmptyResponse(response)) {
- addToInitialRemoteResponse(response);
+ addToInitialRemoteResponse(response, /*isInitialResponse=*/ false);
// Additional content received is in the form of new response content.
return true;
}
@@ -401,7 +400,8 @@
return false;
}
- private void addToInitialRemoteResponse(BeginGetCredentialResponse content) {
+ private void addToInitialRemoteResponse(BeginGetCredentialResponse content,
+ boolean isInitialResponse) {
if (content == null) {
return;
}
@@ -409,7 +409,8 @@
content.getCredentialEntries(),
content.getActions(),
content.getAuthenticationActions(),
- content.getRemoteCredentialEntry()
+ content.getRemoteCredentialEntry(),
+ isInitialResponse
);
}
@@ -424,7 +425,7 @@
/** Updates the response being maintained in state by this provider session. */
private void onSetInitialRemoteResponse(BeginGetCredentialResponse response) {
mProviderResponse = response;
- addToInitialRemoteResponse(response);
+ addToInitialRemoteResponse(response, /*isInitialResponse=*/true);
if (mProviderResponseDataHandler.isEmptyResponse(response)) {
updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE);
return;
@@ -463,7 +464,7 @@
}
private class ProviderResponseDataHandler {
- private final ComponentName mExpectedRemoteEntryProviderService;
+ @Nullable private final ComponentName mExpectedRemoteEntryProviderService;
@NonNull
private final Map<String, Pair<CredentialEntry, Entry>> mUiCredentialEntries =
new HashMap<>();
@@ -475,19 +476,27 @@
@Nullable private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null;
- ProviderResponseDataHandler(ComponentName expectedRemoteEntryProviderService) {
+ ProviderResponseDataHandler(@Nullable ComponentName expectedRemoteEntryProviderService) {
mExpectedRemoteEntryProviderService = expectedRemoteEntryProviderService;
}
public void addResponseContent(List<CredentialEntry> credentialEntries,
List<Action> actions, List<Action> authenticationActions,
- RemoteEntry remoteEntry) {
+ RemoteEntry remoteEntry, boolean isInitialResponse) {
credentialEntries.forEach(this::addCredentialEntry);
actions.forEach(this::addAction);
authenticationActions.forEach(
authenticationAction -> addAuthenticationAction(authenticationAction,
AuthenticationEntry.STATUS_LOCKED));
- setRemoteEntry(remoteEntry);
+ // In the query phase, it is likely most providers will return a null remote entry
+ // so no need to invoke the setter since it adds the overhead of checking for the
+ // hybrid permission, and then sets an already null value to null.
+ // If this is not the query phase, e.g. response after a locked entry is unlocked
+ // then it is valid for the provider to remove the remote entry, and so we allow
+ // them to set it to null.
+ if (remoteEntry != null || !isInitialResponse) {
+ setRemoteEntry(remoteEntry);
+ }
}
public void addCredentialEntry(CredentialEntry credentialEntry) {
String id = generateUniqueId();
@@ -524,12 +533,13 @@
}
public void setRemoteEntry(@Nullable RemoteEntry remoteEntry) {
- if (remoteEntry == null) {
+ if (!enforceRemoteEntryRestrictions(mExpectedRemoteEntryProviderService)) {
+ Log.i(TAG, "Remote entry being dropped as it does not meet the restriction"
+ + " checks.");
return;
}
- if (!mComponentName.equals(mExpectedRemoteEntryProviderService)) {
- Log.i(TAG, "Remote entry being dropped as it is not from the service "
- + "configured by the OEM.");
+ if (remoteEntry == null) {
+ mUiRemoteEntry = null;
return;
}
String id = generateUniqueId();
@@ -538,6 +548,8 @@
mUiRemoteEntry = new Pair<>(generateUniqueId(), new Pair<>(remoteEntry, entry));
}
+
+
public GetCredentialProviderData toGetCredentialProviderData() {
return new GetCredentialProviderData.Builder(
mComponentName.flattenToString()).setActionChips(prepareActionEntries())
@@ -571,7 +583,6 @@
return credEntries;
}
-
private Entry prepareRemoteEntry() {
if (mUiRemoteEntry == null || mUiRemoteEntry.first == null
|| mUiRemoteEntry.second == null) {
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index ecddcf3..53ed070 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -19,10 +19,13 @@
import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_QUERY_FAILURE;
import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_QUERY_SUCCESS;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.credentials.Credential;
import android.credentials.ui.ProviderData;
import android.credentials.ui.ProviderPendingIntentResponse;
@@ -228,6 +231,39 @@
return mProviderResponse;
}
+ protected boolean enforceRemoteEntryRestrictions(
+ @Nullable ComponentName expectedRemoteEntryProviderService) {
+ // Check if the service is the one set by the OEM. If not silently reject this entry
+ if (!mComponentName.equals(expectedRemoteEntryProviderService)) {
+ Log.i(TAG, "Remote entry being dropped as it is not from the service "
+ + "configured by the OEM.");
+ return false;
+ }
+ // Check if the service has the hybrid permission .If not, silently reject this entry.
+ // This check is in addition to the permission check happening in the provider's process.
+ try {
+ ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(
+ mComponentName.getPackageName(),
+ PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY));
+ if (appInfo != null
+ && mContext.checkPermission(
+ Manifest.permission.PROVIDE_REMOTE_CREDENTIALS,
+ /*pId=*/-1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ } catch (SecurityException e) {
+ Log.i(TAG, "Error getting info for "
+ + mComponentName.flattenToString() + ": " + e.getMessage());
+ return false;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.i(TAG, "Error getting info for "
+ + mComponentName.flattenToString() + ": " + e.getMessage());
+ return false;
+ }
+ Log.i(TAG, "In enforceRemoteEntryRestrictions - remote entry checks fail");
+ return false;
+ }
+
/** Should be overridden to prepare, and stores state for {@link ProviderData} to be
* shown on the UI. */
@Nullable protected abstract ProviderData prepareUiData();
diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
index 702261e..ff4e3b6 100644
--- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
+++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
@@ -121,8 +121,6 @@
ProviderCallbacks<BeginGetCredentialResponse> callback) {
Log.i(TAG, "In onGetCredentials in RemoteCredentialService");
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
- AtomicReference<CompletableFuture<BeginGetCredentialResponse>> futureRef =
- new AtomicReference<>();
CompletableFuture<BeginGetCredentialResponse> connectThenExecute = postAsync(service -> {
CompletableFuture<BeginGetCredentialResponse> getCredentials =
@@ -134,7 +132,6 @@
new IBeginGetCredentialCallback.Stub() {
@Override
public void onSuccess(BeginGetCredentialResponse response) {
- Log.i(TAG, "In onSuccess in RemoteCredentialService");
getCredentials.complete(response);
}
@@ -147,22 +144,15 @@
new GetCredentialException(errorType, errorMsg));
}
});
- CompletableFuture<BeginGetCredentialResponse> future = futureRef.get();
- if (future != null && future.isCancelled()) {
- dispatchCancellationSignal(cancellationSignal);
- } else {
- cancellationSink.set(cancellationSignal);
- }
+ cancellationSink.set(cancellationSignal);
return getCredentials;
} finally {
Binder.restoreCallingIdentity(originalCallingUidToken);
}
}).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
- futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
handleExecutionResponse(result, error, cancellationSink, callback)));
-
return cancellationSink.get();
}
@@ -178,8 +168,6 @@
ProviderCallbacks<BeginCreateCredentialResponse> callback) {
Log.i(TAG, "In onCreateCredential in RemoteCredentialService");
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
- AtomicReference<CompletableFuture<BeginCreateCredentialResponse>> futureRef =
- new AtomicReference<>();
CompletableFuture<BeginCreateCredentialResponse> connectThenExecute =
postAsync(service -> {
@@ -205,19 +193,13 @@
new CreateCredentialException(errorType, errorMsg));
}
});
- CompletableFuture<BeginCreateCredentialResponse> future = futureRef.get();
- if (future != null && future.isCancelled()) {
- dispatchCancellationSignal(cancellationSignal);
- } else {
- cancellationSink.set(cancellationSignal);
- }
+ cancellationSink.set(cancellationSignal);
return createCredentialFuture;
} finally {
Binder.restoreCallingIdentity(originalCallingUidToken);
}
}).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
- futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
handleExecutionResponse(result, error, cancellationSink, callback)));
@@ -236,7 +218,6 @@
ProviderCallbacks<Void> callback) {
Log.i(TAG, "In onClearCredentialState in RemoteCredentialService");
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
- AtomicReference<CompletableFuture<Void>> futureRef = new AtomicReference<>();
CompletableFuture<Void> connectThenExecute =
postAsync(service -> {
@@ -263,19 +244,13 @@
errorMsg));
}
});
- CompletableFuture<Void> future = futureRef.get();
- if (future != null && future.isCancelled()) {
- dispatchCancellationSignal(cancellationSignal);
- } else {
- cancellationSink.set(cancellationSignal);
- }
+ cancellationSink.set(cancellationSignal);
return clearCredentialFuture;
} finally {
Binder.restoreCallingIdentity(originalCallingUidToken);
}
}).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
- futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
handleExecutionResponse(result, error, cancellationSink, callback)));
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
index 3ff802c..6b0e330 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.face.aidl;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -30,11 +32,15 @@
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
+import android.hardware.biometrics.common.AuthenticateReason;
import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.common.OperationContext;
+import android.hardware.biometrics.common.WakeReason;
import android.hardware.biometrics.face.ISession;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticateOptions;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;
@@ -69,6 +75,8 @@
private static final int USER_ID = 12;
private static final long OP_ID = 32;
+ private static final int WAKE_REASON = WakeReason.LIFT;
+ private static final int AUTH_REASON = AuthenticateReason.Face.ASSISTANT_VISIBLE;
@Rule
public final TestableContext mContext = new TestableContext(
@@ -126,8 +134,13 @@
InOrder order = inOrder(mHal, mBiometricContext);
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
- order.verify(mHal).authenticateWithContext(
- eq(OP_ID), same(mOperationContextCaptor.getValue().toAidlContext()));
+
+ final OperationContext aidlContext = mOperationContextCaptor.getValue().toAidlContext();
+ order.verify(mHal).authenticateWithContext(eq(OP_ID), same(aidlContext));
+ assertThat(aidlContext.wakeReason).isEqualTo(WAKE_REASON);
+ assertThat(aidlContext.authenticateReason.getFaceAuthenticateReason())
+ .isEqualTo(AUTH_REASON);
+
verify(mHal, never()).authenticate(anyLong());
}
@@ -156,8 +169,11 @@
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
final FaceAuthenticateOptions options = new FaceAuthenticateOptions.Builder()
.setOpPackageName("test-owner")
- .setUserId(5)
+ .setUserId(USER_ID)
.setSensorId(9)
+ .setWakeReason(PowerManager.WAKE_REASON_LIFT)
+ .setAuthenticateReason(
+ FaceAuthenticateOptions.AUTHENTICATE_REASON_ASSISTANT_VISIBLE)
.build();
return new FaceAuthenticationClient(mContext, () -> aidl, mToken,
2 /* requestId */, mClientMonitorCallbackConverter, OP_ID,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
index c4c5505..0abfa7e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.face.aidl;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.inOrder;
@@ -24,9 +26,13 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.biometrics.common.AuthenticateReason;
+import android.hardware.biometrics.common.OperationContext;
+import android.hardware.biometrics.common.WakeReason;
import android.hardware.biometrics.face.ISession;
import android.hardware.face.FaceAuthenticateOptions;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;
@@ -55,6 +61,8 @@
public class FaceDetectClientTest {
private static final int USER_ID = 12;
+ private static final int WAKE_REASON = WakeReason.POWER_BUTTON;
+ private static final int AUTH_REASON = AuthenticateReason.Face.OCCLUDING_APP_REQUESTED;
@Rule
public final TestableContext mContext = new TestableContext(
@@ -103,8 +111,13 @@
InOrder order = inOrder(mHal, mBiometricContext);
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
- order.verify(mHal).detectInteractionWithContext(
- same(mOperationContextCaptor.getValue().toAidlContext()));
+
+ final OperationContext aidlContext = mOperationContextCaptor.getValue().toAidlContext();
+ order.verify(mHal).detectInteractionWithContext(same(aidlContext));
+ assertThat(aidlContext.wakeReason).isEqualTo(WAKE_REASON);
+ assertThat(aidlContext.authenticateReason.getFaceAuthenticateReason())
+ .isEqualTo(AUTH_REASON);
+
verify(mHal, never()).detectInteraction();
}
@@ -118,6 +131,9 @@
.setUserId(USER_ID)
.setSensorId(5)
.setOpPackageName("own-it")
+ .setWakeReason(PowerManager.WAKE_REASON_POWER_BUTTON)
+ .setAuthenticateReason(
+ FaceAuthenticateOptions.AUTHENTICATE_REASON_OCCLUDING_APP_REQUESTED)
.build(),
mBiometricLogger, mBiometricContext,
false /* isStrongBiometric */, null /* sensorPrivacyManager */);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index f0f975c..c664500 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -36,6 +36,7 @@
import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.common.AuthenticateReason;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.ISession;
@@ -165,8 +166,12 @@
InOrder order = inOrder(mHal, mBiometricContext);
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
- order.verify(mHal).authenticateWithContext(
- eq(OP_ID), same(mOperationContextCaptor.getValue().toAidlContext()));
+
+ final OperationContext aidlContext = mOperationContextCaptor.getValue().toAidlContext();
+ order.verify(mHal).authenticateWithContext(eq(OP_ID), same(aidlContext));
+ assertThat(aidlContext.authenticateReason.getFingerprintAuthenticateReason())
+ .isEqualTo(AuthenticateReason.Fingerprint.UNKNOWN);
+
verify(mHal, never()).authenticate(anyLong());
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
index e741e44..c20cc39 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.inOrder;
@@ -24,6 +26,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.biometrics.common.AuthenticateReason;
+import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -108,8 +112,12 @@
InOrder order = inOrder(mHal, mBiometricContext);
order.verify(mBiometricContext).updateContext(
mOperationContextCaptor.capture(), anyBoolean());
- order.verify(mHal).detectInteractionWithContext(
- same(mOperationContextCaptor.getValue().toAidlContext()));
+
+ final OperationContext aidlContext = mOperationContextCaptor.getValue().toAidlContext();
+ order.verify(mHal).detectInteractionWithContext(same(aidlContext));
+ assertThat(aidlContext.authenticateReason.getFingerprintAuthenticateReason())
+ .isEqualTo(AuthenticateReason.Fingerprint.UNKNOWN);
+
verify(mHal, never()).detectInteraction();
}
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java
index c6a7fbc..ee4b839 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java
@@ -572,41 +572,14 @@
mBatteryStatsImpl.noteBluetoothScanStoppedFromSourceLocked(ws, true, 9000, 9000);
mBatteryStatsImpl.noteBluetoothScanResultsFromSourceLocked(ws, 42, 9000, 9000);
-
-
- final Parcel uidTrafficParcel1 = Parcel.obtain();
- final Parcel uidTrafficParcel2 = Parcel.obtain();
-
- uidTrafficParcel1.writeInt(10042);
- uidTrafficParcel1.writeLong(3000);
- uidTrafficParcel1.writeLong(4000);
- uidTrafficParcel1.setDataPosition(0);
- uidTrafficParcel2.writeInt(10043);
- uidTrafficParcel2.writeLong(5000);
- uidTrafficParcel2.writeLong(8000);
- uidTrafficParcel2.setDataPosition(0);
-
- List<UidTraffic> uidTrafficList = ImmutableList.of(
- UidTraffic.CREATOR.createFromParcel(uidTrafficParcel1),
- UidTraffic.CREATOR.createFromParcel(uidTrafficParcel2));
-
- final Parcel btActivityEnergyInfoParcel = Parcel.obtain();
- btActivityEnergyInfoParcel.writeLong(1000);
- btActivityEnergyInfoParcel.writeInt(
- BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE);
- btActivityEnergyInfoParcel.writeLong(9000);
- btActivityEnergyInfoParcel.writeLong(8000);
- btActivityEnergyInfoParcel.writeLong(12000);
- btActivityEnergyInfoParcel.writeLong(0);
- btActivityEnergyInfoParcel.writeTypedList(uidTrafficList);
- btActivityEnergyInfoParcel.setDataPosition(0);
-
- BluetoothActivityEnergyInfo info = BluetoothActivityEnergyInfo.CREATOR
- .createFromParcel(btActivityEnergyInfoParcel);
-
- uidTrafficParcel1.recycle();
- uidTrafficParcel2.recycle();
- btActivityEnergyInfoParcel.recycle();
+ BluetoothActivityEnergyInfo info = createBluetoothActivityEnergyInfo(
+ /* timestamp= */ 1000,
+ /* controllerTxTimeMs= */ 9000,
+ /* controllerRxTimeMs= */ 8000,
+ /* controllerIdleTimeMs= */ 12000,
+ /* controllerEnergyUsed= */ 0,
+ createUidTraffic(/* appUid= */ 10042, /* rxBytes= */ 3000, /* txBytes= */ 4000),
+ createUidTraffic(/* appUid= */ 10043, /* rxBytes= */ 5000, /* txBytes= */ 8000));
mBatteryStatsImpl.updateBluetoothStateLocked(info, -1, 1000, 1000);
@@ -622,4 +595,105 @@
assertThat(uidStats.rxTimeMs).isEqualTo(7375); // Some scan time is treated as RX
assertThat(uidStats.txTimeMs).isEqualTo(7666); // Some scan time is treated as TX
}
+
+ /** A regression test for b/266128651 */
+ @Test
+ public void testGetNetworkActivityBytes_multipleUpdates() {
+ when(mPowerProfile.getAveragePower(
+ PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE)).thenReturn(3.0);
+ mBatteryStatsImpl.setOnBatteryInternal(true);
+ mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+
+ BluetoothActivityEnergyInfo info1 = createBluetoothActivityEnergyInfo(
+ /* timestamp= */ 10000,
+ /* controllerTxTimeMs= */ 9000,
+ /* controllerRxTimeMs= */ 8000,
+ /* controllerIdleTimeMs= */ 2000,
+ /* controllerEnergyUsed= */ 0,
+ createUidTraffic(/* appUid= */ 10042, /* rxBytes= */ 3000, /* txBytes= */ 4000),
+ createUidTraffic(/* appUid= */ 10043, /* rxBytes= */ 5000, /* txBytes= */ 8000));
+
+ mBatteryStatsImpl.updateBluetoothStateLocked(info1, -1, 1000, 1000);
+
+ long totalRx1 = mBatteryStatsImpl.getNetworkActivityBytes(
+ BatteryStats.NETWORK_BT_RX_DATA, BatteryStats.STATS_SINCE_CHARGED);
+ long totalTx1 = mBatteryStatsImpl.getNetworkActivityBytes(
+ BatteryStats.NETWORK_BT_TX_DATA, BatteryStats.STATS_SINCE_CHARGED);
+
+ assertThat(totalRx1).isEqualTo(8000); // 3000 + 5000
+ assertThat(totalTx1).isEqualTo(12000); // 4000 + 8000
+
+ BluetoothActivityEnergyInfo info2 = createBluetoothActivityEnergyInfo(
+ /* timestamp= */ 20000,
+ /* controllerTxTimeMs= */ 19000,
+ /* controllerRxTimeMs= */ 18000,
+ /* controllerIdleTimeMs= */ 3000,
+ /* controllerEnergyUsed= */ 0,
+ createUidTraffic(/* appUid= */ 10043, /* rxBytes= */ 6000, /* txBytes= */ 9500),
+ createUidTraffic(/* appUid= */ 10044, /* rxBytes= */ 7000, /* txBytes= */ 9000));
+
+ mBatteryStatsImpl.updateBluetoothStateLocked(info2, -1, 2000, 2000);
+
+ long totalRx2 = mBatteryStatsImpl.getNetworkActivityBytes(
+ BatteryStats.NETWORK_BT_RX_DATA, BatteryStats.STATS_SINCE_CHARGED);
+ long totalTx2 = mBatteryStatsImpl.getNetworkActivityBytes(
+ BatteryStats.NETWORK_BT_TX_DATA, BatteryStats.STATS_SINCE_CHARGED);
+
+ assertThat(totalRx2).isEqualTo(16000); // 3000 + 6000 (updated) + 7000 (new)
+ assertThat(totalTx2).isEqualTo(22500); // 4000 + 9500 (updated) + 9000 (new)
+
+ BluetoothActivityEnergyInfo info3 = createBluetoothActivityEnergyInfo(
+ /* timestamp= */ 30000,
+ /* controllerTxTimeMs= */ 20000,
+ /* controllerRxTimeMs= */ 20000,
+ /* controllerIdleTimeMs= */ 4000,
+ /* controllerEnergyUsed= */ 0,
+ createUidTraffic(/* appUid= */ 10043, /* rxBytes= */ 7000, /* txBytes= */ 9900),
+ createUidTraffic(/* appUid= */ 10044, /* rxBytes= */ 8000, /* txBytes= */ 10000));
+
+ mBatteryStatsImpl.updateBluetoothStateLocked(info3, -1, 2000, 2000);
+
+ long totalRx3 = mBatteryStatsImpl.getNetworkActivityBytes(
+ BatteryStats.NETWORK_BT_RX_DATA, BatteryStats.STATS_SINCE_CHARGED);
+ long totalTx3 = mBatteryStatsImpl.getNetworkActivityBytes(
+ BatteryStats.NETWORK_BT_TX_DATA, BatteryStats.STATS_SINCE_CHARGED);
+
+ assertThat(totalRx3).isEqualTo(18000); // 3000 + 7000 (updated) + 8000 (updated)
+ assertThat(totalTx3).isEqualTo(23900); // 4000 + 9900 (updated) + 10000 (updated)
+ }
+
+ private UidTraffic createUidTraffic(int appUid, long rxBytes, long txBytes) {
+ final Parcel parcel = Parcel.obtain();
+ parcel.writeInt(appUid); // mAppUid
+ parcel.writeLong(rxBytes); // mRxBytes
+ parcel.writeLong(txBytes); // mTxBytes
+ parcel.setDataPosition(0);
+ UidTraffic uidTraffic = UidTraffic.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+ return uidTraffic;
+ }
+
+ private BluetoothActivityEnergyInfo createBluetoothActivityEnergyInfo(
+ long timestamp,
+ long controllerTxTimeMs,
+ long controllerRxTimeMs,
+ long controllerIdleTimeMs,
+ long controllerEnergyUsed,
+ UidTraffic... uidTraffic) {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeLong(timestamp); // mTimestamp
+ parcel.writeInt(
+ BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE); // mBluetoothStackState
+ parcel.writeLong(controllerTxTimeMs); // mControllerTxTimeMs;
+ parcel.writeLong(controllerRxTimeMs); // mControllerRxTimeMs;
+ parcel.writeLong(controllerIdleTimeMs); // mControllerIdleTimeMs;
+ parcel.writeLong(controllerEnergyUsed); // mControllerEnergyUsed;
+ parcel.writeTypedList(ImmutableList.copyOf(uidTraffic)); // mUidTraffic
+ parcel.setDataPosition(0);
+
+ BluetoothActivityEnergyInfo info =
+ BluetoothActivityEnergyInfo.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+ return info;
+ }
}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
index 2cdb945..7deb8c7 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
@@ -86,7 +86,7 @@
mFile = testContext.getFileStreamPath("tracing_test.dat");
//noinspection ResultOfMethodCallIgnored
mFile.delete();
- mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader);
+ mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader, 1024);
}
@After
diff --git a/tools/codegen/Android.bp b/tools/codegen/Android.bp
index e53ba3e..a1df878 100644
--- a/tools/codegen/Android.bp
+++ b/tools/codegen/Android.bp
@@ -9,7 +9,7 @@
java_binary_host {
name: "codegen_cli",
- manifest: "manifest.txt",
+ main_class: "com.android.codegen.MainKt",
srcs: [
"src/**/*.kt",
],
diff --git a/tools/codegen/BUILD.bazel b/tools/codegen/BUILD.bazel
deleted file mode 100644
index c14046d..0000000
--- a/tools/codegen/BUILD.bazel
+++ /dev/null
@@ -1,21 +0,0 @@
-# TODO(b/245731902): auto-generate these with bp2build.
-load("@rules_kotlin//kotlin:jvm_library.bzl", "kt_jvm_library")
-
-java_binary(
- name = "codegen_cli",
- main_class = "com.android.codegen.MainKt",
- runtime_deps = [
- ":codegen_cli_kt_lib",
- ],
-)
-
-kt_jvm_library(
- name = "codegen_cli_kt_lib",
- srcs = glob(["src/**/*.kt"]),
- deps = ["//external/javaparser"],
-)
-
-kt_jvm_library(
- name = "codegen-version-info",
- srcs = glob(["src/**/SharedConstants.kt"]),
-)
diff --git a/tools/codegen/manifest.txt b/tools/codegen/manifest.txt
deleted file mode 100644
index 6e1018b..0000000
--- a/tools/codegen/manifest.txt
+++ /dev/null
@@ -1 +0,0 @@
-Main-class: com.android.codegen.MainKt