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);
         }