Merge "Add new metric for SMS Mirroring Setting."
diff --git a/api/current.txt b/api/current.txt
index fe309dd..f1fa678 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36950,7 +36950,7 @@
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
- public final class CharSequenceTransformation implements android.os.Parcelable {
+ public final class CharSequenceTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.CharSequenceTransformation> CREATOR;
@@ -37047,7 +37047,7 @@
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
- public final class ImageTransformation implements android.os.Parcelable {
+ public final class ImageTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.ImageTransformation> CREATOR;
@@ -37059,7 +37059,7 @@
method public android.service.autofill.ImageTransformation build();
}
- public final class LuhnChecksumValidator implements android.os.Parcelable {
+ public final class LuhnChecksumValidator implements android.os.Parcelable android.service.autofill.Validator {
ctor public LuhnChecksumValidator(android.view.autofill.AutofillId...);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -37105,7 +37105,7 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
- public final class SimpleRegexValidator implements android.os.Parcelable {
+ public final class SimpleRegexValidator implements android.os.Parcelable android.service.autofill.Validator {
ctor public SimpleRegexValidator(android.view.autofill.AutofillId, java.lang.String);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index efe7288..cc414bc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -40031,7 +40031,7 @@
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
- public final class CharSequenceTransformation implements android.os.Parcelable {
+ public final class CharSequenceTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.CharSequenceTransformation> CREATOR;
@@ -40128,7 +40128,7 @@
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
- public final class ImageTransformation implements android.os.Parcelable {
+ public final class ImageTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.ImageTransformation> CREATOR;
@@ -40140,7 +40140,7 @@
method public android.service.autofill.ImageTransformation build();
}
- public final class LuhnChecksumValidator implements android.os.Parcelable {
+ public final class LuhnChecksumValidator implements android.os.Parcelable android.service.autofill.Validator {
ctor public LuhnChecksumValidator(android.view.autofill.AutofillId...);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -40186,7 +40186,7 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
- public final class SimpleRegexValidator implements android.os.Parcelable {
+ public final class SimpleRegexValidator implements android.os.Parcelable android.service.autofill.Validator {
ctor public SimpleRegexValidator(android.view.autofill.AutofillId, java.lang.String);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 10a3ba0..c1116da 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -37123,7 +37123,7 @@
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
- public final class CharSequenceTransformation implements android.os.Parcelable {
+ public final class CharSequenceTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -37221,7 +37221,7 @@
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
- public final class ImageTransformation implements android.os.Parcelable {
+ public final class ImageTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -37234,7 +37234,7 @@
method public android.service.autofill.ImageTransformation build();
}
- public final class LuhnChecksumValidator implements android.os.Parcelable {
+ public final class LuhnChecksumValidator implements android.os.Parcelable android.service.autofill.Validator {
ctor public LuhnChecksumValidator(android.view.autofill.AutofillId...);
method public int describeContents();
method public boolean isValid(android.service.autofill.ValueFinder);
@@ -37281,9 +37281,10 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
- public final class SimpleRegexValidator implements android.os.Parcelable {
+ public final class SimpleRegexValidator implements android.os.Parcelable android.service.autofill.Validator {
ctor public SimpleRegexValidator(android.view.autofill.AutofillId, java.lang.String);
method public int describeContents();
+ method public boolean isValid(android.service.autofill.ValueFinder);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.SimpleRegexValidator> CREATOR;
}
diff --git a/core/java/android/service/autofill/CharSequenceTransformation.java b/core/java/android/service/autofill/CharSequenceTransformation.java
index 9d8345c..3ff36aa 100644
--- a/core/java/android/service/autofill/CharSequenceTransformation.java
+++ b/core/java/android/service/autofill/CharSequenceTransformation.java
@@ -55,7 +55,8 @@
* .addField(ccExpYearId, "^(\\d\\d\\d\\d)$", " / $1");
* </pre>
*/
-public final class CharSequenceTransformation extends InternalTransformation implements Parcelable {
+public final class CharSequenceTransformation extends InternalTransformation implements
+ Transformation, Parcelable {
private static final String TAG = "CharSequenceTransformation";
@NonNull private final ArrayMap<AutofillId, Pair<Pattern, String>> mFields;
diff --git a/core/java/android/service/autofill/CustomDescription.java b/core/java/android/service/autofill/CustomDescription.java
index 51530d6..e97c364 100644
--- a/core/java/android/service/autofill/CustomDescription.java
+++ b/core/java/android/service/autofill/CustomDescription.java
@@ -78,7 +78,6 @@
* <p>See {@link ImageTransformation}, {@link CharSequenceTransformation} for more info about these
* transformations.
*/
-// TODO(b/62534917): add integration tests
public final class CustomDescription implements Parcelable {
private static final String TAG = "CustomDescription";
@@ -93,7 +92,6 @@
/** @hide */
public RemoteViews getPresentation(ValueFinder finder) {
- // TODO(b/62534917): need to handler errors, like not finding the ID
if (mTransformations != null) {
final int size = mTransformations.size();
if (sDebug) Log.d(TAG, "getPresentation(): applying " + size + " transformations");
@@ -101,7 +99,13 @@
final int id = mTransformations.keyAt(i);
final InternalTransformation transformation = mTransformations.valueAt(i);
if (sDebug) Log.d(TAG, "#" + i + ": " + transformation);
- transformation.apply(finder, mPresentation, id);
+
+ try {
+ transformation.apply(finder, mPresentation, id);
+ } catch (Exception e) {
+ Log.e(TAG, "Could not apply transformation " + transformation + ". "
+ + e.getClass());
+ }
}
}
return mPresentation;
diff --git a/core/java/android/service/autofill/ImageTransformation.java b/core/java/android/service/autofill/ImageTransformation.java
index 5407ad0..4c04e17 100644
--- a/core/java/android/service/autofill/ImageTransformation.java
+++ b/core/java/android/service/autofill/ImageTransformation.java
@@ -51,7 +51,8 @@
* <p>There is no imposed limit in the number of options, but keep in mind that regexs are
* expensive to evaluate, so use the minimum number of regexs.
*/
-public final class ImageTransformation extends InternalTransformation implements Parcelable {
+public final class ImageTransformation extends InternalTransformation implements Transformation,
+ Parcelable {
private static final String TAG = "ImageTransformation";
private final AutofillId mId;
@@ -102,7 +103,8 @@
*
* @param id id of the screen field that will be used to evaluate whether the image should
* be used.
- * @param regex regular expression defining what should be matched to use this image.
+ * @param regex regular expression defining what should be matched to use this image. The
+ * pattern will be {@link Pattern#compile compiled} without setting any flags.
* @param resId resource id of the image (in the autofill service's package). The
* {@link RemoteViews presentation} must contain a {@link ImageView} child with that id.
*/
@@ -115,7 +117,8 @@
/**
* Adds an option to replace the child view with a different image when the regex matches.
*
- * @param regex regular expression defining what should be matched to use this image.
+ * @param regex regular expression defining what should be matched to use this image. The
+ * pattern will be {@link Pattern#compile compiled} without setting any flags.
* @param resId resource id of the image (in the autofill service's package). The
* {@link RemoteViews presentation} must contain a {@link ImageView} child with that id.
*
diff --git a/core/java/android/service/autofill/InternalTransformation.java b/core/java/android/service/autofill/InternalTransformation.java
index 3e51f87..e8ac14a 100644
--- a/core/java/android/service/autofill/InternalTransformation.java
+++ b/core/java/android/service/autofill/InternalTransformation.java
@@ -19,11 +19,17 @@
import android.os.Parcelable;
import android.widget.RemoteViews;
-/** @hide */
+/**
+ * Superclass of all transformation the system understands. As this is not public all
+ * subclasses have to implement {@link Transformation} again.
+ *
+ * @hide
+ */
abstract class InternalTransformation implements Transformation, Parcelable {
/**
- * Applies this transformation to a child view of a {@link RemoteViews presentation template}.
+ * Applies this transformation to a child view of a {@link android.widget.RemoteViews
+ * presentation template}.
*
* @param finder object used to find the value of a field in the screen.
* @param template the {@link RemoteViews presentation template}.
diff --git a/core/java/android/service/autofill/InternalValidator.java b/core/java/android/service/autofill/InternalValidator.java
index 37ef96f..e11cf6a 100644
--- a/core/java/android/service/autofill/InternalValidator.java
+++ b/core/java/android/service/autofill/InternalValidator.java
@@ -18,7 +18,12 @@
import android.annotation.NonNull;
import android.os.Parcelable;
-/** @hide */
+/**
+ * Superclass of all validators the system understands. As this is not public all public subclasses
+ * have to implement {@link Validator} again.
+ *
+ * @hide
+ */
public abstract class InternalValidator implements Validator, Parcelable {
/**
diff --git a/core/java/android/service/autofill/LuhnChecksumValidator.java b/core/java/android/service/autofill/LuhnChecksumValidator.java
index f959f3b9..0b5930d 100644
--- a/core/java/android/service/autofill/LuhnChecksumValidator.java
+++ b/core/java/android/service/autofill/LuhnChecksumValidator.java
@@ -33,7 +33,8 @@
*
* <p>See {@link SaveInfo.Builder#setValidator(Validator)} for examples.
*/
-public final class LuhnChecksumValidator extends InternalValidator implements Parcelable {
+public final class LuhnChecksumValidator extends InternalValidator implements Validator,
+ Parcelable {
private static final String TAG = "LuhnChecksumValidator";
private final AutofillId[] mIds;
diff --git a/core/java/android/service/autofill/OptionalValidators.java b/core/java/android/service/autofill/OptionalValidators.java
index c9dd1d4..f7edd6e 100644
--- a/core/java/android/service/autofill/OptionalValidators.java
+++ b/core/java/android/service/autofill/OptionalValidators.java
@@ -34,7 +34,7 @@
*/
final class OptionalValidators extends InternalValidator {
- private final InternalValidator[] mValidators;
+ @NonNull private final InternalValidator[] mValidators;
OptionalValidators(@NonNull InternalValidator[] validators) {
mValidators = Preconditions.checkArrayElementsNotNull(validators, "validators");
@@ -42,11 +42,6 @@
@Override
public boolean isValid(@NonNull ValueFinder finder) {
- if (mValidators == null) {
- return true;
- }
- // TODO(b/62534917): handle errors, like not finding the ID
-
for (InternalValidator validator : mValidators) {
final boolean valid = validator.isValid(finder);
if (valid) return true;
diff --git a/core/java/android/service/autofill/RequiredValidators.java b/core/java/android/service/autofill/RequiredValidators.java
index f2b7db8..ac85c28 100644
--- a/core/java/android/service/autofill/RequiredValidators.java
+++ b/core/java/android/service/autofill/RequiredValidators.java
@@ -34,7 +34,7 @@
*/
final class RequiredValidators extends InternalValidator {
- private final InternalValidator[] mValidators;
+ @NonNull private final InternalValidator[] mValidators;
RequiredValidators(@NonNull InternalValidator[] validators) {
mValidators = Preconditions.checkArrayElementsNotNull(validators, "validators");
@@ -42,10 +42,6 @@
@Override
public boolean isValid(@NonNull ValueFinder finder) {
- if (mValidators == null) {
- return true;
- }
- // TODO(b/62534917): handle errors, like not finding the ID
for (InternalValidator validator : mValidators) {
final boolean valid = validator.isValid(finder);
if (!valid) return false;
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 4149173..7e4ae27 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -486,10 +486,10 @@
*
* Validator validator =
* and(
- * new SimpleRegexValidator.(ccNumberId1, "^\\d{4}$"),
- * new SimpleRegexValidator.(ccNumberId2, "^\\d{4}$"),
- * new SimpleRegexValidator.(ccNumberId3, "^\\d{4}$"),
- * new SimpleRegexValidator.(ccNumberId4, "^\\d{4}$")
+ * new SimpleRegexValidator(ccNumberId1, "^\\d{4}$"),
+ * new SimpleRegexValidator(ccNumberId2, "^\\d{4}$"),
+ * new SimpleRegexValidator(ccNumberId3, "^\\d{4}$"),
+ * new SimpleRegexValidator(ccNumberId4, "^\\d{4}$")
* );
* </pre>
*
diff --git a/core/java/android/service/autofill/SimpleRegexValidator.java b/core/java/android/service/autofill/SimpleRegexValidator.java
index ffe0076..d56d700 100644
--- a/core/java/android/service/autofill/SimpleRegexValidator.java
+++ b/core/java/android/service/autofill/SimpleRegexValidator.java
@@ -19,6 +19,7 @@
import static android.view.autofill.Helper.sDebug;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -26,42 +27,45 @@
import com.android.internal.util.Preconditions;
+import java.util.regex.Pattern;
+
/**
* Defines if a field is valid based on a regular expression (regex).
*
* <p>See {@link SaveInfo.Builder#setValidator(Validator)} for examples.
*/
-public final class SimpleRegexValidator extends InternalValidator implements Parcelable {
+public final class SimpleRegexValidator extends InternalValidator implements Validator, Parcelable {
private static final String TAG = "SimpleRegexValidator";
private final AutofillId mId;
- private final String mRegex;
+ private final Pattern mRegex;
/**
- * Default constructor.
- *
- * @param id id of the field whose regex is applied to.
- * @param regex regular expression that defines the result
- * of the validator: if the regex matches the contents of
- * the field identified by {@code id}, it returns {@code true}; otherwise, it
- * returns {@code false}.
+ * Default constructor.
+ *
+ * @param id id of the field whose regex is applied to.
+ * @param regex regular expression that defines the result of the validator: if the regex
+ * matches the contents of the field identified by {@code id}, it returns {@code true};
+ * otherwise, it returns {@code false}. The pattern will be {@link Pattern#compile compiled}
+ * without setting any flags.
*/
public SimpleRegexValidator(@NonNull AutofillId id, @NonNull String regex) {
mId = Preconditions.checkNotNull(id);
- //TODO(b/62534917): throw exception if regex is invalid
- mRegex = Preconditions.checkNotNull(regex);
+ mRegex = Pattern.compile(regex);
}
/** @hide */
@Override
+ @TestApi
public boolean isValid(@NonNull ValueFinder finder) {
final String value = finder.findByAutofillId(mId);
if (value == null) {
Log.w(TAG, "No view for id " + mId);
return false;
}
- final boolean valid = value.matches(mRegex);
+
+ final boolean valid = mRegex.matcher(value).matches();
if (sDebug) Log.d(TAG, "isValid(): " + valid);
return valid;
}
@@ -87,7 +91,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeParcelable(mId, flags);
- parcel.writeString(mRegex);
+ parcel.writeString(mRegex.pattern());
}
public static final Parcelable.Creator<SimpleRegexValidator> CREATOR =
diff --git a/core/java/android/service/autofill/Transformation.java b/core/java/android/service/autofill/Transformation.java
index 63b679d..4cef261 100644
--- a/core/java/android/service/autofill/Transformation.java
+++ b/core/java/android/service/autofill/Transformation.java
@@ -16,8 +16,8 @@
package android.service.autofill;
/**
- * Helper class used to change a child view of a {@link RemoteViews presentation template} at
- * runtime, using the values of fields contained in the screen.
+ * Helper class used to change a child view of a {@link android.widget.RemoteViews presentation
+ * template} at runtime, using the values of fields contained in the screen.
*
* <p>Typically used by {@link CustomDescription} to provide a customized Save UI affordance.
*/
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index f5f1024..833376c 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -21,6 +21,8 @@
import android.util.Base64;
import android.util.TimeUtils;
+import java.util.Arrays;
+
import com.android.internal.location.nano.GnssLogsProto.GnssLog;
/**
@@ -40,6 +42,7 @@
locationFailureStatistics = new Statistics();
timeToFirstFixSecStatistics = new Statistics();
positionAccuracyMeterStatistics = new Statistics();
+ topFourAverageCn0Statistics = new Statistics();
reset();
}
@@ -95,6 +98,27 @@
return;
}
+ /*
+ * Logs CN0 when at least 4 SVs are available
+ *
+ */
+ public void logCn0(float[] cn0s, int numSv) {
+ if (numSv < 4) {
+ return;
+ }
+ float[] cn0Array = Arrays.copyOf(cn0s, numSv);
+ Arrays.sort(cn0Array);
+ if (cn0Array[numSv - 4] > 0.0) {
+ double top4AvgCn0 = 0.0;
+ for (int i = numSv - 4; i < numSv; i++) {
+ top4AvgCn0 += (double) cn0Array[i];
+ }
+ top4AvgCn0 /= 4;
+ topFourAverageCn0Statistics.addItem(top4AvgCn0);
+ }
+ return;
+ }
+
/**
* Dumps GNSS metrics as a proto string
* @return
@@ -117,6 +141,12 @@
msg.standardDeviationPositionAccuracyMeters
= (int) positionAccuracyMeterStatistics.getStandardDeviation();
}
+ if (topFourAverageCn0Statistics.getCount() > 0) {
+ msg.numTopFourAverageCn0Processed = topFourAverageCn0Statistics.getCount();
+ msg.meanTopFourAverageCn0DbHz = topFourAverageCn0Statistics.getMean();
+ msg.standardDeviationTopFourAverageCn0DbHz
+ = topFourAverageCn0Statistics.getStandardDeviation();
+ }
String s = Base64.encodeToString(GnssLog.toByteArray(msg), Base64.DEFAULT);
reset();
return s;
@@ -155,6 +185,14 @@
s.append(" Position accuracy standard deviation (m): ").append(
positionAccuracyMeterStatistics.getStandardDeviation()).append("\n");
}
+ s.append(" Number of CN0 reports: ").append(
+ topFourAverageCn0Statistics.getCount()).append("\n");
+ if (topFourAverageCn0Statistics.getCount() > 0) {
+ s.append(" Top 4 Avg CN0 mean (dB-Hz): ").append(
+ topFourAverageCn0Statistics.getMean()).append("\n");
+ s.append(" Top 4 Avg CN0 standard deviation (dB-Hz): ").append(
+ topFourAverageCn0Statistics.getStandardDeviation()).append("\n");
+ }
s.append("GNSS_KPI_END").append("\n");
return s.toString();
}
@@ -211,6 +249,9 @@
/** Position accuracy statistics */
private Statistics positionAccuracyMeterStatistics;
+ /** Top 4 average CN0 statistics */
+ private Statistics topFourAverageCn0Statistics;
+
/**
* Resets GNSS metrics
*/
@@ -221,6 +262,7 @@
locationFailureStatistics.reset();
timeToFirstFixSecStatistics.reset();
positionAccuracyMeterStatistics.reset();
+ topFourAverageCn0Statistics.reset();
return;
}
}
\ No newline at end of file
diff --git a/proto/src/gnss.proto b/proto/src/gnss.proto
index 33a5584..c54ddad 100644
--- a/proto/src/gnss.proto
+++ b/proto/src/gnss.proto
@@ -33,4 +33,13 @@
// Standard deviation of position accuracy (in meters)
optional int32 standard_deviation_position_accuracy_meters = 8;
+
+ // Number of top 4 average CN0 processed
+ optional int32 num_top_four_average_cn0_processed = 9;
+
+ // Mean of top 4 average CN0 (dB-Hz)
+ optional double mean_top_four_average_cn0_db_hz = 10;
+
+ // Standard deviation of top 4 average CN0 (dB-Hz)
+ optional double standard_deviation_top_four_average_cn0_db_hz = 11;
}
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 68b83e6..d45ec41 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -877,10 +877,20 @@
final ValueFinder valueFinder = (id) -> {return getValueAsString(id);};
final InternalValidator validator = saveInfo.getValidator();
- if (validator != null && !validator.isValid(valueFinder)) {
- // TODO(b/62534917): add CTS test
- Slog.i(TAG, "not showing save UI because fields failed validation");
- return true;
+ if (validator != null) {
+ boolean isValid;
+ try {
+ isValid = validator.isValid(valueFinder);
+ } catch (Exception e) {
+ Slog.e(TAG, "Not showing save UI because of exception during validation "
+ + e.getClass());
+ return true;
+ }
+
+ if (!isValid) {
+ Slog.i(TAG, "not showing save UI because fields failed validation");
+ return true;
+ }
}
if (sDebug) Slog.d(TAG, "Good news, everyone! All checks passed, show save UI!");
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index e8dc3c1..750943b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -144,15 +144,19 @@
final CustomDescription customDescription = info.getCustomDescription();
if (customDescription != null) {
- // TODO(b/62534917): add CTS test
if (sDebug) Slog.d(TAG, "Using custom description");
final RemoteViews presentation = customDescription.getPresentation(valueFinder);
if (presentation != null) {
- final View remote = presentation.apply(context, null);
- final LinearLayout layout = view.findViewById(R.id.autofill_save_custom_subtitle);
- layout.addView(remote);
- layout.setVisibility(View.VISIBLE);
+ try {
+ final View remote = presentation.apply(context, null);
+ final LinearLayout layout = view.findViewById(
+ R.id.autofill_save_custom_subtitle);
+ layout.addView(remote);
+ layout.setVisibility(View.VISIBLE);
+ } catch (Exception e) {
+ Slog.e(TAG, "Could not inflate custom description. ", e);
+ }
} else {
Slog.w(TAG, "could not create remote presentation for custom title");
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 070e028..ab76529 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -731,6 +731,13 @@
return null;
}
+ final TaskRecord bottomTask() {
+ if (mTaskHistory.isEmpty()) {
+ return null;
+ }
+ return mTaskHistory.get(0);
+ }
+
TaskRecord taskForIdLocked(int id) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1867,7 +1874,14 @@
// the recents activity from an app.
behindFullscreenActivity = true;
}
-
+ } else if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Skipping after task=" + task
+ + " returning to non-application type=" + task.getTaskToReturnTo());
+ // Once we reach a fullscreen task that should return to another task, then no
+ // other activities behind that one should be visible.
+ if (task.getTaskToReturnTo() != APPLICATION_ACTIVITY_TYPE) {
+ behindFullscreenActivity = true;
+ }
}
}
@@ -2853,10 +2867,13 @@
transit = TRANSIT_TASK_OPEN_BEHIND;
} else {
// If a new task is being launched, then mark the existing top activity as
- // supporting picture-in-picture while pausing
+ // supporting picture-in-picture while pausing only if the starting activity
+ // would not be considered an overlay on top of the current activity
+ // (eg. not fullscreen, or the assistant)
if (focusedTopActivity != null
&& focusedTopActivity.getStackId() != PINNED_STACK_ID
- && r.getStackId() != ASSISTANT_STACK_ID) {
+ && r.getStackId() != ASSISTANT_STACK_ID
+ && r.fullscreen) {
focusedTopActivity.supportsPictureInPictureWhilePausing = true;
}
transit = TRANSIT_TASK_OPEN;
@@ -3338,6 +3355,16 @@
* @param allowFocusSelf Is the focus allowed to remain on the same stack.
*/
private boolean adjustFocusToNextFocusableStackLocked(String reason, boolean allowFocusSelf) {
+ if (isAssistantStack() && bottomTask() != null &&
+ bottomTask().getTaskToReturnTo() == HOME_ACTIVITY_TYPE) {
+ // If the current stack is the assistant stack, then use the return-to type to determine
+ // whether to return to the home screen. This is needed to workaround an issue where
+ // launching a fullscreen task (and subequently returning from that task) will cause
+ // the fullscreen stack to be found as the next focusable stack below, even if the
+ // assistant was launched over home.
+ return mStackSupervisor.moveHomeStackTaskToTop(reason);
+ }
+
final ActivityStack stack = mStackSupervisor.getNextFocusableStackLocked(
allowFocusSelf ? null : this);
final String myReason = reason + " adjustFocusToNextFocusableStack";
@@ -4467,9 +4494,10 @@
updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
}
// If a new task is moved to the front, then mark the existing top activity as supporting
- // picture-in-picture while paused
+ // picture-in-picture while paused only if the task would not be considered an oerlay on top
+ // of the current activity (eg. not fullscreen, or the assistant)
if (topActivity != null && topActivity.getStackId() != PINNED_STACK_ID
- && tr.getStackId() != ASSISTANT_STACK_ID) {
+ && tr.getStackId() != ASSISTANT_STACK_ID && tr.containsOnlyFullscreenActivities()) {
topActivity.supportsPictureInPictureWhilePausing = true;
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4f211e3..96d8573 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1112,6 +1112,19 @@
return intent != null ? intent : affinityIntent;
}
+ /**
+ * @return Whether there are only fullscreen activities in this task.
+ */
+ boolean containsOnlyFullscreenActivities() {
+ for (int i = 0; i < mActivities.size(); i++) {
+ final ActivityRecord r = mActivities.get(i);
+ if (!r.finishing && !r.fullscreen) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/** Returns the first non-finishing activity from the root. */
ActivityRecord getRootActivity() {
for (int i = 0; i < mActivities.size(); i++) {
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 4511aa9..601dd94 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1651,6 +1651,9 @@
mSvAzimuths,
mSvCarrierFreqs);
+ // Log CN0 as part of GNSS metrics
+ mGnssMetrics.logCn0(mCn0s, svCount);
+
if (VERBOSE) {
Log.v(TAG, "SV count: " + svCount);
}
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 01a3143..5dc79f8 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -17,13 +17,14 @@
package com.android.server.wm;
import android.util.Slog;
-import android.view.Display;
import java.util.ArrayDeque;
import java.util.function.Consumer;
+import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -56,7 +57,6 @@
mService = service;
}
- private int mHighestApplicationLayer = 0;
private ArrayDeque<WindowState> mPinnedWindows = new ArrayDeque<>();
private ArrayDeque<WindowState> mDockedWindows = new ArrayDeque<>();
private ArrayDeque<WindowState> mAssistantWindows = new ArrayDeque<>();
@@ -66,6 +66,8 @@
private int mCurBaseLayer;
private int mCurLayer;
private boolean mAnyLayerChanged;
+ private int mHighestApplicationLayer;
+ private int mHighestDockedAffectedLayer;
private int mHighestLayerInImeTargetBaseLayer;
private WindowState mImeTarget;
private boolean mAboveImeTarget;
@@ -98,6 +100,10 @@
mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer,
w.mWinAnimator.mAnimLayer);
}
+ if (w.getAppToken() != null && StackId.isResizeableByDockedStack(w.getStackId())) {
+ mHighestDockedAffectedLayer = Math.max(mHighestDockedAffectedLayer,
+ w.mWinAnimator.mAnimLayer);
+ }
collectSpecialWindows(w);
@@ -135,7 +141,6 @@
}
private void reset() {
- mHighestApplicationLayer = 0;
mPinnedWindows.clear();
mInputMethodWindows.clear();
mDockedWindows.clear();
@@ -147,8 +152,10 @@
mCurLayer = 0;
mAnyLayerChanged = false;
- mImeTarget = mService.mInputMethodTarget;
+ mHighestApplicationLayer = 0;
+ mHighestDockedAffectedLayer = 0;
mHighestLayerInImeTargetBaseLayer = (mImeTarget != null) ? mImeTarget.mBaseLayer : 0;
+ mImeTarget = mService.mInputMethodTarget;
mAboveImeTarget = false;
mAboveImeTargetAppWindows.clear();
}
@@ -179,32 +186,41 @@
}
}
- final Task task = w.getTask();
- if (task == null) {
- return;
- }
- final TaskStack stack = task.mStack;
- if (stack == null) {
- return;
- }
- if (stack.mStackId == PINNED_STACK_ID) {
+ final int stackId = w.getAppToken() != null ? w.getStackId() : INVALID_STACK_ID;
+ if (stackId == PINNED_STACK_ID) {
mPinnedWindows.add(w);
- } else if (stack.mStackId == DOCKED_STACK_ID) {
+ } else if (stackId == DOCKED_STACK_ID) {
mDockedWindows.add(w);
- } else if (stack.mStackId == ASSISTANT_STACK_ID) {
+ } else if (stackId == ASSISTANT_STACK_ID) {
mAssistantWindows.add(w);
}
}
private void adjustSpecialWindows() {
- int layer = mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER;
- // For pinned and docked stack window, we want to make them above other windows also when
- // these windows are animating.
- while (!mDockedWindows.isEmpty()) {
- layer = assignAndIncreaseLayerIfNeeded(mDockedWindows.remove(), layer);
+ // The following adjustments are beyond the highest docked-affected layer
+ int layer = mHighestDockedAffectedLayer + WINDOW_LAYER_MULTIPLIER;
+
+ // Adjust the docked stack windows and dock divider above only the windows that are affected
+ // by the docked stack. When this happens, also boost the assistant window layers, otherwise
+ // the docked stack windows & divider would be promoted above the assistant.
+ if (!mDockedWindows.isEmpty() && mHighestDockedAffectedLayer > 0) {
+ while (!mDockedWindows.isEmpty()) {
+ final WindowState window = mDockedWindows.remove();
+ layer = assignAndIncreaseLayerIfNeeded(window, layer);
+ }
+
+ layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
+
+ while (!mAssistantWindows.isEmpty()) {
+ final WindowState window = mAssistantWindows.remove();
+ if (window.mLayer > mHighestDockedAffectedLayer) {
+ layer = assignAndIncreaseLayerIfNeeded(window, layer);
+ }
+ }
}
- layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
+ // The following adjustments are beyond the highest app layer or boosted layer
+ layer = Math.max(layer, mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER);
// We know that we will be animating a relaunching window in the near future, which will
// receive a z-order increase. We want the replaced window to immediately receive the same
@@ -213,12 +229,6 @@
layer = assignAndIncreaseLayerIfNeeded(mReplacingWindows.remove(), layer);
}
- // Adjust the assistant stack windows to be above the docked and fullscreen stack windows,
- // but under the pinned stack windows
- while (!mAssistantWindows.isEmpty()) {
- layer = assignAndIncreaseLayerIfNeeded(mAssistantWindows.remove(), layer);
- }
-
while (!mPinnedWindows.isEmpty()) {
layer = assignAndIncreaseLayerIfNeeded(mPinnedWindows.remove(), layer);
}