Merge "added methods to @TestApi"
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 81d732f..8bc14d7 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -1299,78 +1299,6 @@
         }
     }
 
-    private BatteryStatsHelper getBatteryStatsHelper() {
-        if (mBatteryStatsHelper == null) {
-            final long callingToken = Binder.clearCallingIdentity();
-            try {
-                // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly().
-                mBatteryStatsHelper = new BatteryStatsHelper(mContext, false);
-            } finally {
-                Binder.restoreCallingIdentity(callingToken);
-            }
-            mBatteryStatsHelper.create((Bundle) null);
-        }
-        long currentTime = SystemClock.elapsedRealtime();
-        if (currentTime - mBatteryStatsHelperTimestampMs >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) {
-            // Load BatteryStats and do all the calculations.
-            mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.USER_ALL);
-            // Calculations are done so we don't need to save the raw BatteryStats data in RAM.
-            mBatteryStatsHelper.clearStats();
-            mBatteryStatsHelperTimestampMs = currentTime;
-        }
-        return mBatteryStatsHelper;
-    }
-
-    private long milliAmpHrsToNanoAmpSecs(double mAh) {
-        final long MILLI_AMP_HR_TO_NANO_AMP_SECS = 1_000_000L * 3600L;
-        return (long) (mAh * MILLI_AMP_HR_TO_NANO_AMP_SECS + 0.5);
-    }
-
-    private void pullDeviceCalculatedPowerUse(int tagId,
-            long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
-        BatteryStatsHelper bsHelper = getBatteryStatsHelper();
-        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
-        e.writeLong(milliAmpHrsToNanoAmpSecs(bsHelper.getComputedPower()));
-        pulledData.add(e);
-    }
-
-    private void pullDeviceCalculatedPowerBlameUid(int tagId,
-            long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
-        final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
-        if (sippers == null) {
-            return;
-        }
-        for (BatterySipper bs : sippers) {
-            if (bs.drainType != bs.drainType.APP) {
-                continue;
-            }
-            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
-            e.writeInt(bs.uidObj.getUid());
-            e.writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah));
-            pulledData.add(e);
-        }
-    }
-
-    private void pullDeviceCalculatedPowerBlameOther(int tagId,
-            long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
-        final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
-        if (sippers == null) {
-            return;
-        }
-        for (BatterySipper bs : sippers) {
-            if (bs.drainType == bs.drainType.APP) {
-                continue; // This is a separate atom; see pullDeviceCalculatedPowerBlameUid().
-            }
-            if (bs.drainType == bs.drainType.USER) {
-                continue; // This is not supported. We purposefully calculate over USER_ALL.
-            }
-            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
-            e.writeInt(bs.drainType.ordinal());
-            e.writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah));
-            pulledData.add(e);
-        }
-    }
-
     private void pullDiskIo(int tagId, long elapsedNanos, final long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
         mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead,
@@ -1992,21 +1920,6 @@
                 break;
             }
 
-            case StatsLog.DEVICE_CALCULATED_POWER_USE: {
-                pullDeviceCalculatedPowerUse(tagId, elapsedNanos, wallClockNanos, ret);
-                break;
-            }
-
-            case StatsLog.DEVICE_CALCULATED_POWER_BLAME_UID: {
-                pullDeviceCalculatedPowerBlameUid(tagId, elapsedNanos, wallClockNanos, ret);
-                break;
-            }
-
-            case StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER: {
-                pullDeviceCalculatedPowerBlameOther(tagId, elapsedNanos, wallClockNanos, ret);
-                break;
-            }
-
             case StatsLog.TEMPERATURE: {
                 pullTemperature(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
diff --git a/api/current.txt b/api/current.txt
index d5ece2e..54bfac2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17289,6 +17289,7 @@
     field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1
     field public static final int LENS_POSE_REFERENCE_GYROSCOPE = 1; // 0x1
     field public static final int LENS_POSE_REFERENCE_PRIMARY_CAMERA = 0; // 0x0
+    field public static final int LENS_POSE_REFERENCE_UNDEFINED = 2; // 0x2
     field public static final int LENS_STATE_MOVING = 1; // 0x1
     field public static final int LENS_STATE_STATIONARY = 0; // 0x0
     field public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE = 0; // 0x0
diff --git a/api/system-current.txt b/api/system-current.txt
index d9d9a4d..d00bd84 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -126,6 +126,7 @@
     field @Deprecated public static final String MODIFY_NETWORK_ACCOUNTING = "android.permission.MODIFY_NETWORK_ACCOUNTING";
     field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
     field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
+    field public static final String MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE = "android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE";
     field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
     field public static final String NETWORK_AIRPLANE_MODE = "android.permission.NETWORK_AIRPLANE_MODE";
     field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
@@ -7715,7 +7716,10 @@
   public final class PermissionManager {
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public int getRuntimePermissionsVersion();
     method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
+    method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledImsServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledTelephonyDataServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
@@ -8169,6 +8173,10 @@
     field public static final int VOLUME_HUSH_VIBRATE = 1; // 0x1
   }
 
+  public static final class Settings.System extends android.provider.Settings.NameValueTable {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, boolean);
+  }
+
   public static interface Telephony.CarrierColumns extends android.provider.BaseColumns {
     field @NonNull public static final android.net.Uri CONTENT_URI;
     field public static final String EXPIRATION_TIME = "expiration_time";
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 9424862..4372e22 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -53,6 +53,7 @@
 import "frameworks/base/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto";
 import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto";
 import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
+import "frameworks/base/core/proto/android/stats/sysui/notification_enums.proto";
 import "frameworks/base/core/proto/android/telecomm/enums.proto";
 import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/core/proto/android/view/enums.proto";
@@ -337,6 +338,9 @@
         BootTimeEventUtcTime boot_time_event_utc_time_reported = 241;
         BootTimeEventErrorCode boot_time_event_error_code_reported = 242;
         UserspaceRebootReported userspace_reboot_reported = 243;
+        NotificationReported notification_reported = 244;
+        NotificationPanelReported notification_panel_reported = 245;
+        NotificationChannelModified notification_panel_modified = 246;
     }
 
     // Pulled events will start at field 10000.
@@ -3287,6 +3291,10 @@
  * this button" or "this dialog was displayed".
  * Keep the UI event stream clean: don't use for system or background events.
  * Log using the UiEventLogger wrapper - don't write with the StatsLog API directly.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/
+ *   frameworks/base/packages/SystemUI/src/com/android/systemui/
  */
 message UiEventReported {
     // The event_id.
@@ -3298,6 +3306,122 @@
 }
 
 /**
+ * Reports a notification was created or updated.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/notification/
+ */
+message NotificationReported {
+    // The event_id (as for UiEventReported).
+    optional int32 event_id = 1;
+    // The notifying app's uid and package.
+    optional int32 uid = 2 [(is_uid) = true];
+    optional string package_name = 3;
+    // A small system-assigned identifier for the notification.
+    // Locally probably-unique, but expect collisions across users and/or days.
+    optional int32 instance_id = 4;
+    // The app-assigned notification ID and tag
+    optional int32 notification_id = 5;
+    optional string notification_tag = 6;
+    optional string channel_id = 7;  // App-assigned channel ID
+
+    // Grouping information
+    optional string group_id = 8;  // Group the notification currently belongs to
+    optional int32 group_instance_id = 9;  // Instance_id of the group-summary notification
+    optional bool is_group_summary = 10;  // Tags the group-summary notification
+
+    // Attributes
+    optional string category = 11;   // App-assigned notification category (API-defined strings)
+    optional int32 style = 12;       // App-assigned notification style
+    optional int32 num_people = 13;  // Number of Person records attached to the notification
+
+    // Ordering, importance and interruptiveness
+
+    optional int32 position = 14;    // Position in NotificationManager's list
+
+    optional android.stats.sysui.NotificationImportance importance = 15;
+    optional int32 alerting = 16;    // Bitfield, 1=buzz 2=beep 4=blink
+
+    enum NotificationImportanceExplanation {
+        IMPORTANCE_EXPLANATION_UNKNOWN = 0;
+        IMPORTANCE_EXPLANATION_APP = 1;     // App-specified channel importance.
+        IMPORTANCE_EXPLANATION_USER = 2;    // User-specified channel importance.
+        IMPORTANCE_EXPLANATION_ASST = 3;    // Notification Assistant override.
+        IMPORTANCE_EXPLANATION_SYSTEM = 4;  // System override.
+        // Like _APP, but based on pre-channels priority signal.
+        IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS = 5;
+    }
+
+    optional NotificationImportanceExplanation importance_source = 17;
+    optional android.stats.sysui.NotificationImportance importance_initial = 18;
+    optional NotificationImportanceExplanation importance_initial_source = 19;
+    optional android.stats.sysui.NotificationImportance importance_asst = 20;
+    optional int32 assistant_hash = 21;
+    optional float assistant_ranking_score = 22;
+}
+
+message Notification {
+    // The notifying app's uid and package.
+    optional int32 uid = 1 [(is_uid) = true];
+    optional string package_name = 2;
+    // A small system-assigned identifier for the notification.
+    optional int32 instance_id = 3;
+
+    // Grouping information.
+    optional int32 group_instance_id = 4;
+    optional bool is_group_summary = 5;
+
+    // The section of the shade that the notification is in.
+    // See NotificationSectionsManager.PriorityBucket.
+    enum NotificationSection {
+        SECTION_UNKNOWN = 0;
+        SECTION_PEOPLE = 1;
+        SECTION_ALERTING = 2;
+        SECTION_SILENT = 3;
+    }
+    optional NotificationSection section = 6;
+}
+
+message NotificationList {
+    repeated Notification notifications = 1;  // An ordered sequence of notifications.
+}
+
+/**
+ * Reports a notification panel was displayed, e.g. from the lockscreen or status bar.
+ *
+ * Logged from:
+ *   frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/
+ */
+message NotificationPanelReported {
+    // The event_id (as for UiEventReported).
+    optional int32 event_id = 1;
+    optional int32 num_notifications = 2;
+    // The notifications in the panel, in the order that they appear there.
+    optional NotificationList notifications = 3 [(log_mode) = MODE_BYTES];
+}
+
+/**
+ * Reports a notification channel, or channel group, was created, updated, or deleted.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/notification/
+ */
+message NotificationChannelModified {
+    // The event_id (as for UiEventReported).
+    optional int32 event_id = 1;
+    // The notifying app's uid and package.
+    optional int32 uid = 2 [(is_uid) = true];
+    optional string package_name = 3;
+    // App-assigned notification channel ID or channel-group ID
+    optional string channel_id = 4;
+    // Previous importance setting, if applicable
+    optional android.stats.sysui.NotificationImportance old_importance = 5;
+    // New importance setting
+    optional android.stats.sysui.NotificationImportance importance = 6;
+}
+
+
+/**
  * Logs when a biometric acquire event occurs.
  *
  * Logged from:
@@ -3485,12 +3609,14 @@
         INSTALL_FAILURE_DOWNLOAD = 23;
         INSTALL_FAILURE_STATE_MISMATCH = 24;
         INSTALL_FAILURE_COMMIT = 25;
+        REBOOT_TRIGGERED = 26;
     }
     optional State state = 6;
     // Possible experiment ids for monitoring this push.
     optional TrainExperimentIds experiment_ids = 7 [(log_mode) = MODE_BYTES];
     // user id
     optional int32 user_id = 8;
+    optional int32 reason = 9;
 }
 
 /* Test atom, is not logged anywhere */
@@ -6782,6 +6908,7 @@
         INSTALL_FAILURE_DOWNLOAD = 23;
         INSTALL_FAILURE_STATE_MISMATCH = 24;
         INSTALL_FAILURE_COMMIT = 25;
+        REBOOT_TRIGGERED = 26;
     }
     optional Status status = 4;
 }
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index b9f7a0b..591d727 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -185,20 +185,6 @@
          {.additiveFields = {7, 9, 11, 13, 15, 17, 19, 21},
           .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}},
 
-        // DeviceCalculatedPowerUse.
-        {{.atomTag = android::util::DEVICE_CALCULATED_POWER_USE},
-         {.puller = new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}},
-
-        // DeviceCalculatedPowerBlameUid.
-        {{.atomTag = android::util::DEVICE_CALCULATED_POWER_BLAME_UID},
-         {.puller = new StatsCompanionServicePuller(
-                  android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}},
-
-        // DeviceCalculatedPowerBlameOther.
-        {{.atomTag = android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER},
-         {.puller = new StatsCompanionServicePuller(
-                  android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}},
-
         // DebugElapsedClock.
         {{.atomTag = android::util::DEBUG_ELAPSED_CLOCK},
          {.additiveFields = {1, 2, 3, 4},
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 70262b0..0c5e67c 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -464,6 +464,9 @@
                     || appDir.equals(instrumentedAppDir)) {
                 outZipPaths.clear();
                 outZipPaths.add(instrumentationAppDir);
+                if (!instrumentationAppDir.equals(instrumentedAppDir)) {
+                    outZipPaths.add(instrumentedAppDir);
+                }
 
                 // Only add splits if the app did not request isolated split loading.
                 if (!aInfo.requestsIsolatedSplitLoading()) {
@@ -472,7 +475,6 @@
                     }
 
                     if (!instrumentationAppDir.equals(instrumentedAppDir)) {
-                        outZipPaths.add(instrumentedAppDir);
                         if (instrumentedSplitAppDirs != null) {
                             Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
                         }
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index bdc7b99..78f9cc8 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -105,6 +105,7 @@
     private static final String ATT_ORIG_IMP = "orig_imp";
     private static final String ATT_PARENT_CHANNEL = "parent";
     private static final String ATT_CONVERSATION_ID = "conv_id";
+    private static final String ATT_DEMOTE = "dem";
     private static final String DELIMITER = ",";
 
     /**
@@ -194,6 +195,7 @@
     private boolean mImportanceLockedDefaultApp;
     private String mParentId = null;
     private String mConversationId = null;
+    private boolean mDemoted = false;
 
     /**
      * Creates a notification channel.
@@ -260,6 +262,7 @@
         mOriginalImportance = in.readInt();
         mParentId = in.readString();
         mConversationId = in.readString();
+        mDemoted = in.readBoolean();
     }
 
     @Override
@@ -317,6 +320,7 @@
         dest.writeInt(mOriginalImportance);
         dest.writeString(mParentId);
         dest.writeString(mConversationId);
+        dest.writeBoolean(mDemoted);
     }
 
     /**
@@ -386,8 +390,6 @@
         return input;
     }
 
-    // Modifiable by apps on channel creation.
-
     /**
      * @hide
      */
@@ -395,6 +397,8 @@
         mId = id;
     }
 
+    // Modifiable by apps on channel creation.
+
     /**
      * Sets what group this channel belongs to.
      *
@@ -767,6 +771,20 @@
     }
 
     /**
+     * @hide
+     */
+    public void setDemoted(boolean demoted) {
+        mDemoted = demoted;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isDemoted() {
+        return mDemoted;
+    }
+
+    /**
      * Returns whether the user has chosen the importance of this channel, either to affirm the
      * initial selection from the app, or changed it to be higher or lower.
      * @see #getImportance()
@@ -829,6 +847,7 @@
         setOriginalImportance(safeInt(parser, ATT_ORIG_IMP, DEFAULT_IMPORTANCE));
         setConversationId(parser.getAttributeValue(null, ATT_PARENT_CHANNEL),
                 parser.getAttributeValue(null, ATT_CONVERSATION_ID));
+        setDemoted(safeBool(parser, ATT_DEMOTE, false));
     }
 
     @Nullable
@@ -959,6 +978,9 @@
         if (getConversationId() != null) {
             out.attribute(null, ATT_CONVERSATION_ID, getConversationId());
         }
+        if (isDemoted()) {
+            out.attribute(null, ATT_DEMOTE, Boolean.toString(isDemoted()));
+        }
 
         // mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of
         // truth and so aren't written to this xml file
@@ -1118,7 +1140,8 @@
                 && mImportanceLockedDefaultApp == that.mImportanceLockedDefaultApp
                 && mOriginalImportance == that.mOriginalImportance
                 && Objects.equals(getParentChannelId(), that.getParentChannelId())
-                && Objects.equals(getConversationId(), that.getConversationId());
+                && Objects.equals(getConversationId(), that.getConversationId())
+                && isDemoted() == that.isDemoted();
     }
 
     @Override
@@ -1129,7 +1152,7 @@
                 isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
                 getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
                 mImportanceLockedByOEM, mImportanceLockedDefaultApp, mOriginalImportance,
-                mParentId, mConversationId);
+                mParentId, mConversationId, mDemoted);
         result = 31 * result + Arrays.hashCode(mVibration);
         return result;
     }
@@ -1176,7 +1199,8 @@
                 + ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
                 + ", mOriginalImp=" + mOriginalImportance
                 + ", mParent=" + mParentId
-                + ", mConversationId=" + mConversationId;
+                + ", mConversationId=" + mConversationId
+                + ", mDemoted=" + mDemoted;
     }
 
     /** @hide */
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index a45648f..7bddc1d 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1539,10 +1539,15 @@
      * <p><code>p' = Rp</code></p>
      * <p>where <code>p</code> is in the device sensor coordinate system, and
      *  <code>p'</code> is in the camera-oriented coordinate system.</p>
+     * <p>If {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, the quaternion rotation cannot
+     *  be accurately represented by the camera device, and will be represented by
+     *  default values matching its default facing.</p>
      * <p><b>Units</b>:
      * Quaternion coefficients</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_REFERENCE
      */
     @PublicKey
     @NonNull
@@ -1577,6 +1582,8 @@
      * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to
      * the center of the primary gyroscope on the device. The axis definitions are the same as
      * with PRIMARY_CAMERA.</p>
+     * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, this position cannot be accurately
+     * represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p>
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
@@ -1714,20 +1721,24 @@
             new Key<float[]>("android.lens.radialDistortion", float[].class);
 
     /**
-     * <p>The origin for {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}.</p>
+     * <p>The origin for {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}, and the accuracy of
+     * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} and {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}.</p>
      * <p>Different calibration methods and use cases can produce better or worse results
      * depending on the selected coordinate origin.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #LENS_POSE_REFERENCE_PRIMARY_CAMERA PRIMARY_CAMERA}</li>
      *   <li>{@link #LENS_POSE_REFERENCE_GYROSCOPE GYROSCOPE}</li>
+     *   <li>{@link #LENS_POSE_REFERENCE_UNDEFINED UNDEFINED}</li>
      * </ul></p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
      * @see #LENS_POSE_REFERENCE_PRIMARY_CAMERA
      * @see #LENS_POSE_REFERENCE_GYROSCOPE
+     * @see #LENS_POSE_REFERENCE_UNDEFINED
      */
     @PublicKey
     @NonNull
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index ec13a36..2377ccd 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -366,6 +366,20 @@
      */
     public static final int LENS_POSE_REFERENCE_GYROSCOPE = 1;
 
+    /**
+     * <p>The camera device cannot represent the values of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}
+     * and {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} accurately enough. One such example is a camera device
+     * on the cover of a foldable phone: in order to measure the pose translation and rotation,
+     * some kind of hinge position sensor would be needed.</p>
+     * <p>The value of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} must be all zeros, and
+     * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} must be values matching its default facing.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#LENS_POSE_REFERENCE
+     */
+    public static final int LENS_POSE_REFERENCE_UNDEFINED = 2;
+
     //
     // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
     //
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 9b305b32..6f0d135 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3027,10 +3027,15 @@
      * <p><code>p' = Rp</code></p>
      * <p>where <code>p</code> is in the device sensor coordinate system, and
      *  <code>p'</code> is in the camera-oriented coordinate system.</p>
+     * <p>If {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, the quaternion rotation cannot
+     *  be accurately represented by the camera device, and will be represented by
+     *  default values matching its default facing.</p>
      * <p><b>Units</b>:
      * Quaternion coefficients</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_REFERENCE
      */
     @PublicKey
     @NonNull
@@ -3065,6 +3070,8 @@
      * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to
      * the center of the primary gyroscope on the device. The axis definitions are the same as
      * with PRIMARY_CAMERA.</p>
+     * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, this position cannot be accurately
+     * represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p>
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 2583292..5a1ba7f 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -160,6 +160,7 @@
      * Grant default permissions to currently active LUI app
      * @param packageName The package name for the LUI app
      * @param user The user handle
+     * @param executor The executor for the callback
      * @param callback The callback provided by caller to be notified when grant completes
      * @hide
      */
@@ -181,6 +182,7 @@
      * Revoke default permissions to currently active LUI app
      * @param packageNames The package names for the LUI apps
      * @param user The user handle
+     * @param executor The executor for the callback
      * @param callback The callback provided by caller to be notified when grant completes
      * @hide
      */
@@ -198,6 +200,72 @@
         }
     }
 
+    /**
+     * Grant default permissions to currently active Ims services
+     * @param packageNames The package names for the Ims services
+     * @param user The user handle
+     * @param executor The executor for the callback
+     * @param callback The callback provided by caller to be notified when grant completes
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS)
+    public void grantDefaultPermissionsToEnabledImsServices(
+            @NonNull String[] packageNames, @NonNull UserHandle user,
+            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+        try {
+            mPermissionManager.grantDefaultPermissionsToEnabledImsServices(
+                    packageNames, user.getIdentifier());
+            executor.execute(() -> callback.accept(true));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Grant default permissions to currently enabled telephony data services
+     * @param packageNames The package name for the services
+     * @param user The user handle
+     * @param executor The executor for the callback
+     * @param callback The callback provided by caller to be notified when grant completes
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS)
+    public void grantDefaultPermissionsToEnabledTelephonyDataServices(
+            @NonNull String[] packageNames, @NonNull UserHandle user,
+            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+        try {
+            mPermissionManager.grantDefaultPermissionsToEnabledTelephonyDataServices(
+                    packageNames, user.getIdentifier());
+            executor.execute(() -> callback.accept(true));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Revoke default permissions to currently active telephony data services
+     * @param packageNames The package name for the services
+     * @param user The user handle
+     * @param executor The executor for the callback
+     * @param callback The callback provided by caller to be notified when revoke completes
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS)
+    public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+            @NonNull String[] packageNames, @NonNull UserHandle user,
+            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+        try {
+            mPermissionManager.revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+                    packageNames, user.getIdentifier());
+            executor.execute(() -> callback.accept(true));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
     private List<SplitPermissionInfo> splitPermissionInfoListToNonParcelableList(
             List<SplitPermissionInfoParcelable> parcelableList) {
         final int size = parcelableList.size();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4f84183..96a4a2f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -95,6 +95,7 @@
  * The Settings provider contains global system-level device preferences.
  */
 public final class Settings {
+    private static final boolean DEFAULT_OVERRIDEABLE_BY_RESTORE = false;
 
     // Intent actions for Settings
 
@@ -2149,6 +2150,11 @@
      */
     public static final String CALL_METHOD_FLAGS_KEY = "_flags";
 
+    /**
+     * @hide - String argument extra to the fast-path call()-based requests
+     */
+    public static final String CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY = "_overrideable_by_restore";
+
     /** @hide - Private call() method to write to 'system' table */
     public static final String CALL_METHOD_PUT_SYSTEM = "PUT_system";
 
@@ -2517,7 +2523,8 @@
         }
 
         public boolean putStringForUser(ContentResolver cr, String name, String value,
-                String tag, boolean makeDefault, final int userHandle) {
+                String tag, boolean makeDefault, final int userHandle,
+                boolean overrideableByRestore) {
             try {
                 Bundle arg = new Bundle();
                 arg.putString(Settings.NameValueTable.VALUE, value);
@@ -2528,6 +2535,9 @@
                 if (makeDefault) {
                     arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true);
                 }
+                if (overrideableByRestore) {
+                    arg.putBoolean(CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY, true);
+                }
                 IContentProvider cp = mProviderHolder.getProvider(cr);
                 cp.call(cr.getPackageName(), cr.getFeatureId(),
                         mProviderHolder.mUri.getAuthority(), mCallSetCommand, name, arg);
@@ -3078,10 +3088,36 @@
             return putStringForUser(resolver, name, value, resolver.getUserId());
         }
 
+        /**
+         * Store a name/value pair into the database. Values written by this method will be
+         * overridden if a restore happens in the future.
+         *
+         * @param resolver to access the database with
+         * @param name to store
+         * @param value to associate with the name
+         *
+         * @return true if the value was set, false on database errors
+         *
+         * @hide
+         */
+        @RequiresPermission(Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE)
+        @SystemApi
+        public static boolean putString(@NonNull ContentResolver resolver,
+                @NonNull String name, @Nullable String value, boolean overrideableByRestore) {
+            return putStringForUser(resolver, name, value, resolver.getUserId(),
+                   overrideableByRestore);
+        }
+
         /** @hide */
         @UnsupportedAppUsage
         public static boolean putStringForUser(ContentResolver resolver, String name, String value,
                 int userHandle) {
+            return putStringForUser(resolver, name, value, userHandle,
+                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
+        }
+
+        private static boolean putStringForUser(ContentResolver resolver, String name, String value,
+                int userHandle, boolean overrideableByRestore) {
             if (MOVED_TO_SECURE.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                         + " to android.provider.Settings.Secure, value is unchanged.");
@@ -3092,7 +3128,8 @@
                         + " to android.provider.Settings.Global, value is unchanged.");
                 return false;
             }
-            return sNameValueCache.putStringForUser(resolver, name, value, null, false, userHandle);
+            return sNameValueCache.putStringForUser(resolver, name, value, null, false, userHandle,
+                    overrideableByRestore);
         }
 
         /**
@@ -3416,7 +3453,7 @@
                     // need to store the adjusted configuration as the initial settings.
                     Settings.System.putStringForUser(
                             cr, SYSTEM_LOCALES, outConfig.getLocales().toLanguageTags(),
-                            userHandle);
+                            userHandle, DEFAULT_OVERRIDEABLE_BY_RESTORE);
                 }
             }
         }
@@ -3449,7 +3486,8 @@
                 int userHandle) {
             return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle) &&
                     Settings.System.putStringForUser(
-                            cr, SYSTEM_LOCALES, config.getLocales().toLanguageTags(), userHandle);
+                            cr, SYSTEM_LOCALES, config.getLocales().toLanguageTags(), userHandle,
+                            DEFAULT_OVERRIDEABLE_BY_RESTORE);
         }
 
         /** @hide */
@@ -5251,6 +5289,24 @@
         }
 
         /**
+         * Store a name/value pair into the database. Values written by this method will be
+         * overridden if a restore happens in the future.
+         *
+         * @param resolver to access the database with
+         * @param name to store
+         * @param value to associate with the name
+         * @return true if the value was set, false on database errors
+         *
+         * @hide
+         */
+        @RequiresPermission(Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE)
+        public static boolean putString(ContentResolver resolver, String name,
+                String value, boolean overrideableByRestore) {
+            return putStringForUser(resolver, name, value, /* tag */ null, /* makeDefault */ false,
+                    resolver.getUserId(), overrideableByRestore);
+        }
+
+        /**
          * Store a name/value pair into the database.
          * @param resolver to access the database with
          * @param name to store
@@ -5265,22 +5321,23 @@
         @UnsupportedAppUsage
         public static boolean putStringForUser(ContentResolver resolver, String name, String value,
                 int userHandle) {
-            return putStringForUser(resolver, name, value, null, false, userHandle);
+            return putStringForUser(resolver, name, value, null, false, userHandle,
+                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
         }
 
         /** @hide */
         @UnsupportedAppUsage
         public static boolean putStringForUser(@NonNull ContentResolver resolver,
                 @NonNull String name, @Nullable String value, @Nullable String tag,
-                boolean makeDefault, @UserIdInt int userHandle) {
+                boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore) {
             if (MOVED_TO_GLOBAL.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
                         + " to android.provider.Settings.Global");
                 return Global.putStringForUser(resolver, name, value,
-                        tag, makeDefault, userHandle);
+                        tag, makeDefault, userHandle, DEFAULT_OVERRIDEABLE_BY_RESTORE);
             }
             return sNameValueCache.putStringForUser(resolver, name, value, tag,
-                    makeDefault, userHandle);
+                    makeDefault, userHandle, overrideableByRestore);
         }
 
         /**
@@ -5329,7 +5386,7 @@
                 @NonNull String name, @Nullable String value, @Nullable String tag,
                 boolean makeDefault) {
             return putStringForUser(resolver, name, value, tag, makeDefault,
-                    resolver.getUserId());
+                    resolver.getUserId(), DEFAULT_OVERRIDEABLE_BY_RESTORE);
         }
 
         /**
@@ -12940,7 +12997,29 @@
          */
         public static boolean putString(ContentResolver resolver,
                 String name, String value) {
-            return putStringForUser(resolver, name, value, null, false, resolver.getUserId());
+            return putStringForUser(resolver, name, value, null, false, resolver.getUserId(),
+                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
+        }
+
+        /**
+         * Store a name/value pair into the database.
+         *
+         * @param resolver to access the database with
+         * @param name to store
+         * @param value to associate with the name
+         * @param tag to associated with the setting.
+         * @param makeDefault whether to make the value the default one.
+         * @param overrideableByRestore whether restore can override this value
+         * @return true if the value was set, false on database errors
+         *
+         * @hide
+         */
+        @RequiresPermission(Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE)
+        public static boolean putString(@NonNull ContentResolver resolver,
+                @NonNull String name, @Nullable String value, @Nullable String tag,
+                boolean makeDefault, boolean overrideableByRestore) {
+            return putStringForUser(resolver, name, value, tag, makeDefault,
+                    resolver.getUserId(), overrideableByRestore);
         }
 
         /**
@@ -12989,7 +13068,7 @@
                 @NonNull String name, @Nullable String value, @Nullable String tag,
                 boolean makeDefault) {
             return putStringForUser(resolver, name, value, tag, makeDefault,
-                    resolver.getUserId());
+                    resolver.getUserId(), DEFAULT_OVERRIDEABLE_BY_RESTORE);
         }
 
         /**
@@ -13051,13 +13130,14 @@
         @UnsupportedAppUsage
         public static boolean putStringForUser(ContentResolver resolver,
                 String name, String value, int userHandle) {
-            return putStringForUser(resolver, name, value, null, false, userHandle);
+            return putStringForUser(resolver, name, value, null, false, userHandle,
+                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
         }
 
         /** @hide */
         public static boolean putStringForUser(@NonNull ContentResolver resolver,
                 @NonNull String name, @Nullable String value, @Nullable String tag,
-                boolean makeDefault, @UserIdInt int userHandle) {
+                boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore) {
             if (LOCAL_LOGV) {
                 Log.v(TAG, "Global.putString(name=" + name + ", value=" + value
                         + " for " + userHandle);
@@ -13067,10 +13147,10 @@
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Global"
                         + " to android.provider.Settings.Secure, value is unchanged.");
                 return Secure.putStringForUser(resolver, name, value, tag,
-                        makeDefault, userHandle);
+                        makeDefault, userHandle, overrideableByRestore);
             }
             return sNameValueCache.putStringForUser(resolver, name, value, tag,
-                    makeDefault, userHandle);
+                    makeDefault, userHandle, overrideableByRestore);
         }
 
         /**
@@ -13937,7 +14017,8 @@
         static boolean putString(@NonNull ContentResolver resolver, @NonNull String namespace,
                 @NonNull String name, @Nullable String value, boolean makeDefault) {
             return sNameValueCache.putStringForUser(resolver, createCompositeName(namespace, name),
-                    value, null, makeDefault, resolver.getUserId());
+                    value, null, makeDefault, resolver.getUserId(),
+                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
         }
 
         /**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c191a0d..eb4af1c 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -61,7 +61,7 @@
         DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
         DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
         DEFAULT_FLAGS.put("settings_conditionals", "false");
-        DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+        DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
     }
 
     /**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ff8455a..cc4278b 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -122,6 +122,8 @@
     private static native void nativeSetColor(long transactionObj, long nativeObject, float[] color);
     private static native void nativeSetFlags(long transactionObj, long nativeObject,
             int flags, int mask);
+    private static native void nativeSetFrameRateSelectionPriority(long transactionObj,
+            long nativeObject, int priority);
     private static native void nativeSetWindowCrop(long transactionObj, long nativeObject,
             int l, int t, int r, int b);
     private static native void nativeSetCornerRadius(long transactionObj, long nativeObject,
@@ -2245,6 +2247,19 @@
         }
 
         /**
+         * This information is passed to SurfaceFlinger to decide which window should have a
+         * priority when deciding about the refresh rate of the display. All windows have the
+         * lowest priority by default.
+         * @hide
+         */
+        @NonNull
+        public Transaction setFrameRateSelectionPriority(@NonNull SurfaceControl sc, int priority) {
+            sc.checkNotReleased();
+            nativeSetFrameRateSelectionPriority(mNativeObject, sc.mNativeObject, priority);
+            return this;
+        }
+
+        /**
          * Request that a given surface and it's sub-tree be shown.
          *
          * @param sc The surface to show.
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b47080f..573f378 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -423,6 +423,14 @@
     transaction->setFlags(ctrl, flags, mask);
 }
 
+static void nativeSetFrameRateSelectionPriority(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jint priority) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    transaction->setFrameRateSelectionPriority(ctrl, priority);
+}
+
 static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong transactionObj,
         jlong nativeObject, jobject regionObj) {
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -1362,6 +1370,8 @@
             (void*)nativeSetColorSpaceAgnostic },
     {"nativeSetFlags", "(JJII)V",
             (void*)nativeSetFlags },
+    {"nativeSetFrameRateSelectionPriority", "(JJI)V",
+            (void*)nativeSetFrameRateSelectionPriority },
     {"nativeSetWindowCrop", "(JJIIII)V",
             (void*)nativeSetWindowCrop },
     {"nativeSetCornerRadius", "(JJF)V",
diff --git a/core/proto/android/stats/sysui/notification_enums.proto b/core/proto/android/stats/sysui/notification_enums.proto
new file mode 100644
index 0000000..0983702
--- /dev/null
+++ b/core/proto/android/stats/sysui/notification_enums.proto
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.stats.sysui;
+
+// Enum used in NotificationReported and NotificationChannelModified atoms
+enum NotificationImportance {  // Constants from NotificationManager.java
+  IMPORTANCE_UNSPECIFIED = -1000;  // Should not occur for real notifications.
+  IMPORTANCE_NONE = 0;  // No importance: does not show in the shade.
+  IMPORTANCE_MIN = 1;  // Minimum to show in the shade.
+  IMPORTANCE_LOW = 2;  // Shows in shade, maybe status bar, no buzz/beep.
+  IMPORTANCE_DEFAULT = 3;  // Shows everywhere, makes noise, no heads-up.
+  IMPORTANCE_HIGH = 4;  // Shows everywhere, makes noise, heads-up, may full-screen.
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2665e8a..0bc16a3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3980,6 +3980,13 @@
     <permission android:name="android.permission.BACKUP"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to make modifications to device settings such that these
+         modifications will be overridden by settings restore..
+    <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE"
+                android:protectionLevel="signature|setup" />
+
     <!-- @SystemApi Allows application to manage
          {@link android.security.keystore.recovery.RecoveryController}.
          <p>Not for use by third-party applications.
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 0574775..877ef26 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -180,7 +180,6 @@
     <assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" />
     <assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" />
 
-    <assign-permission name="android.permission.BATTERY_STATS" uid="statsd" />
     <assign-permission name="android.permission.DUMP" uid="statsd" />
     <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" />
     <assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index b93759f..c445885 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -108,10 +108,26 @@
     }
 }
 
+// FIXME: Share with the version in android_bitmap.cpp?
+// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut
+// matches the white point used by ColorSpace.Named.DCIP3.
+static constexpr skcms_Matrix3x3 kDCIP3 = {{
+        {0.486143, 0.323835, 0.154234},
+        {0.226676, 0.710327, 0.0629966},
+        {0.000800549, 0.0432385, 0.78275},
+}};
+
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
     if (dataspace == HAL_DATASPACE_UNKNOWN) {
         return SkColorSpace::MakeSRGB();
     }
+    if (dataspace == HAL_DATASPACE_DCI_P3) {
+        // This cannot be handled by the switch statements below because it
+        // needs to use the locally-defined kDCIP3 gamut, rather than the one in
+        // Skia (SkNamedGamut), which is used for other data spaces with
+        // HAL_DATASPACE_STANDARD_DCI_P3 (e.g. HAL_DATASPACE_DISPLAY_P3).
+        return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, kDCIP3);
+    }
 
     skcms_Matrix3x3 gamut;
     switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
@@ -152,10 +168,12 @@
             return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
         case HAL_DATASPACE_TRANSFER_GAMMA2_8:
             return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+        case HAL_DATASPACE_TRANSFER_ST2084:
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+        case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
         case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
             return nullptr;
-        case HAL_DATASPACE_TRANSFER_SMPTE_170M:
-        case HAL_DATASPACE_TRANSFER_ST2084:
         case HAL_DATASPACE_TRANSFER_HLG:
         default:
             ALOGV("Unsupported Gamma: %d", dataspace);
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 5a72b22..18969ae 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -16,6 +16,7 @@
 
 package android.media.tv.tuner;
 
+import android.annotation.BytesLong;
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -27,6 +28,8 @@
 import android.media.tv.tuner.TunerConstants.FrontendScanType;
 import android.media.tv.tuner.TunerConstants.Result;
 import android.media.tv.tuner.dvr.Dvr;
+import android.media.tv.tuner.dvr.DvrCallback;
+import android.media.tv.tuner.dvr.DvrSettings;
 import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
 import android.media.tv.tuner.filter.FilterEvent;
 import android.media.tv.tuner.filter.TimeFilter;
@@ -88,6 +91,31 @@
         nativeSetup();
     }
 
+    /**
+     * Constructs a Tuner instance.
+     *
+     * @param context the context of the caller.
+     * @param tvInputSessionId the session ID of the TV input.
+     * @param useCase the use case of this Tuner instance.
+     *
+     * @hide
+     * TODO: replace the other constructor
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    public Tuner(@NonNull Context context, @NonNull String tvInputSessionId, int useCase) {
+        mContext = context;
+    }
+
+    /**
+     * Shares the frontend resource with another Tuner instance
+     *
+     * @param tuner the Tuner instance to share frontend resource with.
+     *
+     * @hide
+     */
+    public void shareFrontend(@NonNull Tuner tuner) { }
+
+
     private long mNativeContext; // used by native jMediaTuner
 
     /** @hide */
@@ -125,7 +153,7 @@
     private native int nativeConnectCiCam(int ciCamId);
     private native int nativeDisconnectCiCam();
     private native FrontendInfo nativeGetFrontendInfo(int id);
-    private native Filter nativeOpenFilter(int type, int subType, int bufferSize);
+    private native Filter nativeOpenFilter(int type, int subType, long bufferSize);
     private native TimeFilter nativeOpenTimeFilter();
 
     private native List<Integer> nativeGetLnbIds();
@@ -133,7 +161,7 @@
 
     private native Descrambler nativeOpenDescrambler();
 
-    private native Dvr nativeOpenDvr(int type, int bufferSize);
+    private native Dvr nativeOpenDvr(int type, long bufferSize);
 
     private static native DemuxCapabilities nativeGetDemuxCapabilities();
 
@@ -159,6 +187,21 @@
         void onFilterStatusChanged(@NonNull Filter filter, @FilterStatus int status);
     }
 
+
+    /**
+     * Listener for resource lost.
+     *
+     * @hide
+     */
+    public interface OnResourceLostListener {
+        /**
+         * Invoked when resource lost.
+         *
+         * @param tuner the tuner instance whose resource is being reclaimed.
+         */
+        void onResourceLost(@NonNull Tuner tuner);
+    }
+
     @Nullable
     private EventHandler createEventHandler() {
         Looper looper;
@@ -221,23 +264,32 @@
     /**
      * Stops a previous tuning.
      *
-     * If the method completes successfully the frontend is no longer tuned and no data
+     * <p>If the method completes successfully, the frontend is no longer tuned and no data
      * will be sent to attached filters.
      *
      * @return result status of the operation.
+     *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Result
     public int stopTune() {
+        TunerUtils.checkTunerPermission(mContext);
         return nativeStopTune();
     }
 
     /**
      * Scan channels.
+     *
+     * @param settings A {@link FrontendSettings} to configure the frontend.
+     * @param scanType The scan type.
+     *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType,
             @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) {
+        TunerUtils.checkTunerPermission(mContext);
         mScanCallback = scanCallback;
         mScanCallbackExecutor = executor;
         return nativeScan(settings.getType(), settings, scanType);
@@ -255,6 +307,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Result
     public int stopScan() {
         TunerUtils.checkTunerPermission(mContext);
         int retVal = nativeStopScan();
@@ -266,37 +319,44 @@
     /**
      * Sets Low-Noise Block downconverter (LNB) for satellite frontend.
      *
-     * This assigns a hardware LNB resource to the satellite tuner. It can be
+     * <p>This assigns a hardware LNB resource to the satellite tuner. It can be
      * called multiple times to update LNB assignment.
      *
      * @param lnb the LNB instance.
      *
      * @return result status of the operation.
+     *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Result
     public int setLnb(@NonNull Lnb lnb) {
+        TunerUtils.checkTunerPermission(mContext);
         return nativeSetLnb(lnb.mId);
     }
 
     /**
      * Enable or Disable Low Noise Amplifier (LNA).
      *
-     * @param enable true to activate LNA module; false to deactivate LNA
+     * @param enable {@code true} to activate LNA module; {@code false} to deactivate LNA.
      *
      * @return result status of the operation.
+     *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Result
     public int setLna(boolean enable) {
+        TunerUtils.checkTunerPermission(mContext);
         return nativeSetLna(enable);
     }
 
     /**
      * Gets the statuses of the frontend.
      *
-     * This retrieve the statuses of the frontend for given status types.
+     * <p>This retrieve the statuses of the frontend for given status types.
      *
-     * @param statusTypes an array of status type which the caller request.
-     *
+     * @param statusTypes an array of status types which the caller requests.
      * @return statuses which response the caller's requests.
      * @hide
      */
@@ -310,59 +370,77 @@
      *
      * @param filter the filter instance for the hardware sync ID.
      * @return the id of hardware A/V sync.
+     *
      * @hide
      */
-    public int getAvSyncHwId(Filter filter) {
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    public int getAvSyncHwId(@NonNull Filter filter) {
+        TunerUtils.checkTunerPermission(mContext);
         return nativeGetAvSyncHwId(filter);
     }
+
     /**
-     * Gets the current timestamp for A/V sync
+     * Gets the current timestamp for Audio/Video sync
      *
-     * The timestamp is maintained by hardware. The timestamp based on 90KHz, and it's format is the
-     * same as PTS (Presentation Time Stamp).
+     * <p>The timestamp is maintained by hardware. The timestamp based on 90KHz, and it's format is
+     * the same as PTS (Presentation Time Stamp).
      *
      * @param avSyncHwId the hardware id of A/V sync.
      * @return the current timestamp of hardware A/V sync.
+     *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public long getAvSyncTime(int avSyncHwId) {
+        TunerUtils.checkTunerPermission(mContext);
         return nativeGetAvSyncTime(avSyncHwId);
     }
 
-
     /**
      * Connects Conditional Access Modules (CAM) through Common Interface (CI)
      *
-     * The demux uses the output from the frontend as the input by default, and must change to use
-     * the output from CI-CAM as the input after this call.
+     * <p>The demux uses the output from the frontend as the input by default, and must change to
+     * use the output from CI-CAM as the input after this call.
      *
      * @param ciCamId specify CI-CAM Id to connect.
      * @return result status of the operation.
+     *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int connectCiCam(int ciCamId) {
+        TunerUtils.checkTunerPermission(mContext);
         return nativeConnectCiCam(ciCamId);
     }
 
     /**
      * Disconnects Conditional Access Modules (CAM)
      *
-     * The demux will use the output from the frontend as the input after this call.
+     * <p>The demux will use the output from the frontend as the input after this call.
      *
      * @return result status of the operation.
+     *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int disconnectCiCam() {
+        TunerUtils.checkTunerPermission(mContext);
         return nativeDisconnectCiCam();
     }
 
     /**
-     * Retrieve the frontend information.
+     * Gets the frontend information.
+     *
+     * @return The frontend information. {@code null} if the operation failed.
+     *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Nullable
     public FrontendInfo getFrontendInfo() {
+        TunerUtils.checkTunerPermission(mContext);
         if (mFrontend == null) {
             throw new IllegalStateException("frontend is not initialized");
         }
@@ -370,10 +448,13 @@
     }
 
     /**
-     * Gets frontend ID.
+     * Gets the frontend ID.
+     *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public int getFrontendId() {
+        TunerUtils.checkTunerPermission(mContext);
         if (mFrontend == null) {
             throw new IllegalStateException("frontend is not initialized");
         }
@@ -382,6 +463,7 @@
 
     /**
      * Gets Demux capabilities.
+     *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@@ -424,8 +506,26 @@
         private Filter() {}
     }
 
-    private Filter openFilter(@FilterType int mainType, @FilterSubtype int subType, int bufferSize,
-            FilterCallback cb) {
+    /**
+     * Opens a filter object based on the given types and buffer size.
+     *
+     * @param mainType the main type of the filter.
+     * @param subType the subtype of the filter.
+     * @param bufferSize the buffer size of the filter to be opened in bytes. The buffer holds the
+     * data output from the filter.
+     * @param cb the callback to receive notifications from filter.
+     * @param executor the executor on which callback will be invoked. The default event handler
+     * executor is used if it's {@code null}.
+     * @return the opened filter. {@code null} if the operation failed.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Nullable
+    public Filter openFilter(@FilterType int mainType, @FilterSubtype int subType,
+            @BytesLong long bufferSize, @Nullable FilterCallback cb,
+            @CallbackExecutor @Nullable Executor executor) {
+        TunerUtils.checkTunerPermission(mContext);
         Filter filter = nativeOpenFilter(
                 mainType, TunerUtils.getFilterSubtype(mainType, subType), bufferSize);
         if (filter != null) {
@@ -437,6 +537,24 @@
         return filter;
     }
 
+    /**
+     * Opens an LNB (low-noise block downconverter) object.
+     *
+     * @param cb the callback to receive notifications from LNB.
+     * @param executor the executor on which callback will be invoked. The default event handler
+     * executor is used if it's {@code null}.
+     * @return the opened LNB object. {@code null} if the operation failed.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Nullable
+    public Lnb openLnb(LnbCallback cb, @CallbackExecutor @Nullable Executor executor) {
+        TunerUtils.checkTunerPermission(mContext);
+        // TODO: use resource manager to get LNB ID.
+        return new Lnb(0);
+    }
+
     private List<Integer> getLnbIds() {
         mLnbIds = nativeGetLnbIds();
         return mLnbIds;
@@ -484,7 +602,24 @@
         return nativeOpenDescrambler();
     }
 
-    private Dvr openDvr(int type, int bufferSize) {
+    /**
+     * Open a DVR (Digital Video Record) instance.
+     *
+     * @param type the DVR type to be opened.
+     * @param bufferSize the buffer size of the output in bytes. It's used to hold output data of
+     * the attached filters.
+     * @param cb the callback to receive notifications from DVR.
+     * @param executor the executor on which callback will be invoked. The default event handler
+     * executor is used if it's {@code null}.
+     * @return the opened DVR object. {@code null} if the operation failed.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Nullable
+    public Dvr openDvr(@DvrSettings.Type int type, @BytesLong long bufferSize, DvrCallback cb,
+            @CallbackExecutor @Nullable Executor executor) {
+        TunerUtils.checkTunerPermission(mContext);
         Dvr dvr = nativeOpenDvr(type, bufferSize);
         return dvr;
     }
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index 19cfa32..fa8f550 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -129,93 +129,29 @@
      */
     public static final int FILTER_STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW;
 
-    /**
-     * Indexes can be tagged through TS (Transport Stream) header.
-     *
-     * @hide
-     */
-    @IntDef(flag = true, value = {TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
-            TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
-            TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR,
-            TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR, TS_INDEX_PCR_FLAG,
-            TS_INDEX_OPCR_FLAG, TS_INDEX_SPLICING_POINT_FLAG, TS_INDEX_PRIVATE_DATA,
-            TS_INDEX_ADAPTATION_EXTENSION_FLAG})
+
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    public @interface TsIndex {}
+    @IntDef(prefix = "INDEX_TYPE_", value =
+            {INDEX_TYPE_NONE, INDEX_TYPE_SC, INDEX_TYPE_SC_HEVC})
+    public @interface ScIndexType {}
 
     /**
-     * TS index FIRST_PACKET.
+     * Start Code Index is not used.
      * @hide
      */
-    public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET;
+    public static final int INDEX_TYPE_NONE = Constants.DemuxRecordScIndexType.NONE;
     /**
-     * TS index PAYLOAD_UNIT_START_INDICATOR.
+     * Start Code index.
      * @hide
      */
-    public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR =
-            Constants.DemuxTsIndex.PAYLOAD_UNIT_START_INDICATOR;
+    public static final int INDEX_TYPE_SC = Constants.DemuxRecordScIndexType.SC;
     /**
-     * TS index CHANGE_TO_NOT_SCRAMBLED.
+     * Start Code index for HEVC.
      * @hide
      */
-    public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED =
-            Constants.DemuxTsIndex.CHANGE_TO_NOT_SCRAMBLED;
-    /**
-     * TS index CHANGE_TO_EVEN_SCRAMBLED.
-     * @hide
-     */
-    public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED =
-            Constants.DemuxTsIndex.CHANGE_TO_EVEN_SCRAMBLED;
-    /**
-     * TS index CHANGE_TO_ODD_SCRAMBLED.
-     * @hide
-     */
-    public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED =
-            Constants.DemuxTsIndex.CHANGE_TO_ODD_SCRAMBLED;
-    /**
-     * TS index DISCONTINUITY_INDICATOR.
-     * @hide
-     */
-    public static final int TS_INDEX_DISCONTINUITY_INDICATOR =
-            Constants.DemuxTsIndex.DISCONTINUITY_INDICATOR;
-    /**
-     * TS index RANDOM_ACCESS_INDICATOR.
-     * @hide
-     */
-    public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR =
-            Constants.DemuxTsIndex.RANDOM_ACCESS_INDICATOR;
-    /**
-     * TS index PRIORITY_INDICATOR.
-     * @hide
-     */
-    public static final int TS_INDEX_PRIORITY_INDICATOR = Constants.DemuxTsIndex.PRIORITY_INDICATOR;
-    /**
-     * TS index PCR_FLAG.
-     * @hide
-     */
-    public static final int TS_INDEX_PCR_FLAG = Constants.DemuxTsIndex.PCR_FLAG;
-    /**
-     * TS index OPCR_FLAG.
-     * @hide
-     */
-    public static final int TS_INDEX_OPCR_FLAG = Constants.DemuxTsIndex.OPCR_FLAG;
-    /**
-     * TS index SPLICING_POINT_FLAG.
-     * @hide
-     */
-    public static final int TS_INDEX_SPLICING_POINT_FLAG =
-            Constants.DemuxTsIndex.SPLICING_POINT_FLAG;
-    /**
-     * TS index PRIVATE_DATA.
-     * @hide
-     */
-    public static final int TS_INDEX_PRIVATE_DATA = Constants.DemuxTsIndex.PRIVATE_DATA;
-    /**
-     * TS index ADAPTATION_EXTENSION_FLAG.
-     * @hide
-     */
-    public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG =
-            Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
+    public static final int INDEX_TYPE_SC_HEVC = Constants.DemuxRecordScIndexType.SC_HEVC;
+
 
     /**
      * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index f0fe533..fcca6a1 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -16,20 +16,123 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Filter configuration for a ALP filter.
  * @hide
  */
 public class AlpFilterConfiguration extends FilterConfiguration {
-    private int mPacketType;
-    private int mLengthType;
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "LENGTH_TYPE_", value =
+            {LENGTH_TYPE_UNDEFINED, LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER,
+            LENGTH_TYPE_WITH_ADDITIONAL_HEADER})
+    public @interface LengthType {}
 
-    public AlpFilterConfiguration(Settings settings) {
+    /**
+     * Length type not defined.
+     */
+    public static final int LENGTH_TYPE_UNDEFINED = Constants.DemuxAlpLengthType.UNDEFINED;
+    /**
+     * Length does NOT include additional header.
+     */
+    public static final int LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER =
+            Constants.DemuxAlpLengthType.WITHOUT_ADDITIONAL_HEADER;
+    /**
+     * Length includes additional header.
+     */
+    public static final int LENGTH_TYPE_WITH_ADDITIONAL_HEADER =
+            Constants.DemuxAlpLengthType.WITH_ADDITIONAL_HEADER;
+
+
+    private final int mPacketType;
+    private final int mLengthType;
+
+    public AlpFilterConfiguration(Settings settings, int packetType, int lengthType) {
         super(settings);
+        mPacketType = packetType;
+        mLengthType = lengthType;
     }
 
     @Override
     public int getType() {
         return FilterConfiguration.FILTER_TYPE_ALP;
     }
+
+    /**
+     * Gets packet type.
+     */
+    @FilterConfiguration.PacketType
+    public int getPacketType() {
+        return mPacketType;
+    }
+    /**
+     * Gets length type.
+     */
+    @LengthType
+    public int getLengthType() {
+        return mLengthType;
+    }
+
+    /**
+     * Creates a builder for {@link AlpFilterConfiguration}.
+     *
+     * @param context the context of the caller.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @NonNull
+    public static Builder builder(@NonNull Context context) {
+        TunerUtils.checkTunerPermission(context);
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link AlpFilterConfiguration}.
+     */
+    public static class Builder extends FilterConfiguration.Builder<Builder> {
+        private int mPacketType;
+        private int mLengthType;
+
+        private Builder() {
+        }
+
+        /**
+         * Sets packet type.
+         */
+        @NonNull
+        public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+            mPacketType = packetType;
+            return this;
+        }
+        /**
+         * Sets length type.
+         */
+        @NonNull
+        public Builder setLengthType(@LengthType int lengthType) {
+            mLengthType = lengthType;
+            return this;
+        }
+
+        /**
+         * Builds a {@link AlpFilterConfiguration} object.
+         */
+        @NonNull
+        public AlpFilterConfiguration build() {
+            return new AlpFilterConfiguration(mSettings, mPacketType, mLengthType);
+        }
+
+        @Override
+        Builder self() {
+            return this;
+        }
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
index a7c49d5..940b5ae 100644
--- a/media/java/android/media/tv/tuner/filter/AvSettings.java
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -16,21 +16,84 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
 import android.media.tv.tuner.TunerConstants;
 import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
 
 /**
  * Filter Settings for a Video and Audio.
+ *
  * @hide
  */
 public class AvSettings extends Settings {
-    private boolean mIsPassthrough;
+    private final boolean mIsPassthrough;
 
-    private AvSettings(int mainType, boolean isAudio) {
+    private AvSettings(int mainType, boolean isAudio, boolean isPassthrough) {
         super(TunerUtils.getFilterSubtype(
                 mainType,
                 isAudio
                         ? TunerConstants.FILTER_SUBTYPE_AUDIO
                         : TunerConstants.FILTER_SUBTYPE_VIDEO));
+        mIsPassthrough = isPassthrough;
+    }
+
+    /**
+     * Checks whether it's passthrough.
+     */
+    public boolean isPassthrough() {
+        return mIsPassthrough;
+    }
+
+    /**
+     * Creates a builder for {@link AvSettings}.
+     *
+     * @param context the context of the caller.
+     * @param mainType the filter main type.
+     * @param isAudio {@code true} if it's audio settings; {@code false} if it's video settings.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @NonNull
+    public static Builder builder(
+            @NonNull Context context, @FilterType int mainType, boolean isAudio) {
+        TunerUtils.checkTunerPermission(context);
+        return new Builder(mainType, isAudio);
+    }
+
+    /**
+     * Builder for {@link AvSettings}.
+     */
+    public static class Builder extends Settings.Builder<Builder> {
+        private final boolean mIsAudio;
+        private boolean mIsPassthrough;
+
+        private Builder(int mainType, boolean isAudio) {
+            super(mainType);
+            mIsAudio = isAudio;
+        }
+
+        /**
+         * Sets whether it's passthrough.
+         */
+        @NonNull
+        public Builder setPassthrough(boolean isPassthrough) {
+            mIsPassthrough = isPassthrough;
+            return this;
+        }
+
+        /**
+         * Builds a {@link AvSettings} object.
+         */
+        @NonNull
+        public AvSettings build() {
+            return new AvSettings(mMainType, mIsAudio, mIsPassthrough);
+        }
+
+        @Override
+        Builder self() {
+            return this;
+        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/filter/DownloadSettings.java b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
index 0742b11..e3e1df0 100644
--- a/media/java/android/media/tv/tuner/filter/DownloadSettings.java
+++ b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
@@ -16,17 +16,75 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
 import android.media.tv.tuner.TunerConstants;
 import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
 
 /**
  * Filter Settings for a Download.
  * @hide
  */
 public class DownloadSettings extends Settings {
-    private int mDownloadId;
+    private final int mDownloadId;
 
-    public DownloadSettings(int mainType) {
+    private DownloadSettings(int mainType, int downloadId) {
         super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_DOWNLOAD));
+        mDownloadId = downloadId;
+    }
+
+    /**
+     * Gets download ID.
+     */
+    public int getDownloadId() {
+        return mDownloadId;
+    }
+
+    /**
+     * Creates a builder for {@link DownloadSettings}.
+     *
+     * @param context the context of the caller.
+     * @param mainType the filter main type.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @NonNull
+    public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+        TunerUtils.checkTunerPermission(context);
+        return new Builder(mainType);
+    }
+
+    /**
+     * Builder for {@link DownloadSettings}.
+     */
+    public static class Builder extends Settings.Builder<Builder> {
+        private int mDownloadId;
+
+        private Builder(int mainType) {
+            super(mainType);
+        }
+
+        /**
+         * Sets download ID.
+         */
+        @NonNull
+        public Builder setDownloadId(int downloadId) {
+            mDownloadId = downloadId;
+            return this;
+        }
+
+        /**
+         * Builds a {@link DownloadSettings} object.
+         */
+        @NonNull
+        public DownloadSettings build() {
+            return new DownloadSettings(mMainType, mDownloadId);
+        }
+
+        @Override
+        Builder self() {
+            return this;
+        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
index 6496627..68c722f 100644
--- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -33,7 +33,8 @@
 public abstract class FilterConfiguration {
 
     /** @hide */
-    @IntDef({FILTER_TYPE_TS, FILTER_TYPE_MMTP, FILTER_TYPE_IP, FILTER_TYPE_TLV, FILTER_TYPE_ALP})
+    @IntDef(prefix = "FILTER_TYPE_", value =
+            {FILTER_TYPE_TS, FILTER_TYPE_MMTP, FILTER_TYPE_IP, FILTER_TYPE_TLV, FILTER_TYPE_ALP})
     @Retention(RetentionPolicy.SOURCE)
     public @interface FilterType {}
 
@@ -58,6 +59,30 @@
      */
     public static final int FILTER_TYPE_ALP = Constants.DemuxFilterMainType.ALP;
 
+
+    /** @hide */
+    @IntDef(prefix = "PACKET_TYPE_", value =
+            {PACKET_TYPE_IPV4, PACKET_TYPE_COMPRESSED, PACKET_TYPE_SIGNALING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PacketType {}
+
+    /**
+     * IP v4 packet type.
+     * @hide
+     */
+    public static final int PACKET_TYPE_IPV4 = 0;
+    /**
+     * Compressed packet type.
+     * @hide
+     */
+    public static final int PACKET_TYPE_COMPRESSED = 2;
+    /**
+     * Signaling packet type.
+     * @hide
+     */
+    public static final int PACKET_TYPE_SIGNALING = 4;
+
+
     @Nullable
     /* package */ final Settings mSettings;
 
@@ -77,4 +102,27 @@
     public Settings getSettings() {
         return mSettings;
     }
+
+    /**
+     * Builder for {@link FilterConfiguration}.
+     *
+     * @param <T> The subclass to be built.
+     * @hide
+     */
+    public abstract static class Builder<T extends Builder<T>> {
+        /* package */ Settings mSettings;
+
+        /* package */ Builder() {
+        }
+
+        /**
+         * Sets filter settings.
+         */
+        @Nullable
+        public T setFrequency(Settings settings) {
+            mSettings = settings;
+            return self();
+        }
+        /* package */ abstract T self();
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index c896368..98edf10 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -16,23 +16,152 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.Size;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+
 /**
  * Filter configuration for a IP filter.
  * @hide
  */
 public class IpFilterConfiguration extends FilterConfiguration {
-    private byte[] mSrcIpAddress;
-    private byte[] mDstIpAddress;
-    private int mSrcPort;
-    private int mDstPort;
-    private boolean mPassthrough;
+    private final byte[] mSrcIpAddress;
+    private final byte[] mDstIpAddress;
+    private final int mSrcPort;
+    private final int mDstPort;
+    private final boolean mPassthrough;
 
-    public IpFilterConfiguration(Settings settings) {
+    public IpFilterConfiguration(Settings settings, byte[] srcAddr, byte[] dstAddr, int srcPort,
+            int dstPort, boolean passthrough) {
         super(settings);
+        mSrcIpAddress = srcAddr;
+        mDstIpAddress = dstAddr;
+        mSrcPort = srcPort;
+        mDstPort = dstPort;
+        mPassthrough = passthrough;
     }
 
     @Override
     public int getType() {
         return FilterConfiguration.FILTER_TYPE_IP;
     }
+
+    /**
+     * Gets source IP address.
+     */
+    @Size(min = 4, max = 16)
+    public byte[] getSrcIpAddress() {
+        return mSrcIpAddress;
+    }
+    /**
+     * Gets destination IP address.
+     */
+    @Size(min = 4, max = 16)
+    public byte[] getDstIpAddress() {
+        return mDstIpAddress;
+    }
+    /**
+     * Gets source port.
+     */
+    public int getSrcPort() {
+        return mSrcPort;
+    }
+    /**
+     * Gets destination port.
+     */
+    public int getDstPort() {
+        return mDstPort;
+    }
+    /**
+     * Checks whether the filter is passthrough.
+     *
+     * @return {@code true} if the data from IP subtype go to next filter directly;
+     *         {@code false} otherwise.
+     */
+    public boolean isPassthrough() {
+        return mPassthrough;
+    }
+
+    /**
+     * Creates a builder for {@link IpFilterConfiguration}.
+     *
+     * @param context the context of the caller.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @NonNull
+    public static Builder builder(@NonNull Context context) {
+        TunerUtils.checkTunerPermission(context);
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link IpFilterConfiguration}.
+     */
+    public static class Builder extends FilterConfiguration.Builder<Builder> {
+        private byte[] mSrcIpAddress;
+        private byte[] mDstIpAddress;
+        private int mSrcPort;
+        private int mDstPort;
+        private boolean mPassthrough;
+
+        private Builder() {
+        }
+
+        /**
+         * Sets source IP address.
+         */
+        @NonNull
+        public Builder setSrcIpAddress(byte[] srcIpAddress) {
+            mSrcIpAddress = srcIpAddress;
+            return this;
+        }
+        /**
+         * Sets destination IP address.
+         */
+        @NonNull
+        public Builder setDstIpAddress(byte[] dstIpAddress) {
+            mDstIpAddress = dstIpAddress;
+            return this;
+        }
+        /**
+         * Sets source port.
+         */
+        @NonNull
+        public Builder setSrcPort(int srcPort) {
+            mSrcPort = srcPort;
+            return this;
+        }
+        /**
+         * Sets destination port.
+         */
+        @NonNull
+        public Builder setDstPort(int dstPort) {
+            mDstPort = dstPort;
+            return this;
+        }
+        /**
+         * Sets passthrough.
+         */
+        @NonNull
+        public Builder setPassthrough(boolean passthrough) {
+            mPassthrough = passthrough;
+            return this;
+        }
+
+        /**
+         * Builds a {@link IpFilterConfiguration} object.
+         */
+        @NonNull
+        public IpFilterConfiguration build() {
+            return new IpFilterConfiguration(
+                    mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, mPassthrough);
+        }
+
+        @Override
+        Builder self() {
+            return this;
+        }
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
index 9045ce6..83246e5 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
@@ -16,19 +16,78 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+
 /**
  * Filter configuration for a MMTP filter.
  * @hide
  */
 public class MmtpFilterConfiguration extends FilterConfiguration {
-    private int mMmtpPid;
+    private final int mMmtpPid;
 
-    public MmtpFilterConfiguration(Settings settings) {
+    public MmtpFilterConfiguration(Settings settings, int mmtpPid) {
         super(settings);
+        mMmtpPid = mmtpPid;
     }
 
     @Override
     public int getType() {
         return FilterConfiguration.FILTER_TYPE_MMTP;
     }
+
+    /**
+     * Gets MMPT PID.
+     *
+     * <p>Packet ID is used to specify packets in MMTP.
+     */
+    public int getMmtpPid() {
+        return mMmtpPid;
+    }
+
+    /**
+     * Creates a builder for {@link IpFilterConfiguration}.
+     *
+     * @param context the context of the caller.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @NonNull
+    public static Builder builder(@NonNull Context context) {
+        TunerUtils.checkTunerPermission(context);
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link IpFilterConfiguration}.
+     */
+    public static class Builder extends FilterConfiguration.Builder<Builder> {
+        private int mMmtpPid;
+
+        private Builder() {
+        }
+
+        /**
+         * Sets MMPT PID.
+         */
+        @NonNull
+        public Builder setMmtpPid(int mmtpPid) {
+            mMmtpPid = mmtpPid;
+            return this;
+        }
+
+        /**
+         * Builds a {@link IpFilterConfiguration} object.
+         */
+        @NonNull
+        public MmtpFilterConfiguration build() {
+            return new MmtpFilterConfiguration(mSettings, mMmtpPid);
+        }
+
+        @Override
+        Builder self() {
+            return this;
+        }
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index 701868a..4833709 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -16,18 +16,231 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.hardware.tv.tuner.V1_0.Constants;
 import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerConstants.ScIndexType;
 import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * The Settings for the record in DVR.
  * @hide
  */
 public class RecordSettings extends Settings {
-    private int mIndexType;
-    private int mIndexMask;
+    /**
+     * Indexes can be tagged through TS (Transport Stream) header.
+     *
+     * @hide
+     */
+    @IntDef(flag = true,
+            prefix = "TS_INDEX_",
+            value = {TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
+                    TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
+                    TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR,
+                    TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR,
+                    TS_INDEX_PCR_FLAG, TS_INDEX_OPCR_FLAG, TS_INDEX_SPLICING_POINT_FLAG,
+                    TS_INDEX_PRIVATE_DATA, TS_INDEX_ADAPTATION_EXTENSION_FLAG})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TsIndexMask {}
 
-    public RecordSettings(int mainType) {
+    /**
+     * TS index FIRST_PACKET.
+     * @hide
+     */
+    public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET;
+    /**
+     * TS index PAYLOAD_UNIT_START_INDICATOR.
+     * @hide
+     */
+    public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR =
+            Constants.DemuxTsIndex.PAYLOAD_UNIT_START_INDICATOR;
+    /**
+     * TS index CHANGE_TO_NOT_SCRAMBLED.
+     * @hide
+     */
+    public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED =
+            Constants.DemuxTsIndex.CHANGE_TO_NOT_SCRAMBLED;
+    /**
+     * TS index CHANGE_TO_EVEN_SCRAMBLED.
+     * @hide
+     */
+    public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED =
+            Constants.DemuxTsIndex.CHANGE_TO_EVEN_SCRAMBLED;
+    /**
+     * TS index CHANGE_TO_ODD_SCRAMBLED.
+     * @hide
+     */
+    public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED =
+            Constants.DemuxTsIndex.CHANGE_TO_ODD_SCRAMBLED;
+    /**
+     * TS index DISCONTINUITY_INDICATOR.
+     * @hide
+     */
+    public static final int TS_INDEX_DISCONTINUITY_INDICATOR =
+            Constants.DemuxTsIndex.DISCONTINUITY_INDICATOR;
+    /**
+     * TS index RANDOM_ACCESS_INDICATOR.
+     * @hide
+     */
+    public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR =
+            Constants.DemuxTsIndex.RANDOM_ACCESS_INDICATOR;
+    /**
+     * TS index PRIORITY_INDICATOR.
+     * @hide
+     */
+    public static final int TS_INDEX_PRIORITY_INDICATOR = Constants.DemuxTsIndex.PRIORITY_INDICATOR;
+    /**
+     * TS index PCR_FLAG.
+     * @hide
+     */
+    public static final int TS_INDEX_PCR_FLAG = Constants.DemuxTsIndex.PCR_FLAG;
+    /**
+     * TS index OPCR_FLAG.
+     * @hide
+     */
+    public static final int TS_INDEX_OPCR_FLAG = Constants.DemuxTsIndex.OPCR_FLAG;
+    /**
+     * TS index SPLICING_POINT_FLAG.
+     * @hide
+     */
+    public static final int TS_INDEX_SPLICING_POINT_FLAG =
+            Constants.DemuxTsIndex.SPLICING_POINT_FLAG;
+    /**
+     * TS index PRIVATE_DATA.
+     * @hide
+     */
+    public static final int TS_INDEX_PRIVATE_DATA = Constants.DemuxTsIndex.PRIVATE_DATA;
+    /**
+     * TS index ADAPTATION_EXTENSION_FLAG.
+     * @hide
+     */
+    public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG =
+            Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
+    /**
+     * @hide
+     */
+    @IntDef(flag = true,
+            prefix = "SC_",
+            value = {
+                TunerConstants.SC_INDEX_I_FRAME,
+                TunerConstants.SC_INDEX_P_FRAME,
+                TunerConstants.SC_INDEX_B_FRAME,
+                TunerConstants.SC_INDEX_SEQUENCE,
+                TunerConstants.SC_HEVC_INDEX_SPS,
+                TunerConstants.SC_HEVC_INDEX_AUD,
+                TunerConstants.SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
+                TunerConstants.SC_HEVC_INDEX_SLICE_BLA_W_RADL,
+                TunerConstants.SC_HEVC_INDEX_SLICE_BLA_N_LP,
+                TunerConstants.SC_HEVC_INDEX_SLICE_IDR_W_RADL,
+                TunerConstants.SC_HEVC_INDEX_SLICE_IDR_N_LP,
+                TunerConstants.SC_HEVC_INDEX_SLICE_TRAIL_CRA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScIndexMask {}
+
+
+    private final int mTsIndexMask;
+    private final int mScIndexType;
+    private final int mScIndexMask;
+
+    private RecordSettings(int mainType, int tsIndexType, int scIndexType, int scIndexMask) {
         super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_RECORD));
+        mTsIndexMask = tsIndexType;
+        mScIndexType = scIndexType;
+        mScIndexMask = scIndexMask;
     }
+
+    /**
+     * Gets TS index mask.
+     */
+    @TsIndexMask
+    public int getTsIndexMask() {
+        return mTsIndexMask;
+    }
+    /**
+     * Gets Start Code index type.
+     */
+    @ScIndexType
+    public int getScIndexType() {
+        return mScIndexType;
+    }
+    /**
+     * Gets Start Code index mask.
+     */
+    @ScIndexMask
+    public int getScIndexMask() {
+        return mScIndexMask;
+    }
+
+    /**
+     * Creates a builder for {@link RecordSettings}.
+     *
+     * @param context the context of the caller.
+     * @param mainType the filter main type.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @NonNull
+    public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+        TunerUtils.checkTunerPermission(context);
+        return new Builder(mainType);
+    }
+
+    /**
+     * Builder for {@link RecordSettings}.
+     */
+    public static class Builder extends Settings.Builder<Builder> {
+        private int mTsIndexMask;
+        private int mScIndexType;
+        private int mScIndexMask;
+
+        private Builder(int mainType) {
+            super(mainType);
+        }
+
+        /**
+         * Sets TS index mask.
+         */
+        @NonNull
+        public Builder setTsIndexMask(@TsIndexMask int indexMask) {
+            mTsIndexMask = indexMask;
+            return this;
+        }
+        /**
+         * Sets index type.
+         */
+        @NonNull
+        public Builder setScIndexType(@ScIndexType int indexType) {
+            mScIndexType = indexType;
+            return this;
+        }
+        /**
+         * Sets Start Code index mask.
+         */
+        @NonNull
+        public Builder setScIndexMask(@ScIndexMask int indexMask) {
+            mScIndexMask = indexMask;
+            return this;
+        }
+
+        /**
+         * Builds a {@link RecordSettings} object.
+         */
+        @NonNull
+        public RecordSettings build() {
+            return new RecordSettings(mMainType, mTsIndexMask, mScIndexType, mScIndexMask);
+        }
+
+        @Override
+        Builder self() {
+            return this;
+        }
+    }
+
 }
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
index 414ea67..0fa982e 100644
--- a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
@@ -16,18 +16,116 @@
 
 package android.media.tv.tuner.filter;
 
-import java.util.List;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
 
 /**
- * Bits Settings for Section Filter.
+ * Bits Settings for Section Filters.
  * @hide
  */
 public class SectionSettingsWithSectionBits extends SectionSettings {
-    private List<Byte> mFilter;
-    private List<Byte> mMask;
-    private List<Byte> mMode;
+    private final byte[] mFilter;
+    private final byte[] mMask;
+    private final byte[] mMode;
 
-    private SectionSettingsWithSectionBits(int mainType) {
+
+    private SectionSettingsWithSectionBits(int mainType, byte[] filter, byte[] mask, byte[] mode) {
         super(mainType);
+        mFilter = filter;
+        mMask = mask;
+        mMode = mode;
+    }
+
+    /**
+     * Gets the bytes configured for Section Filter
+     */
+    public byte[] getFilterBytes() {
+        return mFilter;
+    }
+    /**
+     * Gets bit mask.
+     *
+     * <p>The bits in the bytes are used for filtering.
+     */
+    public byte[] getMask() {
+        return mMask;
+    }
+    /**
+     * Gets mode.
+     *
+     * <p>Do positive match at the bit position of the configured bytes when the bit at same
+     * position of the mode is 0.
+     * <p>Do negative match at the bit position of the configured bytes when the bit at same
+     * position of the mode is 1.
+     */
+    public byte[] getMode() {
+        return mMode;
+    }
+
+    /**
+     * Creates a builder for {@link SectionSettingsWithSectionBits}.
+     *
+     * @param context the context of the caller.
+     * @param mainType the filter main type.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @NonNull
+    public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+        TunerUtils.checkTunerPermission(context);
+        return new Builder(mainType);
+    }
+
+    /**
+     * Builder for {@link SectionSettingsWithSectionBits}.
+     */
+    public static class Builder extends Settings.Builder<Builder> {
+        private byte[] mFilter;
+        private byte[] mMask;
+        private byte[] mMode;
+
+        private Builder(int mainType) {
+            super(mainType);
+        }
+
+        /**
+         * Sets filter bytes.
+         */
+        @NonNull
+        public Builder setFilter(byte[] filter) {
+            mFilter = filter;
+            return this;
+        }
+        /**
+         * Sets bit mask.
+         */
+        @NonNull
+        public Builder setMask(byte[] mask) {
+            mMask = mask;
+            return this;
+        }
+        /**
+         * Sets mode.
+         */
+        @NonNull
+        public Builder setMode(byte[] mode) {
+            mMode = mode;
+            return this;
+        }
+
+        /**
+         * Builds a {@link SectionSettingsWithSectionBits} object.
+         */
+        @NonNull
+        public SectionSettingsWithSectionBits build() {
+            return new SectionSettingsWithSectionBits(mMainType, mFilter, mMask, mMode);
+        }
+
+        @Override
+        Builder self() {
+            return this;
+        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
index 0df1d73..6542b89 100644
--- a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
@@ -16,15 +16,92 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
+
 /**
  * Table information for Section Filter.
  * @hide
  */
 public class SectionSettingsWithTableInfo extends SectionSettings {
-    private int mTableId;
-    private int mVersion;
+    private final int mTableId;
+    private final int mVersion;
 
-    private SectionSettingsWithTableInfo(int mainType) {
+    private SectionSettingsWithTableInfo(int mainType, int tableId, int version) {
         super(mainType);
+        mTableId = tableId;
+        mVersion = version;
     }
+
+    /**
+     * Gets table ID.
+     */
+    public int getTableId() {
+        return mTableId;
+    }
+    /**
+     * Gets version.
+     */
+    public int getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * Creates a builder for {@link SectionSettingsWithTableInfo}.
+     *
+     * @param context the context of the caller.
+     * @param mainType the filter main type.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @NonNull
+    public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+        TunerUtils.checkTunerPermission(context);
+        return new Builder(mainType);
+    }
+
+    /**
+     * Builder for {@link SectionSettingsWithTableInfo}.
+     */
+    public static class Builder extends Settings.Builder<Builder> {
+        private int mTableId;
+        private int mVersion;
+
+        private Builder(int mainType) {
+            super(mainType);
+        }
+
+        /**
+         * Sets table ID.
+         */
+        @NonNull
+        public Builder setTableId(int tableId) {
+            mTableId = tableId;
+            return this;
+        }
+        /**
+         * Sets version.
+         */
+        @NonNull
+        public Builder setVersion(int version) {
+            mVersion = version;
+            return this;
+        }
+
+        /**
+         * Builds a {@link SectionSettingsWithTableInfo} object.
+         */
+        @NonNull
+        public SectionSettingsWithTableInfo build() {
+            return new SectionSettingsWithTableInfo(mMainType, mTableId, mVersion);
+        }
+
+        @Override
+        Builder self() {
+            return this;
+        }
+    }
+
 }
diff --git a/media/java/android/media/tv/tuner/filter/Settings.java b/media/java/android/media/tv/tuner/filter/Settings.java
index 9155926..d697280 100644
--- a/media/java/android/media/tv/tuner/filter/Settings.java
+++ b/media/java/android/media/tv/tuner/filter/Settings.java
@@ -39,4 +39,20 @@
     public int getType() {
         return mType;
     }
+
+
+    /**
+     * Builder for {@link Settings}.
+     *
+     * @param <T> The subclass to be built.
+     * @hide
+     */
+    public abstract static class Builder<T extends Builder<T>> {
+        /* package */ final int mMainType;
+
+        /* package */ Builder(int mainType) {
+            mMainType = mainType;
+        }
+        /* package */ abstract T self();
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
index de8ee75..eb97fc0 100644
--- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -16,21 +16,118 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+
 /**
  * Filter configuration for a TLV filter.
  * @hide
  */
 public class TlvFilterConfiguration extends FilterConfiguration {
-    private int mPacketType;
-    private boolean mIsCompressedIpPacket;
-    private boolean mPassthrough;
+    private final int mPacketType;
+    private final boolean mIsCompressedIpPacket;
+    private final boolean mPassthrough;
 
-    public TlvFilterConfiguration(Settings settings) {
+    public TlvFilterConfiguration(Settings settings, int packetType, boolean isCompressed,
+            boolean passthrough) {
         super(settings);
+        mPacketType = packetType;
+        mIsCompressedIpPacket = isCompressed;
+        mPassthrough = passthrough;
     }
 
     @Override
     public int getType() {
         return FilterConfiguration.FILTER_TYPE_TLV;
     }
+
+    /**
+     * Gets packet type.
+     */
+    @FilterConfiguration.PacketType
+    public int getPacketType() {
+        return mPacketType;
+    }
+    /**
+     * Checks whether the data is compressed IP packet.
+     *
+     * @return {@code true} if the filtered data is compressed IP packet; {@code false} otherwise.
+     */
+    public boolean isCompressedIpPacket() {
+        return mIsCompressedIpPacket;
+    }
+    /**
+     * Checks whether it's passthrough.
+     *
+     * @return {@code true} if the data from TLV subtype go to next filter directly;
+     *         {@code false} otherwise.
+     */
+    public boolean isPassthrough() {
+        return mPassthrough;
+    }
+
+    /**
+     * Creates a builder for {@link TlvFilterConfiguration}.
+     *
+     * @param context the context of the caller.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @NonNull
+    public static Builder builder(@NonNull Context context) {
+        TunerUtils.checkTunerPermission(context);
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link TlvFilterConfiguration}.
+     */
+    public static class Builder extends FilterConfiguration.Builder<Builder> {
+        private int mPacketType;
+        private boolean mIsCompressedIpPacket;
+        private boolean mPassthrough;
+
+        private Builder() {
+        }
+
+        /**
+         * Sets packet type.
+         */
+        @NonNull
+        public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+            mPacketType = packetType;
+            return this;
+        }
+        /**
+         * Sets whether the data is compressed IP packet.
+         */
+        @NonNull
+        public Builder setIsCompressedIpPacket(boolean isCompressedIpPacket) {
+            mIsCompressedIpPacket = isCompressedIpPacket;
+            return this;
+        }
+        /**
+         * Sets whether it's passthrough.
+         */
+        @NonNull
+        public Builder setPassthrough(boolean passthrough) {
+            mPassthrough = passthrough;
+            return this;
+        }
+
+        /**
+         * Builds a {@link TlvFilterConfiguration} object.
+         */
+        @NonNull
+        public TlvFilterConfiguration build() {
+            return new TlvFilterConfiguration(
+                    mSettings, mPacketType, mIsCompressedIpPacket, mPassthrough);
+        }
+
+        @Override
+        Builder self() {
+            return this;
+        }
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
index fa4dd72..1b8485e 100644
--- a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
@@ -16,12 +16,8 @@
 
 package android.media.tv.tuner.filter;
 
-import android.annotation.IntDef;
 import android.media.tv.tuner.Tuner.Filter;
-import android.media.tv.tuner.TunerConstants;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 
 /**
  * Filter event sent from {@link Filter} objects for TS record data.
@@ -29,47 +25,17 @@
  * @hide
  */
 public class TsRecordEvent extends FilterEvent {
-    /**
-     * @hide
-     */
-    @IntDef(flag = true, value = {
-            TunerConstants.TS_INDEX_FIRST_PACKET,
-            TunerConstants.TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
-            TunerConstants.TS_INDEX_CHANGE_TO_NOT_SCRAMBLED,
-            TunerConstants.TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
-            TunerConstants.TS_INDEX_CHANGE_TO_ODD_SCRAMBLED,
-            TunerConstants.TS_INDEX_DISCONTINUITY_INDICATOR,
-            TunerConstants.TS_INDEX_RANDOM_ACCESS_INDICATOR,
-            TunerConstants.TS_INDEX_PRIORITY_INDICATOR,
-            TunerConstants.TS_INDEX_PCR_FLAG,
-            TunerConstants.TS_INDEX_OPCR_FLAG,
-            TunerConstants.TS_INDEX_SPLICING_POINT_FLAG,
-            TunerConstants.TS_INDEX_PRIVATE_DATA,
-            TunerConstants.TS_INDEX_ADAPTATION_EXTENSION_FLAG,
-            TunerConstants.SC_INDEX_I_FRAME,
-            TunerConstants.SC_INDEX_P_FRAME,
-            TunerConstants.SC_INDEX_B_FRAME,
-            TunerConstants.SC_INDEX_SEQUENCE,
-            TunerConstants.SC_HEVC_INDEX_SPS,
-            TunerConstants.SC_HEVC_INDEX_AUD,
-            TunerConstants.SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
-            TunerConstants.SC_HEVC_INDEX_SLICE_BLA_W_RADL,
-            TunerConstants.SC_HEVC_INDEX_SLICE_BLA_N_LP,
-            TunerConstants.SC_HEVC_INDEX_SLICE_IDR_W_RADL,
-            TunerConstants.SC_HEVC_INDEX_SLICE_IDR_N_LP,
-            TunerConstants.SC_HEVC_INDEX_SLICE_TRAIL_CRA,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface IndexMask {}
 
     private final int mPid;
-    private final int mIndexMask;
+    private final int mTsIndexMask;
+    private final int mScIndexMask;
     private final long mByteNumber;
 
     // This constructor is used by JNI code only
-    private TsRecordEvent(int pid, int indexMask, long byteNumber) {
+    private TsRecordEvent(int pid, int tsIndexMask, int scIndexMask, long byteNumber) {
         mPid = pid;
-        mIndexMask = indexMask;
+        mTsIndexMask = tsIndexMask;
+        mScIndexMask = scIndexMask;
         mByteNumber = byteNumber;
     }
 
@@ -81,13 +47,20 @@
     }
 
     /**
-     * Gets index mask.
-     *
-     * <p>The index type is one of TS, SC, and SC-HEVC, and is set when configuring the filter.
+     * Gets TS index mask.
      */
-    @IndexMask
-    public int getIndexMask() {
-        return mIndexMask;
+    @RecordSettings.TsIndexMask
+    public int getTsIndexMask() {
+        return mTsIndexMask;
+    }
+    /**
+     * Gets SC index mask.
+     *
+     * <p>The index type is SC or SC-HEVC, and is set when configuring the filter.
+     */
+    @RecordSettings.ScIndexMask
+    public int getScIndexMask() {
+        return mScIndexMask;
     }
 
     /**
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 41a9b24..5054281 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -49,7 +49,6 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.TrafficStatsConstants;
 
@@ -207,7 +206,7 @@
         if (TextUtils.isEmpty(url)) url = mCm.getCaptivePortalServerUrl();
         final CarrierConfigManager configManager = getApplicationContext()
                 .getSystemService(CarrierConfigManager.class);
-        final int subId = getIntent().getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+        final int subId = getIntent().getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         final String[] portalURLs = configManager.getConfigForSubId(subId).getStringArray(
                 CarrierConfigManager.KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 4443524..c913999 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -367,7 +367,9 @@
                 String value = getSettingValue(args);
                 String tag = getSettingTag(args);
                 final boolean makeDefault = getSettingMakeDefault(args);
-                insertGlobalSetting(name, value, tag, makeDefault, requestingUserId, false);
+                final boolean overrideableByRestore = getSettingOverrideableByRestore(args);
+                insertGlobalSetting(name, value, tag, makeDefault, requestingUserId, false,
+                        overrideableByRestore);
                 break;
             }
 
@@ -375,13 +377,16 @@
                 String value = getSettingValue(args);
                 String tag = getSettingTag(args);
                 final boolean makeDefault = getSettingMakeDefault(args);
-                insertSecureSetting(name, value, tag, makeDefault, requestingUserId, false);
+                final boolean overrideableByRestore = getSettingOverrideableByRestore(args);
+                insertSecureSetting(name, value, tag, makeDefault, requestingUserId, false,
+                        overrideableByRestore);
                 break;
             }
 
             case Settings.CALL_METHOD_PUT_SYSTEM: {
                 String value = getSettingValue(args);
-                insertSystemSetting(name, value, requestingUserId);
+                boolean overrideableByRestore = getSettingOverrideableByRestore(args);
+                insertSystemSetting(name, value, requestingUserId, overrideableByRestore);
                 break;
             }
 
@@ -576,20 +581,23 @@
         switch (table) {
             case TABLE_GLOBAL: {
                 if (insertGlobalSetting(name, value, null, false,
-                        UserHandle.getCallingUserId(), false)) {
+                        UserHandle.getCallingUserId(), false,
+                        /* overrideableByRestore */ false)) {
                     return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
                 }
             } break;
 
             case TABLE_SECURE: {
                 if (insertSecureSetting(name, value, null, false,
-                        UserHandle.getCallingUserId(), false)) {
+                        UserHandle.getCallingUserId(), false,
+                        /* overrideableByRestore */ false)) {
                     return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
                 }
             } break;
 
             case TABLE_SYSTEM: {
-                if (insertSystemSetting(name, value, UserHandle.getCallingUserId())) {
+                if (insertSystemSetting(name, value, UserHandle.getCallingUserId(),
+                        /* overridableByRestore */ false)) {
                     return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);
                 }
             } break;
@@ -1075,7 +1083,8 @@
                 case MUTATION_OPERATION_INSERT: {
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
                             UserHandle.USER_SYSTEM, name, value, null, makeDefault, true,
-                            resolveCallingPackage(), false, null);
+                            resolveCallingPackage(), false, null,
+                            /* overrideableByRestore */ false);
                 }
 
                 case MUTATION_OPERATION_DELETE: {
@@ -1179,14 +1188,15 @@
     }
 
     private boolean insertGlobalSetting(String name, String value, String tag,
-            boolean makeDefault, int requestingUserId, boolean forceNotify) {
+            boolean makeDefault, int requestingUserId, boolean forceNotify,
+            boolean overrideableByRestore) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value  + ", "
                     + ", " + tag + ", " + makeDefault + ", " + requestingUserId
                     + ", " + forceNotify + ")");
         }
         return mutateGlobalSetting(name, value, tag, makeDefault, requestingUserId,
-                MUTATION_OPERATION_INSERT, forceNotify, 0);
+                MUTATION_OPERATION_INSERT, forceNotify, 0, overrideableByRestore);
     }
 
     private boolean deleteGlobalSetting(String name, int requestingUserId, boolean forceNotify) {
@@ -1221,6 +1231,15 @@
     private boolean mutateGlobalSetting(String name, String value, String tag,
             boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
             int mode) {
+        // overrideableByRestore = false as by default settings values shouldn't be overrideable by
+        // restore.
+        return mutateGlobalSetting(name, value, tag, makeDefault, requestingUserId, operation,
+                forceNotify, mode, /* overrideableByRestore */ false);
+    }
+
+    private boolean mutateGlobalSetting(String name, String value, String tag,
+            boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
+            int mode, boolean overrideableByRestore) {
         // Make sure the caller can change the settings - treated as secure.
         enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
 
@@ -1239,7 +1258,8 @@
                 case MUTATION_OPERATION_INSERT: {
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL,
                             UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
-                            getCallingPackage(), forceNotify, CRITICAL_GLOBAL_SETTINGS);
+                            getCallingPackage(), forceNotify,
+                            CRITICAL_GLOBAL_SETTINGS, overrideableByRestore);
                 }
 
                 case MUTATION_OPERATION_DELETE: {
@@ -1475,7 +1495,7 @@
             ) {
                 @Override
                 public boolean update(String value, boolean setDefault, String packageName,
-                        String tag, boolean forceNonSystemPackage) {
+                        String tag, boolean forceNonSystemPackage, boolean overrideableByRestore) {
                     Slog.wtf(LOG_TAG, "update shouldn't be called on this instance.");
                     return false;
                 }
@@ -1484,14 +1504,15 @@
     }
 
     private boolean insertSecureSetting(String name, String value, String tag,
-            boolean makeDefault, int requestingUserId, boolean forceNotify) {
+            boolean makeDefault, int requestingUserId, boolean forceNotify,
+            boolean overrideableByRestore) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", "
                     + ", " + tag  + ", " + makeDefault + ", "  + requestingUserId
                     + ", " + forceNotify + ")");
         }
         return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId,
-                MUTATION_OPERATION_INSERT, forceNotify, 0);
+                MUTATION_OPERATION_INSERT, forceNotify, 0, overrideableByRestore);
     }
 
     private boolean deleteSecureSetting(String name, int requestingUserId, boolean forceNotify) {
@@ -1529,6 +1550,15 @@
     private boolean mutateSecureSetting(String name, String value, String tag,
             boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
             int mode) {
+        // overrideableByRestore = false as by default settings values shouldn't be overrideable by
+        // restore.
+        return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId, operation,
+                forceNotify, mode, /* overrideableByRestore */ false);
+    }
+
+    private boolean mutateSecureSetting(String name, String value, String tag,
+            boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
+            int mode, boolean overrideableByRestore) {
         // Make sure the caller can change the settings.
         enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
 
@@ -1561,7 +1591,8 @@
                 case MUTATION_OPERATION_INSERT: {
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SECURE,
                             owningUserId, name, value, tag, makeDefault,
-                            getCallingPackage(), forceNotify, CRITICAL_SECURE_SETTINGS);
+                            getCallingPackage(), forceNotify, CRITICAL_SECURE_SETTINGS,
+                            overrideableByRestore);
                 }
 
                 case MUTATION_OPERATION_DELETE: {
@@ -1637,13 +1668,15 @@
         }
     }
 
-    private boolean insertSystemSetting(String name, String value, int requestingUserId) {
+    private boolean insertSystemSetting(String name, String value, int requestingUserId,
+            boolean overrideableByRestore) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "insertSystemSetting(" + name + ", " + value + ", "
                     + requestingUserId + ")");
         }
 
-        return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+        return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT,
+                overrideableByRestore);
     }
 
     private boolean deleteSystemSetting(String name, int requestingUserId) {
@@ -1663,8 +1696,15 @@
         return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
     }
 
-    private boolean mutateSystemSetting(String name, String value, int runAsUserId,
-            int operation) {
+    private boolean mutateSystemSetting(String name, String value, int runAsUserId, int operation) {
+        // overrideableByRestore = false as by default settings values shouldn't be overrideable by
+        // restore.
+        return mutateSystemSetting(name, value, runAsUserId, operation,
+                /* overrideableByRestore */ false);
+    }
+
+    private boolean mutateSystemSetting(String name, String value, int runAsUserId, int operation,
+            boolean overrideableByRestore) {
         if (!hasWriteSecureSettingsPermission()) {
             // If the caller doesn't hold WRITE_SECURE_SETTINGS, we verify whether this
             // operation is allowed for the calling package through appops.
@@ -1714,7 +1754,7 @@
                     validateSystemSettingValue(name, value);
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SYSTEM,
                             owningUserId, name, value, null, false, getCallingPackage(),
-                            false, null);
+                            false, null, overrideableByRestore);
                 }
 
                 case MUTATION_OPERATION_DELETE: {
@@ -2051,7 +2091,8 @@
         }
         return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SECURE,
                 owningUserId, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, newProviders, tag,
-                makeDefault, getCallingPackage(), forceNotify, CRITICAL_SECURE_SETTINGS);
+                makeDefault, getCallingPackage(), forceNotify, CRITICAL_SECURE_SETTINGS,
+                /* overrideableByRestore */ false);
     }
 
     private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
@@ -2145,6 +2186,10 @@
         return (args != null) && args.getBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY);
     }
 
+    private static boolean getSettingOverrideableByRestore(Bundle args) {
+        return (args != null) && args.getBoolean(Settings.CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY);
+    }
+
     private static int getResetModeEnforcingPermission(Bundle args) {
         final int mode = (args != null) ? args.getInt(Settings.CALL_METHOD_RESET_MODE_KEY) : 0;
         switch (mode) {
@@ -2642,21 +2687,21 @@
 
         public boolean insertSettingLocked(int type, int userId, String name, String value,
                 String tag, boolean makeDefault, String packageName, boolean forceNotify,
-                Set<String> criticalSettings) {
+                Set<String> criticalSettings, boolean overrideableByRestore) {
             return insertSettingLocked(type, userId, name, value, tag, makeDefault, false,
-                    packageName, forceNotify, criticalSettings);
+                    packageName, forceNotify, criticalSettings, overrideableByRestore);
         }
 
         public boolean insertSettingLocked(int type, int userId, String name, String value,
                 String tag, boolean makeDefault, boolean forceNonSystemPackage, String packageName,
-                boolean forceNotify, Set<String> criticalSettings) {
+                boolean forceNotify, Set<String> criticalSettings, boolean overrideableByRestore) {
             final int key = makeKey(type, userId);
 
             boolean success = false;
             SettingsState settingsState = peekSettingsStateLocked(key);
             if (settingsState != null) {
                 success = settingsState.insertSettingLocked(name, value,
-                        tag, makeDefault, forceNonSystemPackage, packageName);
+                        tag, makeDefault, forceNonSystemPackage, packageName, overrideableByRestore);
             }
 
             if (success && criticalSettings != null && criticalSettings.contains(name)) {
@@ -3391,6 +3436,10 @@
              * for this user from the old to the new version. When you add a new
              * upgrade step you *must* update SETTINGS_VERSION.
              *
+             * All settings modifications should be made through
+             * {@link SettingsState#insertSettingOverrideableByRestoreLocked(String, String, String,
+             * boolean, String)} so that restore can override those values if needed.
+             *
              * This is an example of moving a setting from secure to global.
              *
              * // v119: Example settings changes.
@@ -3436,7 +3485,8 @@
                 // v120: Add double tap to wake setting.
                 if (currentVersion == 119) {
                     SettingsState secureSettings = getSecureSettingsLocked(userId);
-                    secureSettings.insertSettingLocked(Settings.Secure.DOUBLE_TAP_TO_WAKE,
+                    secureSettings.insertSettingOverrideableByRestoreLocked(
+                            Settings.Secure.DOUBLE_TAP_TO_WAKE,
                             getContext().getResources().getBoolean(
                                     R.bool.def_double_tap_to_wake) ? "1" : "0", null, true,
                             SettingsState.SYSTEM_PACKAGE_NAME);
@@ -3461,7 +3511,7 @@
                             Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
                     if (defaultComponent != null && !defaultComponent.isEmpty() &&
                         currentSetting.isNull()) {
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
                                 defaultComponent, null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -3476,7 +3526,7 @@
                         Setting currentSetting = globalSettings.getSettingLocked(
                                 Settings.Global.ADD_USERS_WHEN_LOCKED);
                         if (currentSetting.isNull()) {
-                            globalSettings.insertSettingLocked(
+                            globalSettings.insertSettingOverrideableByRestoreLocked(
                                     Settings.Global.ADD_USERS_WHEN_LOCKED,
                                     getContext().getResources().getBoolean(
                                             R.bool.def_add_users_from_lockscreen) ? "1" : "0",
@@ -3490,8 +3540,9 @@
                     final SettingsState globalSettings = getGlobalSettingsLocked();
                     String defaultDisabledProfiles = (getContext().getResources().getString(
                             R.string.def_bluetooth_disabled_profiles));
-                    globalSettings.insertSettingLocked(Settings.Global.BLUETOOTH_DISABLED_PROFILES,
-                            defaultDisabledProfiles, null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    globalSettings.insertSettingOverrideableByRestoreLocked(
+                            Settings.Global.BLUETOOTH_DISABLED_PROFILES, defaultDisabledProfiles,
+                            null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     currentVersion = 124;
                 }
 
@@ -3502,7 +3553,7 @@
                     Setting currentSetting = secureSettings.getSettingLocked(
                             Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
                     if (currentSetting.isNull()) {
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
                                 getContext().getResources().getBoolean(
                                         R.bool.def_show_ime_with_hard_keyboard) ? "1" : "0",
@@ -3531,7 +3582,7 @@
                                 b.append(c.flattenToString());
                                 start = false;
                             }
-                            secureSettings.insertSettingLocked(
+                            secureSettings.insertSettingOverrideableByRestoreLocked(
                                     Settings.Secure.ENABLED_VR_LISTENERS, b.toString(),
                                     null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                         }
@@ -3551,7 +3602,7 @@
                                 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
                         if (!showNotifications.isNull()) {
                             final SettingsState secureSettings = getSecureSettingsLocked(userId);
-                            secureSettings.insertSettingLocked(
+                            secureSettings.insertSettingOverrideableByRestoreLocked(
                                     Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
                                     showNotifications.getValue(), null, true,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
@@ -3561,7 +3612,7 @@
                                 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
                         if (!allowPrivate.isNull()) {
                             final SettingsState secureSettings = getSecureSettingsLocked(userId);
-                            secureSettings.insertSettingLocked(
+                            secureSettings.insertSettingOverrideableByRestoreLocked(
                                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
                                     allowPrivate.getValue(), null, true,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
@@ -3588,7 +3639,7 @@
                     final String oldValue = systemSecureSettings.getSettingLocked(
                             Settings.Secure.LONG_PRESS_TIMEOUT).getValue();
                     if (TextUtils.equals("500", oldValue)) {
-                        systemSecureSettings.insertSettingLocked(
+                        systemSecureSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Secure.LONG_PRESS_TIMEOUT,
                                 String.valueOf(getContext().getResources().getInteger(
                                         R.integer.def_long_press_timeout_millis)),
@@ -3604,10 +3655,12 @@
                             getSettingLocked(Settings.Secure.DOZE_ENABLED).getValue());
 
                     if (dozeExplicitlyDisabled) {
-                        secureSettings.insertSettingLocked(Settings.Secure.DOZE_PICK_UP_GESTURE,
-                                "0", null, true, SettingsState.SYSTEM_PACKAGE_NAME);
-                        secureSettings.insertSettingLocked(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
-                                "0", null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
+                                Settings.Secure.DOZE_PICK_UP_GESTURE, "0", null, true,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
+                                Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, "0", null, true,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
                     }
                     currentVersion = 131;
                 }
@@ -3618,7 +3671,7 @@
                     final String oldValue = systemSecureSettings.getSettingLocked(
                             Settings.Secure.MULTI_PRESS_TIMEOUT).getValue();
                     if (TextUtils.equals(null, oldValue)) {
-                        systemSecureSettings.insertSettingLocked(
+                        systemSecureSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Secure.MULTI_PRESS_TIMEOUT,
                                 String.valueOf(getContext().getResources().getInteger(
                                         R.integer.def_multi_press_timeout_millis)),
@@ -3633,7 +3686,7 @@
                     final SettingsState systemSecureSettings = getSecureSettingsLocked(userId);
                     String defaultSyncParentSounds = (getContext().getResources()
                             .getBoolean(R.bool.def_sync_parent_sounds) ? "1" : "0");
-                    systemSecureSettings.insertSettingLocked(
+                    systemSecureSettings.insertSettingOverrideableByRestoreLocked(
                             Settings.Secure.SYNC_PARENT_SOUNDS, defaultSyncParentSounds,
                             null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     currentVersion = 133;
@@ -3646,9 +3699,9 @@
                             .isNull()) {
                         String defaultEndButtonBehavior = Integer.toString(getContext()
                                 .getResources().getInteger(R.integer.def_end_button_behavior));
-                        systemSettings.insertSettingLocked(Settings.System.END_BUTTON_BEHAVIOR,
-                                defaultEndButtonBehavior, null, true,
-                                SettingsState.SYSTEM_PACKAGE_NAME);
+                        systemSettings.insertSettingOverrideableByRestoreLocked(
+                                Settings.System.END_BUTTON_BEHAVIOR, defaultEndButtonBehavior, null,
+                                true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
                     currentVersion = 134;
                 }
@@ -3706,8 +3759,8 @@
 
                             if (ssaid.isNull() || ssaid.getValue() == null) {
                                 // Android Id doesn't exist for this package so create it.
-                                ssaidSettings.insertSettingLocked(uid, legacySsaid, null, true,
-                                        info.packageName);
+                                ssaidSettings.insertSettingOverrideableByRestoreLocked(uid,
+                                        legacySsaid, null, true, info.packageName);
                                 if (DEBUG) {
                                     Slog.d(LOG_TAG, "Keep the legacy ssaid for uid=" + uid);
                                 }
@@ -3727,13 +3780,14 @@
                             && secureSetting.getSettingLocked(
                             Settings.Secure.INSTALL_NON_MARKET_APPS).getValue().equals("0")) {
 
-                        secureSetting.insertSettingLocked(Settings.Secure.INSTALL_NON_MARKET_APPS,
-                                "1", null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                        secureSetting.insertSettingOverrideableByRestoreLocked(
+                                Settings.Secure.INSTALL_NON_MARKET_APPS, "1", null, true,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
                         // For managed profiles with profile owners, DevicePolicyManagerService
                         // may want to set the user restriction in this case
-                        secureSetting.insertSettingLocked(
-                                Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, "1", null, true,
-                                SettingsState.SYSTEM_PACKAGE_NAME);
+                        secureSetting.insertSettingOverrideableByRestoreLocked(
+                                Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, "1", null,
+                                true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
                     currentVersion = 138;
                 }
@@ -3774,7 +3828,7 @@
                         Setting currentSetting = globalSettings.getSettingLocked(
                                 Settings.Global.WIFI_WAKEUP_ENABLED);
                         if (currentSetting.isNull()) {
-                            globalSettings.insertSettingLocked(
+                            globalSettings.insertSettingOverrideableByRestoreLocked(
                                     Settings.Global.WIFI_WAKEUP_ENABLED,
                                     getContext().getResources().getBoolean(
                                             R.bool.def_wifi_wakeup_enabled) ? "1" : "0",
@@ -3796,8 +3850,9 @@
                         if (defaultValue != null) {
                             Slog.d(LOG_TAG, "Setting [" + defaultValue + "] as Autofill Service "
                                     + "for user " + userId);
-                            secureSettings.insertSettingLocked(Settings.Secure.AUTOFILL_SERVICE,
-                                    defaultValue, null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                            secureSettings.insertSettingOverrideableByRestoreLocked(
+                                    Settings.Secure.AUTOFILL_SERVICE, defaultValue, null, true,
+                                    SettingsState.SYSTEM_PACKAGE_NAME);
                         }
                     }
 
@@ -3848,7 +3903,7 @@
                         final Setting currentSetting = globalSettings.getSettingLocked(
                                 Global.DEFAULT_RESTRICT_BACKGROUND_DATA);
                         if (currentSetting.isNull()) {
-                            globalSettings.insertSettingLocked(
+                            globalSettings.insertSettingOverrideableByRestoreLocked(
                                     Global.DEFAULT_RESTRICT_BACKGROUND_DATA,
                                     getContext().getResources().getBoolean(
                                             R.bool.def_restrict_background_data) ? "1" : "0",
@@ -3867,7 +3922,7 @@
                         final String defaultValue = getContext().getResources().getString(
                                 R.string.def_backup_manager_constants);
                         if (!TextUtils.isEmpty(defaultValue)) {
-                            systemSecureSettings.insertSettingLocked(
+                            systemSecureSettings.insertSettingOverrideableByRestoreLocked(
                                     Settings.Secure.BACKUP_MANAGER_CONSTANTS, defaultValue, null,
                                     true, SettingsState.SYSTEM_PACKAGE_NAME);
                         }
@@ -3881,7 +3936,7 @@
                     final Setting currentSetting = globalSettings.getSettingLocked(
                             Settings.Global.MOBILE_DATA_ALWAYS_ON);
                     if (currentSetting.isNull()) {
-                        globalSettings.insertSettingLocked(
+                        globalSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Global.MOBILE_DATA_ALWAYS_ON,
                                 getContext().getResources().getBoolean(
                                         R.bool.def_mobile_data_always_on) ? "1" : "0",
@@ -3917,7 +3972,7 @@
                     if (showNotificationBadges.isNull()) {
                         final boolean defaultValue = getContext().getResources().getBoolean(
                                 com.android.internal.R.bool.config_notificationBadging);
-                        systemSecureSettings.insertSettingLocked(
+                        systemSecureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.NOTIFICATION_BADGING,
                                 defaultValue ? "1" : "0",
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
@@ -3934,7 +3989,7 @@
                         final String defaultValue = getContext().getResources().getString(
                                 R.string.def_backup_local_transport_parameters);
                         if (!TextUtils.isEmpty(defaultValue)) {
-                            systemSecureSettings.insertSettingLocked(
+                            systemSecureSettings.insertSettingOverrideableByRestoreLocked(
                                     Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS, defaultValue,
                                     null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                         }
@@ -3957,7 +4012,7 @@
                     if (currentSetting.isNull()) {
                         String defaultZenDuration = Integer.toString(getContext()
                                 .getResources().getInteger(R.integer.def_zen_duration));
-                        globalSettings.insertSettingLocked(
+                        globalSettings.insertSettingOverrideableByRestoreLocked(
                                 Global.ZEN_DURATION, defaultZenDuration,
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -3973,7 +4028,7 @@
                         final String defaultValue = getContext().getResources().getString(
                                 R.string.def_backup_agent_timeout_parameters);
                         if (!TextUtils.isEmpty(defaultValue)) {
-                            globalSettings.insertSettingLocked(
+                            globalSettings.insertSettingOverrideableByRestoreLocked(
                                     Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS, defaultValue,
                                     null, true,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
@@ -4002,7 +4057,7 @@
                             Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
                         // The default value is "1", check if user has turned it off.
                         if ("0".equals(showNotifications.getValue())) {
-                            secureSettings.insertSettingLocked(
+                            secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, "0",
                                 null /* tag */, false /* makeDefault */,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
@@ -4023,7 +4078,7 @@
                     String oldValue = globalSettings.getSettingLocked(
                             Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY).getValue();
                     if (TextUtils.equals(null, oldValue)) {
-                        globalSettings.insertSettingLocked(
+                        globalSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
                                 Integer.toString(getContext().getResources().getInteger(
                                         R.integer.def_max_sound_trigger_detection_service_ops_per_day)),
@@ -4033,7 +4088,7 @@
                     oldValue = globalSettings.getSettingLocked(
                             Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT).getValue();
                     if (TextUtils.equals(null, oldValue)) {
-                        globalSettings.insertSettingLocked(
+                        globalSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT,
                                 Integer.toString(getContext().getResources().getInteger(
                                         R.integer.def_sound_trigger_detection_service_op_timeout)),
@@ -4048,7 +4103,7 @@
                     final Setting currentSetting = secureSettings.getSettingLocked(
                             Secure.VOLUME_HUSH_GESTURE);
                     if (currentSetting.isNull()) {
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.VOLUME_HUSH_GESTURE,
                                 Integer.toString(Secure.VOLUME_HUSH_VIBRATE),
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
@@ -4069,7 +4124,7 @@
                     final Setting currentSetting = settings.getSettingLocked(
                             Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY);
                     if (currentSetting.isDefaultFromSystem()) {
-                        settings.insertSettingLocked(
+                        settings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
                                 Integer.toString(getContext().getResources().getInteger(
                                         R.integer
@@ -4098,7 +4153,7 @@
                     Setting currentHushUsedSetting = secureSettings.getSettingLocked(
                             Secure.HUSH_GESTURE_USED);
                     if (currentHushUsedSetting.isNull()) {
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Secure.HUSH_GESTURE_USED, "0", null, true,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4106,7 +4161,7 @@
                     Setting currentRingerToggleCountSetting = secureSettings.getSettingLocked(
                             Secure.MANUAL_RINGER_TOGGLE_COUNT);
                     if (currentRingerToggleCountSetting.isNull()) {
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, "0", null, true,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4125,7 +4180,7 @@
                     final Setting currentSetting = systemSettings.getSettingLocked(
                             Settings.System.VIBRATE_WHEN_RINGING);
                     if (currentSetting.isNull()) {
-                        systemSettings.insertSettingLocked(
+                        systemSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.System.VIBRATE_WHEN_RINGING,
                                 getContext().getResources().getBoolean(
                                         R.bool.def_vibrate_when_ringing) ? "1" : "0",
@@ -4149,18 +4204,18 @@
 
                     // ZEN_DURATION
                     if (!globalZenDuration.isNull()) {
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.ZEN_DURATION, globalZenDuration.getValue(), null, false,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
 
                         // set global zen duration setting to null since it's deprecated
-                        globalSettings.insertSettingLocked(
+                        globalSettings.insertSettingOverrideableByRestoreLocked(
                                 Global.ZEN_DURATION, null, null, true,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
                     } else if (secureZenDuration.isNull()) {
                         String defaultZenDuration = Integer.toString(getContext()
                                 .getResources().getInteger(R.integer.def_zen_duration));
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.ZEN_DURATION, defaultZenDuration, null, true,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4169,7 +4224,7 @@
                     final Setting currentShowZenSettingSuggestion = secureSettings.getSettingLocked(
                             Secure.SHOW_ZEN_SETTINGS_SUGGESTION);
                     if (currentShowZenSettingSuggestion.isNull()) {
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.SHOW_ZEN_SETTINGS_SUGGESTION, "1",
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4178,7 +4233,7 @@
                     final Setting currentUpdatedSetting = secureSettings.getSettingLocked(
                             Secure.ZEN_SETTINGS_UPDATED);
                     if (currentUpdatedSetting.isNull()) {
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.ZEN_SETTINGS_UPDATED, "0",
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4187,7 +4242,7 @@
                     final Setting currentSettingSuggestionViewed = secureSettings.getSettingLocked(
                             Secure.ZEN_SETTINGS_SUGGESTION_VIEWED);
                     if (currentSettingSuggestionViewed.isNull()) {
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.ZEN_SETTINGS_SUGGESTION_VIEWED, "0",
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4210,20 +4265,20 @@
 
                     if (!globalChargingSoundEnabled.isNull()) {
                         if (secureChargingSoundsEnabled.isNull()) {
-                            secureSettings.insertSettingLocked(
+                            secureSettings.insertSettingOverrideableByRestoreLocked(
                                     Secure.CHARGING_SOUNDS_ENABLED,
                                     globalChargingSoundEnabled.getValue(), null, false,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
                         }
 
                         // set global charging_sounds_enabled setting to null since it's deprecated
-                        globalSettings.insertSettingLocked(
+                        globalSettings.insertSettingOverrideableByRestoreLocked(
                                 Global.CHARGING_SOUNDS_ENABLED, null, null, true,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
                     } else if (secureChargingSoundsEnabled.isNull()) {
                         String defChargingSoundsEnabled = getContext().getResources()
                                 .getBoolean(R.bool.def_charging_sounds_enabled) ? "1" : "0";
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.CHARGING_SOUNDS_ENABLED, defChargingSoundsEnabled, null,
                                 true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4235,7 +4290,7 @@
                     if (secureChargingVibrationEnabled.isNull()) {
                         String defChargingVibrationEnabled = getContext().getResources()
                                 .getBoolean(R.bool.def_charging_vibration_enabled) ? "1" : "0";
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.CHARGING_VIBRATION_ENABLED, defChargingVibrationEnabled,
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4255,7 +4310,7 @@
                                     currentSetting.getValue());
                             if ((currentSettingIntegerValue
                                  & (1 << AudioManager.STREAM_VOICE_CALL)) == 0) {
-                                systemSettings.insertSettingLocked(
+                                systemSettings.insertSettingOverrideableByRestoreLocked(
                                     Settings.System.MUTE_STREAMS_AFFECTED,
                                     Integer.toString(
                                         currentSettingIntegerValue
@@ -4296,7 +4351,7 @@
                                             ? Secure.LOCATION_MODE_ON
                                             : Secure.LOCATION_MODE_OFF;
                         }
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.LOCATION_MODE, Integer.toString(defLocationMode),
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4318,7 +4373,7 @@
                     Setting currentRampingRingerSetting = globalSettings.getSettingLocked(
                             Settings.Global.APPLY_RAMPING_RINGER);
                     if (currentRampingRingerSetting.isNull()) {
-                        globalSettings.insertSettingLocked(
+                        globalSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.Global.APPLY_RAMPING_RINGER,
                                 getContext().getResources().getBoolean(
                                         R.bool.def_apply_ramping_ringer) ? "1" : "0", null,
@@ -4344,7 +4399,7 @@
 
                     if (!notificationVibrationIntensity.isNull()
                             && ringVibrationIntensity.isNull()) {
-                        systemSettings.insertSettingLocked(
+                        systemSettings.insertSettingOverrideableByRestoreLocked(
                                 Settings.System.RING_VIBRATION_INTENSITY,
                                 notificationVibrationIntensity.getValue(),
                                 null , true, SettingsState.SYSTEM_PACKAGE_NAME);
@@ -4388,7 +4443,7 @@
                     if (awareEnabled.isNull()) {
                         final boolean defAwareEnabled = getContext().getResources().getBoolean(
                                 R.bool.def_aware_enabled);
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.AWARE_ENABLED, defAwareEnabled ? "1" : "0",
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4408,7 +4463,7 @@
                     if (skipGesture.isNull()) {
                         final boolean defSkipGesture = getContext().getResources().getBoolean(
                                 R.bool.def_skip_gesture);
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.SKIP_GESTURE, defSkipGesture ? "1" : "0",
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4419,7 +4474,7 @@
                     if (silenceGesture.isNull()) {
                         final boolean defSilenceGesture = getContext().getResources().getBoolean(
                                 R.bool.def_silence_gesture);
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.SILENCE_GESTURE, defSilenceGesture ? "1" : "0",
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4447,7 +4502,7 @@
                     if (awareLockEnabled.isNull()) {
                         final boolean defAwareLockEnabled = getContext().getResources().getBoolean(
                                 R.bool.def_aware_lock_enabled);
-                        secureSettings.insertSettingLocked(
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
                                 Secure.AWARE_LOCK_ENABLED, defAwareLockEnabled ? "1" : "0",
                                 null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
@@ -4467,7 +4522,7 @@
                                     currentSetting.getValue());
                             if ((currentSettingIntegerValue
                                     & (1 << AudioManager.STREAM_BLUETOOTH_SCO)) == 0) {
-                                systemSettings.insertSettingLocked(
+                                systemSettings.insertSettingOverrideableByRestoreLocked(
                                         Settings.System.MUTE_STREAMS_AFFECTED,
                                         Integer.toString(
                                         currentSettingIntegerValue
@@ -4513,13 +4568,13 @@
                     if (oldValueWireless == null
                             || TextUtils.equals(oldValueWireless, defaultValueWired)) {
                         if (!TextUtils.isEmpty(defaultValueWireless)) {
-                            globalSettings.insertSettingLocked(
+                            globalSettings.insertSettingOverrideableByRestoreLocked(
                                     Global.WIRELESS_CHARGING_STARTED_SOUND, defaultValueWireless,
                                     null /* tag */, true /* makeDefault */,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
                         } else if (!TextUtils.isEmpty(defaultValueWired)) {
                             // if the wireless sound is empty, use the wired charging sound
-                            globalSettings.insertSettingLocked(
+                            globalSettings.insertSettingOverrideableByRestoreLocked(
                                     Global.WIRELESS_CHARGING_STARTED_SOUND, defaultValueWired,
                                     null /* tag */, true /* makeDefault */,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
@@ -4528,7 +4583,7 @@
 
                     // wired charging sound
                     if (oldValueWired == null && !TextUtils.isEmpty(defaultValueWired)) {
-                        globalSettings.insertSettingLocked(
+                        globalSettings.insertSettingOverrideableByRestoreLocked(
                                 Global.CHARGING_STARTED_SOUND, defaultValueWired,
                                 null /* tag */, true /* makeDefault */,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
@@ -4540,8 +4595,8 @@
                     // Version 184: Reset the default for Global Settings: NOTIFICATION_BUBBLES
                     // This is originally set in version 182, however, the default value changed
                     // so this step is to ensure the value is updated to the correct default.
-                    getGlobalSettingsLocked().insertSettingLocked(Global.NOTIFICATION_BUBBLES,
-                            getContext().getResources().getBoolean(
+                    getGlobalSettingsLocked().insertSettingOverrideableByRestoreLocked(
+                            Global.NOTIFICATION_BUBBLES, getContext().getResources().getBoolean(
                                     R.bool.def_notification_bubbles) ? "1" : "0", null /* tag */,
                             true /* makeDefault */, SettingsState.SYSTEM_PACKAGE_NAME);
 
@@ -4617,7 +4672,7 @@
                     final boolean systemSet = SettingsState.isSystemPackage(getContext(),
                             setting.getPackageName(), callingUid, userId);
                     if (systemSet) {
-                        settings.insertSettingLocked(name, setting.getValue(),
+                        settings.insertSettingOverrideableByRestoreLocked(name, setting.getValue(),
                                 setting.getTag(), true, setting.getPackageName());
                     } else if (setting.getDefaultValue() != null && setting.isDefaultFromSystem()) {
                         // We had a bug where changes by non-system packages were marked
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 5b1b530..db18213 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -117,6 +117,8 @@
     private static final String ATTR_NAMESPACE = "namespace";
     private static final String ATTR_BANNED_HASH = "bannedHash";
 
+    private static final String ATTR_PRESERVE_IN_RESTORE = "preserve_in_restore";
+
     /**
      * Non-binary value will be written in this attributes.
      */
@@ -388,15 +390,25 @@
 
     // The settings provider must hold its lock when calling here.
     @GuardedBy("mLock")
-    public boolean insertSettingLocked(String name, String value, String tag,
+    public boolean insertSettingOverrideableByRestoreLocked(String name, String value, String tag,
             boolean makeDefault, String packageName) {
-        return insertSettingLocked(name, value, tag, makeDefault, false, packageName);
+        return insertSettingLocked(name, value, tag, makeDefault, false, packageName,
+                /* overrideableByRestore */ true);
     }
 
     // The settings provider must hold its lock when calling here.
     @GuardedBy("mLock")
     public boolean insertSettingLocked(String name, String value, String tag,
-            boolean makeDefault, boolean forceNonSystemPackage, String packageName) {
+            boolean makeDefault, String packageName) {
+        return insertSettingLocked(name, value, tag, makeDefault, false, packageName,
+                /* overrideableByRestore */ false);
+    }
+
+    // The settings provider must hold its lock when calling here.
+    @GuardedBy("mLock")
+    public boolean insertSettingLocked(String name, String value, String tag,
+            boolean makeDefault, boolean forceNonSystemPackage, String packageName,
+            boolean overrideableByRestore) {
         if (TextUtils.isEmpty(name)) {
             return false;
         }
@@ -407,7 +419,8 @@
         Setting newState;
 
         if (oldState != null) {
-            if (!oldState.update(value, makeDefault, packageName, tag, forceNonSystemPackage)) {
+            if (!oldState.update(value, makeDefault, packageName, tag, forceNonSystemPackage,
+                    overrideableByRestore)) {
                 return false;
             }
             newState = oldState;
@@ -495,7 +508,8 @@
                 changedKeys.add(key); // key was added
             } else if (state.value != value) {
                 oldValue = state.value;
-                state.update(value, false, packageName, null, true);
+                state.update(value, false, packageName, null, true,
+                        /* overrideableByRestore */ false);
                 changedKeys.add(key); // key was updated
             } else {
                 // this key/value already exists, no change and no logging necessary
@@ -797,7 +811,8 @@
 
                     writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
                             setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
-                            setting.getTag(), setting.isDefaultFromSystem());
+                            setting.getTag(), setting.isDefaultFromSystem(),
+                            setting.isValuePreservedInRestore());
 
                     if (DEBUG_PERSISTENCE) {
                         Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "="
@@ -886,7 +901,8 @@
 
     static void writeSingleSetting(int version, XmlSerializer serializer, String id,
             String name, String value, String defaultValue, String packageName,
-            String tag, boolean defaultSysSet) throws IOException {
+            String tag, boolean defaultSysSet, boolean isValuePreservedInRestore)
+            throws IOException {
         if (id == null || isBinary(id) || name == null || isBinary(name)
                 || packageName == null || isBinary(packageName)) {
             // This shouldn't happen.
@@ -905,6 +921,9 @@
             setValueAttribute(ATTR_TAG, ATTR_TAG_BASE64,
                     version, serializer, tag);
         }
+        if (isValuePreservedInRestore) {
+            serializer.attribute(null, ATTR_PRESERVE_IN_RESTORE, Boolean.toString(true));
+        }
         serializer.endTag(null, TAG_SETTING);
     }
 
@@ -1041,6 +1060,10 @@
                 String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                 String defaultValue = getValueAttribute(parser, ATTR_DEFAULT_VALUE,
                         ATTR_DEFAULT_VALUE_BASE64);
+                String isPreservedInRestoreString = parser.getAttributeValue(null,
+                        ATTR_PRESERVE_IN_RESTORE);
+                boolean isPreservedInRestore = isPreservedInRestoreString != null
+                        && Boolean.parseBoolean(isPreservedInRestoreString);
                 String tag = null;
                 boolean fromSystem = false;
                 if (defaultValue != null) {
@@ -1049,7 +1072,7 @@
                     tag = getValueAttribute(parser, ATTR_TAG, ATTR_TAG_BASE64);
                 }
                 mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag,
-                        fromSystem, id));
+                        fromSystem, id, isPreservedInRestore));
 
                 if (DEBUG_PERSISTENCE) {
                     Slog.i(LOG_TAG, "[RESTORED] " + name + "=" + value);
@@ -1133,6 +1156,8 @@
         private String tag;
         // Whether the default is set by the system
         private boolean defaultFromSystem;
+        // Whether the value of this setting will be preserved when restore happens.
+        private boolean isValuePreservedInRestore;
 
         public Setting(Setting other) {
             name = other.name;
@@ -1142,25 +1167,38 @@
             id = other.id;
             defaultFromSystem = other.defaultFromSystem;
             tag = other.tag;
+            isValuePreservedInRestore = other.isValuePreservedInRestore;
         }
 
         public Setting(String name, String value, boolean makeDefault, String packageName,
                 String tag) {
             this.name = name;
-            update(value, makeDefault, packageName, tag, false);
+            // overrideableByRestore = true as the first initialization isn't considered a
+            // modification.
+            update(value, makeDefault, packageName, tag, false,
+                    /* overrideableByRestore */ true);
         }
 
         public Setting(String name, String value, String defaultValue,
                 String packageName, String tag, boolean fromSystem, String id) {
+            this(name, value, defaultValue, packageName, tag, fromSystem, id,
+                    /* isOverrideableByRestore */ false);
+        }
+
+        Setting(String name, String value, String defaultValue,
+                String packageName, String tag, boolean fromSystem, String id,
+                boolean isValuePreservedInRestore) {
             mNextId = Math.max(mNextId, Long.parseLong(id) + 1);
             if (NULL_VALUE.equals(value)) {
                 value = null;
             }
-            init(name, value, tag, defaultValue, packageName, fromSystem, id);
+            init(name, value, tag, defaultValue, packageName, fromSystem, id,
+                    isValuePreservedInRestore);
         }
 
         private void init(String name, String value, String tag, String defaultValue,
-                String packageName, boolean fromSystem, String id) {
+                String packageName, boolean fromSystem, String id,
+                boolean isValuePreservedInRestore) {
             this.name = name;
             this.value = value;
             this.tag = tag;
@@ -1168,6 +1206,7 @@
             this.packageName = packageName;
             this.id = id;
             this.defaultFromSystem = fromSystem;
+            this.isValuePreservedInRestore = isValuePreservedInRestore;
         }
 
         public String getName() {
@@ -1198,6 +1237,10 @@
             return defaultFromSystem;
         }
 
+        public boolean isValuePreservedInRestore() {
+            return isValuePreservedInRestore;
+        }
+
         public String getId() {
             return id;
         }
@@ -1208,7 +1251,9 @@
 
         /** @return whether the value changed */
         public boolean reset() {
-            return update(this.defaultValue, false, packageName, null, true);
+            // overrideableByRestore = true as resetting to default value isn't considered a
+            // modification.
+            return update(this.defaultValue, false, packageName, null, true, true);
         }
 
         public boolean isTransient() {
@@ -1220,7 +1265,7 @@
         }
 
         public boolean update(String value, boolean setDefault, String packageName, String tag,
-                boolean forceNonSystemPackage) {
+                boolean forceNonSystemPackage, boolean overrideableByRestore) {
             if (NULL_VALUE.equals(value)) {
                 value = null;
             }
@@ -1253,17 +1298,22 @@
                 }
             }
 
+            // isValuePreservedInRestore shouldn't change back to false if it has been set to true.
+            boolean isPreserved = this.isValuePreservedInRestore || !overrideableByRestore;
+
             // Is something gonna change?
             if (Objects.equals(value, this.value)
                     && Objects.equals(defaultValue, this.defaultValue)
                     && Objects.equals(packageName, this.packageName)
                     && Objects.equals(tag, this.tag)
-                    && defaultFromSystem == this.defaultFromSystem) {
+                    && defaultFromSystem == this.defaultFromSystem
+                    && isPreserved == this.isValuePreservedInRestore) {
                 return false;
             }
 
             init(name, value, tag, defaultValue, packageName, defaultFromSystem,
-                    String.valueOf(mNextId++));
+                    String.valueOf(mNextId++), isPreserved);
+
             return true;
         }
 
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 3f68554..b855d87 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -46,6 +46,18 @@
             "\uD800ab\uDC00 " + // broken surrogate pairs
             "日本語";
 
+    private static final String TEST_PACKAGE = "package";
+    private static final String SETTING_NAME = "test_setting";
+
+    private final Object mLock = new Object();
+
+    private File mSettingsFile;
+
+    @Override
+    protected void setUp() {
+        mSettingsFile = new File(getContext().getCacheDir(), "setting.xml");
+        mSettingsFile.delete();
+    }
 
     public void testIsBinary() {
         assertFalse(SettingsState.isBinary(" abc 日本語"));
@@ -99,10 +111,10 @@
         checkWriteSingleSetting(serializer, CRAZY_STRING, null);
         SettingsState.writeSingleSetting(
                 SettingsState.SETTINGS_VERSION_NEW_ENCODING,
-                serializer, null, "k", "v", null, "package", null, false);
+                serializer, null, "k", "v", null, "package", null, false, false);
         SettingsState.writeSingleSetting(
                 SettingsState.SETTINGS_VERSION_NEW_ENCODING,
-                serializer, "1", "k", "v", null, null, null, false);
+                serializer, "1", "k", "v", null, null, null, false, false);
     }
 
     private void checkWriteSingleSetting(XmlSerializer serializer, String key, String value)
@@ -115,7 +127,7 @@
         // Make sure the XML serializer won't crash.
         SettingsState.writeSingleSetting(
                 SettingsState.SETTINGS_VERSION_NEW_ENCODING,
-                serializer, "1", key, value, null, "package", null, false);
+                serializer, "1", key, value, null, "package", null, false, false);
     }
 
     /**
@@ -182,4 +194,57 @@
             assertEquals("p2", s.getPackageName());
         }
     }
+
+    public void testInitializeSetting_preserveFlagNotSet() {
+        SettingsState settingsWriter = getSettingStateObject();
+        settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
+        settingsWriter.persistSyncLocked();
+
+        SettingsState settingsReader = getSettingStateObject();
+        assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
+    }
+
+    public void testModifySetting_preserveFlagSet() {
+        SettingsState settingsWriter = getSettingStateObject();
+        settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
+        settingsWriter.insertSettingLocked(SETTING_NAME, "2", null, false, TEST_PACKAGE);
+        settingsWriter.persistSyncLocked();
+
+        SettingsState settingsReader = getSettingStateObject();
+        assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
+    }
+
+    public void testModifySettingOverrideableByRestore_preserveFlagNotSet() {
+        SettingsState settingsWriter = getSettingStateObject();
+        settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
+        settingsWriter.insertSettingLocked(SETTING_NAME, "2", null, false, false, TEST_PACKAGE,
+                /* overrideableByRestore */ true);
+        settingsWriter.persistSyncLocked();
+
+        SettingsState settingsReader = getSettingStateObject();
+        assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
+    }
+
+    public void testModifySettingOverrideableByRestore_preserveFlagAlreadySet_flagValueUnchanged() {
+        SettingsState settingsWriter = getSettingStateObject();
+        // Init the setting.
+        settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
+        // This modification will set isValuePreservedInRestore = true.
+        settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
+        // This modification shouldn't change the value of isValuePreservedInRestore since it's
+        // already been set to true.
+        settingsWriter.insertSettingLocked(SETTING_NAME, "2", null, false, false, TEST_PACKAGE,
+                /* overrideableByRestore */ true);
+        settingsWriter.persistSyncLocked();
+
+        SettingsState settingsReader = getSettingStateObject();
+        assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
+    }
+
+    private SettingsState getSettingStateObject() {
+        SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+        settingsState.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING);
+        return settingsState;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a58e3d7..65fc215 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -31,8 +31,8 @@
 import static android.os.BatteryManager.EXTRA_PLUGGED;
 import static android.os.BatteryManager.EXTRA_STATUS;
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
+import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
 
-import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -92,7 +92,6 @@
 import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settingslib.WirelessUtils;
@@ -446,7 +445,7 @@
      */
     public List<SubscriptionInfo> getFilteredSubscriptionInfo(boolean forceReload) {
         List<SubscriptionInfo> subscriptions = getSubscriptionInfo(false);
-        if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
+        if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
             SubscriptionInfo info1 = subscriptions.get(0);
             SubscriptionInfo info2 = subscriptions.get(1);
             if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
@@ -1074,7 +1073,7 @@
                 mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
             } else if (Intent.ACTION_SERVICE_STATE.equals(action)) {
                 ServiceState serviceState = ServiceState.newFromBundle(intent.getExtras());
-                int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
                 if (DEBUG) {
                     Log.v(TAG, "action " + action + " serviceState=" + serviceState + " subId="
@@ -1236,8 +1235,8 @@
                 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
             }
             String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
-            int slotId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
-            int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+            int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
+            int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
             if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
                 final String absentReason = intent
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 820c042..f7fe064 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection
 
+import android.app.NotificationChannel
 import android.app.NotificationManager.IMPORTANCE_HIGH
 import android.app.NotificationManager.IMPORTANCE_MIN
 import android.service.notification.NotificationListenerService.Ranking
@@ -191,9 +192,9 @@
     }
 
     private fun NotificationEntry.isPeopleNotification() =
-            sbn.isPeopleNotification()
-    private fun StatusBarNotification.isPeopleNotification() =
-            peopleNotificationIdentifier.isPeopleNotification(this)
+            sbn.isPeopleNotification(channel)
+    private fun StatusBarNotification.isPeopleNotification(channel: NotificationChannel) =
+            peopleNotificationIdentifier.isPeopleNotification(this, channel)
 
     private fun NotificationEntry.isHighPriority() =
             highPriorityProvider.isHighPriority(this)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java
index 2c6a165..2eec68b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.notification.collection.coalescer;
 
+import androidx.annotation.Nullable;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -35,6 +37,8 @@
      */
     final List<CoalescedEvent> mMembers = new ArrayList<>();
 
+    @Nullable Runnable mCancelShortTimeout;
+
     EventBatch(long createdTimestamp, String groupKey) {
         mCreatedTimestamp = createdTimestamp;
         this.mGroupKey = groupKey;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
index 8076616..f589038 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection.coalescer;
 
+import static com.android.systemui.statusbar.notification.logging.NotifEvent.BATCH_MAX_TIMEOUT;
 import static com.android.systemui.statusbar.notification.logging.NotifEvent.COALESCED_EVENT;
 import static com.android.systemui.statusbar.notification.logging.NotifEvent.EARLY_BATCH_EMIT;
 import static com.android.systemui.statusbar.notification.logging.NotifEvent.EMIT_EVENT_BATCH;
@@ -71,7 +72,8 @@
     private final DelayableExecutor mMainExecutor;
     private final SystemClock mClock;
     private final NotifLog mLog;
-    private final long mGroupLingerDuration;
+    private final long mMinGroupLingerDuration;
+    private final long mMaxGroupLingerDuration;
 
     private BatchableNotificationHandler mHandler;
 
@@ -82,22 +84,28 @@
     public GroupCoalescer(
             @Main DelayableExecutor mainExecutor,
             SystemClock clock, NotifLog log) {
-        this(mainExecutor, clock, log, GROUP_LINGER_DURATION);
+        this(mainExecutor, clock, log, MIN_GROUP_LINGER_DURATION, MAX_GROUP_LINGER_DURATION);
     }
 
     /**
-     * @param groupLingerDuration How long, in ms, that notifications that are members of a group
-     *                            are delayed within the GroupCoalescer before being posted
+     * @param minGroupLingerDuration How long, in ms, to wait for another notification from the same
+     *                               group to arrive before emitting all pending events for that
+     *                               group. Each subsequent arrival of a group member resets the
+     *                               timer for that group.
+     * @param maxGroupLingerDuration The maximum time, in ms, that a group can linger in the
+     *                               coalescer before it's force-emitted.
      */
     GroupCoalescer(
             @Main DelayableExecutor mainExecutor,
             SystemClock clock,
             NotifLog log,
-            long groupLingerDuration) {
+            long minGroupLingerDuration,
+            long maxGroupLingerDuration) {
         mMainExecutor = mainExecutor;
         mClock = clock;
         mLog = log;
-        mGroupLingerDuration = groupLingerDuration;
+        mMinGroupLingerDuration = minGroupLingerDuration;
+        mMaxGroupLingerDuration = maxGroupLingerDuration;
     }
 
     /**
@@ -115,7 +123,7 @@
     private final NotificationHandler mListener = new NotificationHandler() {
         @Override
         public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
-            maybeEmitBatch(sbn.getKey());
+            maybeEmitBatch(sbn);
             applyRanking(rankingMap);
 
             final boolean shouldCoalesce = handleNotificationPosted(sbn, rankingMap);
@@ -130,7 +138,7 @@
 
         @Override
         public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
-            maybeEmitBatch(sbn.getKey());
+            maybeEmitBatch(sbn);
             applyRanking(rankingMap);
             mHandler.onNotificationRemoved(sbn, rankingMap);
         }
@@ -140,7 +148,7 @@
                 StatusBarNotification sbn,
                 RankingMap rankingMap,
                 int reason) {
-            maybeEmitBatch(sbn.getKey());
+            maybeEmitBatch(sbn);
             applyRanking(rankingMap);
             mHandler.onNotificationRemoved(sbn, rankingMap, reason);
         }
@@ -152,13 +160,20 @@
         }
     };
 
-    private void maybeEmitBatch(String memberKey) {
-        CoalescedEvent event = mCoalescedEvents.get(memberKey);
+    private void maybeEmitBatch(StatusBarNotification sbn) {
+        final CoalescedEvent event = mCoalescedEvents.get(sbn.getKey());
+        final EventBatch batch = mBatches.get(sbn.getGroupKey());
         if (event != null) {
             mLog.log(EARLY_BATCH_EMIT,
                     String.format("Modification of %s triggered early emit of batched group %s",
-                            memberKey, requireNonNull(event.getBatch()).mGroupKey));
+                            sbn.getKey(), requireNonNull(event.getBatch()).mGroupKey));
             emitBatch(requireNonNull(event.getBatch()));
+        } else if (batch != null
+                && mClock.uptimeMillis() - batch.mCreatedTimestamp >= mMaxGroupLingerDuration) {
+            mLog.log(BATCH_MAX_TIMEOUT,
+                    String.format("Modification of %s triggered timeout emit of batched group %s",
+                            sbn.getKey(), batch.mGroupKey));
+            emitBatch(batch);
         }
     }
 
@@ -175,7 +190,8 @@
         }
 
         if (sbn.isGroup()) {
-            EventBatch batch = startBatchingGroup(sbn.getGroupKey());
+            final EventBatch batch = getOrBuildBatch(sbn.getGroupKey());
+
             CoalescedEvent event =
                     new CoalescedEvent(
                             sbn.getKey(),
@@ -183,10 +199,10 @@
                             sbn,
                             requireRanking(rankingMap, sbn.getKey()),
                             batch);
+            mCoalescedEvents.put(event.getKey(), event);
 
             batch.mMembers.add(event);
-
-            mCoalescedEvents.put(event.getKey(), event);
+            resetShortTimeout(batch);
 
             return true;
         } else {
@@ -194,27 +210,39 @@
         }
     }
 
-    private EventBatch startBatchingGroup(final String groupKey) {
+    private EventBatch getOrBuildBatch(final String groupKey) {
         EventBatch batch = mBatches.get(groupKey);
         if (batch == null) {
-            final EventBatch newBatch = new EventBatch(mClock.uptimeMillis(), groupKey);
-            mBatches.put(groupKey, newBatch);
-            mMainExecutor.executeDelayed(() -> emitBatch(newBatch), mGroupLingerDuration);
-
-            batch = newBatch;
+            batch = new EventBatch(mClock.uptimeMillis(), groupKey);
+            mBatches.put(groupKey, batch);
         }
         return batch;
     }
 
+    private void resetShortTimeout(EventBatch batch) {
+        if (batch.mCancelShortTimeout != null) {
+            batch.mCancelShortTimeout.run();
+        }
+        batch.mCancelShortTimeout =
+                mMainExecutor.executeDelayed(
+                        () -> {
+                            batch.mCancelShortTimeout = null;
+                            emitBatch(batch);
+                        },
+                        mMinGroupLingerDuration);
+    }
+
     private void emitBatch(EventBatch batch) {
         if (batch != mBatches.get(batch.mGroupKey)) {
-            // If we emit a batch early, we don't want to emit it a second time when its timeout
-            // expires.
-            return;
+            throw new IllegalStateException("Cannot emit out-of-date batch " + batch.mGroupKey);
         }
         if (batch.mMembers.isEmpty()) {
             throw new IllegalStateException("Batch " + batch.mGroupKey + " cannot be empty");
         }
+        if (batch.mCancelShortTimeout != null) {
+            batch.mCancelShortTimeout.run();
+            batch.mCancelShortTimeout = null;
+        }
 
         mBatches.remove(batch.mGroupKey);
 
@@ -299,5 +327,6 @@
         void onNotificationBatchPosted(List<CoalescedEvent> events);
     }
 
-    private static final int GROUP_LINGER_DURATION = 500;
+    private static final int MIN_GROUP_LINGER_DURATION = 50;
+    private static final int MAX_GROUP_LINGER_DURATION = 500;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
index 3cc5e62..ccd7fa3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -99,7 +99,8 @@
     }
 
     private boolean isPeopleNotification(NotificationEntry entry) {
-        return mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn());
+        return mPeopleNotificationIdentifier.isPeopleNotification(
+                entry.getSbn(), entry.getChannel());
     }
 
     private boolean hasUserSetImportance(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
index 2374cde..9adceb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -156,7 +156,8 @@
                     // GroupCoalescer labels:
                     "CoalescedEvent",
                     "EarlyBatchEmit",
-                    "EmitEventBatch"
+                    "EmitEventBatch",
+                    "BatchMaxTimeout"
             };
 
     private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length;
@@ -206,5 +207,6 @@
     public static final int COALESCED_EVENT = COALESCER_EVENT_START_INDEX;
     public static final int EARLY_BATCH_EMIT = COALESCER_EVENT_START_INDEX + 1;
     public static final int EMIT_EVENT_BATCH = COALESCER_EVENT_START_INDEX + 2;
+    public static final int BATCH_MAX_TIMEOUT = COALESCER_EVENT_START_INDEX + 3;
     private static final int TOTAL_COALESCER_EVENT_TYPES = 3;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index 452d1eb..5c90211 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -18,13 +18,14 @@
 
 import android.app.Notification
 import android.content.Context
+import android.app.NotificationChannel
 import android.service.notification.StatusBarNotification
 import android.util.FeatureFlagUtils
 import javax.inject.Inject
 import javax.inject.Singleton
 
 interface PeopleNotificationIdentifier {
-    fun isPeopleNotification(sbn: StatusBarNotification): Boolean
+    fun isPeopleNotification(sbn: StatusBarNotification, channel: NotificationChannel): Boolean
 }
 
 @Singleton
@@ -33,12 +34,13 @@
     private val context: Context
 ) : PeopleNotificationIdentifier {
 
-    override fun isPeopleNotification(sbn: StatusBarNotification) =
-            (sbn.notification.notificationStyle == Notification.MessagingStyle::class.java &&
+    override fun isPeopleNotification(sbn: StatusBarNotification, channel: NotificationChannel) =
+            ((sbn.notification.notificationStyle == Notification.MessagingStyle::class.java &&
                     (sbn.notification.shortcutId != null ||
                             FeatureFlagUtils.isEnabled(
                                     context,
                                     FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ
                             ))) ||
-                    personExtractor.isPersonNotification(sbn)
+                    personExtractor.isPersonNotification(sbn)) &&
+                    !channel.isDemoted
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index ec420f3..3b106cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -25,6 +25,7 @@
 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
 
 import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_BUBBLE;
+import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_DEMOTE;
 import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_FAVORITE;
 import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_HOME;
 import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_MUTE;
@@ -61,6 +62,7 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.Button;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -151,6 +153,11 @@
       closeControls(v, true);
     };
 
+    private OnClickListener mOnDemoteClick = v -> {
+        mSelectedAction = ACTION_DEMOTE;
+        closeControls(v, true);
+    };
+
     public NotificationConversationInfo(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -295,6 +302,8 @@
                     mContext.getDrawable(R.drawable.ic_notifications_alert), null, null, null);
         }
 
+        ImageButton demote = findViewById(R.id.demote);
+        demote.setOnClickListener(mOnDemoteClick);
     }
 
     private void bindHeader() {
@@ -609,7 +618,7 @@
                         }
                         break;
                     case ACTION_DEMOTE:
-                        // TODO: when demotion status field exists on notificationchannel
+                        mChannelToUpdate.setDemoted(!mChannelToUpdate.isDemoted());
                         break;
 
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index f05b585..cca100f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -26,6 +26,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.provider.Settings.Global;
+import android.telephony.Annotation;
 import android.telephony.CellSignalStrength;
 import android.telephony.CellSignalStrengthCdma;
 import android.telephony.NetworkRegistrationInfo;
@@ -37,7 +38,6 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.TelephonyIntents;
@@ -53,7 +53,9 @@
 
 import java.io.PrintWriter;
 import java.util.BitSet;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.regex.Matcher;
@@ -77,12 +79,14 @@
     final SubscriptionInfo mSubscriptionInfo;
 
     // @VisibleForDemoMode
-    final SparseArray<MobileIconGroup> mNetworkToIconLookup;
+    final Map<String, MobileIconGroup> mNetworkToIconLookup;
 
     // Since some pieces of the phone state are interdependent we store it locally,
     // this could potentially become part of MobileState for simplification/complication
     // of code.
     private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+    private boolean mCA = false;
+    private boolean mCAPlus = false;
     private int mDataState = TelephonyManager.DATA_DISCONNECTED;
     private ServiceState mServiceState;
     private SignalStrength mSignalStrength;
@@ -93,9 +97,6 @@
     boolean mInflateSignalStrengths = false;
     @VisibleForTesting
     boolean mIsShowingIconGracefully = false;
-    // Some specific carriers have 5GE network which is special LTE CA network.
-    private static final int NETWORK_TYPE_LTE_CA_5GE =
-            TelephonyManager.getAllNetworkTypes().length + 1;
 
     // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
     // need listener lists anymore.
@@ -106,7 +107,7 @@
         super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
                 NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
                 networkController);
-        mNetworkToIconLookup = new SparseArray<>();
+        mNetworkToIconLookup = new HashMap<>();
         mConfig = config;
         mPhone = phone;
         mDefaults = defaults;
@@ -213,29 +214,38 @@
     private void mapIconSets() {
         mNetworkToIconLookup.clear();
 
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_TD_SCDMA, TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EVDO_0),
+                TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EVDO_A),
+                TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EVDO_B),
+                TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EHRPD),
+                TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_UMTS),
+                TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_TD_SCDMA),
+                TelephonyIcons.THREE_G);
 
         if (!mConfig.showAtLeast3G) {
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_UNKNOWN),
                     TelephonyIcons.UNKNOWN);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X);
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EDGE),
+                    TelephonyIcons.E);
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_CDMA),
+                    TelephonyIcons.ONE_X);
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_1xRTT),
+                    TelephonyIcons.ONE_X);
 
             mDefaultIcons = TelephonyIcons.G;
         } else {
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_UNKNOWN),
                     TelephonyIcons.THREE_G);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE,
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EDGE),
                     TelephonyIcons.THREE_G);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA,
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_CDMA),
                     TelephonyIcons.THREE_G);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT,
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_1xRTT),
                     TelephonyIcons.THREE_G);
             mDefaultIcons = TelephonyIcons.THREE_G;
         }
@@ -250,33 +260,59 @@
             hPlusGroup = TelephonyIcons.H_PLUS;
         }
 
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hPlusGroup);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_HSDPA), hGroup);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_HSUPA), hGroup);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_HSPA), hGroup);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_HSPAP), hPlusGroup);
 
         if (mConfig.show4gForLte) {
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_LTE),
+                    TelephonyIcons.FOUR_G);
             if (mConfig.hideLtePlus) {
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+                mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
                         TelephonyIcons.FOUR_G);
             } else {
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+                mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
                         TelephonyIcons.FOUR_G_PLUS);
             }
         } else {
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
+            mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_LTE),
+                    TelephonyIcons.LTE);
             if (mConfig.hideLtePlus) {
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+                mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
                         TelephonyIcons.LTE);
             } else {
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+                mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
                         TelephonyIcons.LTE_PLUS);
             }
         }
-        mNetworkToIconLookup.put(NETWORK_TYPE_LTE_CA_5GE,
+        mNetworkToIconLookup.put(toIconKeyCAPlus(TelephonyManager.NETWORK_TYPE_LTE),
                 TelephonyIcons.LTE_CA_5G_E);
-        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
+        mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_IWLAN),
+                TelephonyIcons.WFC);
+    }
+
+    private String getIconKey() {
+        if (mCA) {
+            return toIconKeyCA(mDataNetType);
+        } else if (mCAPlus) {
+            return toIconKeyCAPlus(mDataNetType);
+        } else {
+            return toIconKey(mDataNetType);
+        }
+    }
+
+    // Some specific carriers have 5GE network which is special CA network.
+    private String toIconKeyCAPlus(@Annotation.NetworkType int networkType) {
+        return toIconKeyCA(networkType) + "_Plus";
+    }
+
+    private String toIconKeyCA(@Annotation.NetworkType int networkType) {
+        return toIconKey(networkType) + "_CA";
+    }
+
+    private String toIconKey(@Annotation.NetworkType int networkType) {
+        return Integer.toString(networkType);
     }
 
     private void updateInflateSignalStrength() {
@@ -523,10 +559,11 @@
             nr5GIconGroup = adjustNr5GIconGroupByDisplayGraceTime(nr5GIconGroup);
         }
 
+        String iconKey = getIconKey();
         if (nr5GIconGroup != null) {
             mCurrentState.iconGroup = nr5GIconGroup;
-        } else if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
-            mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
+        } else if (mNetworkToIconLookup.get(iconKey) != null) {
+            mCurrentState.iconGroup = mNetworkToIconLookup.get(iconKey);
         } else {
             mCurrentState.iconGroup = mDefaultIcons;
         }
@@ -679,6 +716,8 @@
         pw.println("  mSignalStrength=" + mSignalStrength + ",");
         pw.println("  mDataState=" + mDataState + ",");
         pw.println("  mDataNetType=" + mDataNetType + ",");
+        pw.println("  mCA=" + mCA + ",");
+        pw.println("  mCAPlus=" + mCAPlus + ",");
         pw.println("  mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
         pw.println("  isDataDisabled=" + isDataDisabled() + ",");
         pw.println("  mIsShowingIconGracefully=" + mIsShowingIconGracefully + ",");
@@ -729,11 +768,13 @@
 
         private void updateDataNetType(int networkType) {
             mDataNetType = networkType;
+            mCA = false;
+            mCAPlus = false;
             if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE) {
                 if (isCarrierSpecificDataIcon()) {
-                    mDataNetType = NETWORK_TYPE_LTE_CA_5GE;
+                    mCAPlus = true;
                 } else if (mServiceState != null && mServiceState.isUsingCarrierAggregation()) {
-                    mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
+                    mCA = true;
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 679fa7e..6b3c5dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -22,8 +22,7 @@
 import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE;
 import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT;
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
-
-import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
+import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -57,7 +56,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.DemoMode;
@@ -547,7 +545,7 @@
                 mReceiverHandler.post(this::handleConfigurationChanged);
                 break;
             default:
-                int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
                 if (SubscriptionManager.isValidSubscriptionId(subId)) {
                     if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
@@ -582,7 +580,7 @@
     }
 
     private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
-        if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
+        if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
             SubscriptionInfo info1 = subscriptions.get(0);
             SubscriptionInfo info2 = subscriptions.get(1);
             if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 2e0fb3b..12da006 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -57,7 +57,6 @@
 import android.testing.TestableContext;
 import android.testing.TestableLooper;
 
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.DumpController;
 import com.android.systemui.SysuiTestCase;
@@ -524,9 +523,9 @@
         int subscription = simInited
                 ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE;
         if (data != null) intent.putExtras(data);
-        intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
-        intent.putExtra("subscription", subscription);
-        intent.putExtra("slot", 0/* SLOT 1 */);
+
+        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subscription);
+        intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
         return intent;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index cc5514f..d852fa1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -571,7 +571,7 @@
     }
 
     private NotificationEntry createNotification() {
-        Notification.Builder n = new Notification.Builder(mContext, "")
+        Notification.Builder n = new Notification.Builder(mContext, "id")
                 .setSmallIcon(R.drawable.ic_person)
                 .setContentTitle("Title")
                 .setContentText("Text");
@@ -582,6 +582,7 @@
                 .setUid(TEST_UID)
                 .setId(mId++)
                 .setNotification(n.build())
+                .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
                 .setUser(new UserHandle(ActivityManager.getCurrentUser()))
                 .build();
     }
@@ -616,7 +617,7 @@
     @Test
     public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() {
         Assert.sMainLooper = TestableLooper.get(this).getLooper();
-        Notification.Builder n = new Notification.Builder(mContext, "")
+        Notification.Builder n = new Notification.Builder(mContext, "di")
                 .setSmallIcon(R.drawable.ic_person)
                 .setContentTitle("Title")
                 .setContentText("Text");
@@ -628,6 +629,7 @@
                 .setId(mId++)
                 .setNotification(n.build())
                 .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+                .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
                 .build();
 
         mEntryManager.addActiveNotificationForTest(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 93909dc..7c3665b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -60,7 +60,8 @@
         final NotificationEntry entry = new NotificationEntryBuilder()
                 .setImportance(IMPORTANCE_HIGH)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+                .thenReturn(false);
 
         // THEN it has high priority
         assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -75,7 +76,8 @@
                 .setNotification(notification)
                 .setImportance(IMPORTANCE_LOW)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(true);
+        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+                .thenReturn(true);
 
         // THEN it has high priority
         assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -90,7 +92,8 @@
         final NotificationEntry entry = new NotificationEntryBuilder()
                 .setNotification(notification)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+                .thenReturn(false);
 
         // THEN it has high priority
         assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -106,7 +109,8 @@
                 .setNotification(notification)
                 .setImportance(IMPORTANCE_LOW)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+                .thenReturn(false);
 
         // THEN it has high priority
         assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -122,7 +126,8 @@
                 .setNotification(notification)
                 .setImportance(IMPORTANCE_MIN)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+                .thenReturn(false);
 
         // THEN it does NOT have high priority
         assertFalse(mHighPriorityProvider.isHighPriority(entry));
@@ -144,7 +149,8 @@
                 .setNotification(notification)
                 .setChannel(channel)
                 .build();
-        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(true);
+        when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+                .thenReturn(true);
 
         // THEN it does NOT have high priority
         assertFalse(mHighPriorityProvider.isHighPriority(entry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index e273191..7ab4846 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.collection
 
 import android.app.Notification
+import android.app.NotificationChannel
 import android.app.NotificationManager.IMPORTANCE_DEFAULT
 import android.app.NotificationManager.IMPORTANCE_HIGH
 import android.app.NotificationManager.IMPORTANCE_LOW
@@ -81,6 +82,7 @@
                 .setNotification(
                         Notification.Builder(mContext, "test")
                                 .build())
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
@@ -94,6 +96,7 @@
                 .setNotification(
                         Notification.Builder(mContext, "test")
                                 .build())
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
@@ -116,6 +119,7 @@
                 .setOpPkg("pkg")
                 .setTag("tag")
                 .setNotification(aN)
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
@@ -130,6 +134,7 @@
                 .setOpPkg("pkg2")
                 .setTag("tag")
                 .setNotification(bN)
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
                 .setUser(mContext.getUser())
                 .setOverrideGroupKey("")
                 .build()
@@ -149,6 +154,7 @@
                 .setTag("tag")
                 .setNotification(notif)
                 .setUser(mContext.user)
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
                 .setOverrideGroupKey("")
                 .build()
 
@@ -168,6 +174,7 @@
                 .setTag("tag")
                 .setNotification(notif)
                 .setUser(mContext.user)
+                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
                 .setOverrideGroupKey("")
                 .build()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
index 5e0baf2..86c1eb97 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
@@ -80,7 +80,8 @@
                         mExecutor,
                         mClock,
                         mLog,
-                        LINGER_DURATION);
+                        MIN_LINGER_DURATION,
+                        MAX_LINGER_DURATION);
         mCoalescer.setNotificationHandler(mListener);
         mCoalescer.attach(mListenerService);
 
@@ -96,7 +97,7 @@
                 new NotificationEntryBuilder()
                         .setId(0)
                         .setPkg(TEST_PACKAGE_A));
-        mClock.advanceTime(LINGER_DURATION);
+        mClock.advanceTime(MIN_LINGER_DURATION);
 
         // THEN the event is passed through to the handler
         verify(mListener).onNotificationPosted(notif1.sbn, notif1.rankingMap);
@@ -144,12 +145,16 @@
                 .setId(1)
                 .setGroup(mContext, GROUP_1));
 
+        mClock.advanceTime(2);
+
         NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
                 .setPkg(TEST_PACKAGE_A)
                 .setId(2)
                 .setGroup(mContext, GROUP_1)
                 .setGroupSummary(mContext, true));
 
+        mClock.advanceTime(3);
+
         NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder()
                 .setPkg(TEST_PACKAGE_A)
                 .setId(3)
@@ -161,7 +166,7 @@
         verify(mListener, never()).onNotificationBatchPosted(anyList());
 
         // WHEN enough time passes
-        mClock.advanceTime(LINGER_DURATION);
+        mClock.advanceTime(MIN_LINGER_DURATION);
 
         // THEN the coalesced notifs are applied. The summary is sorted to the front.
         verify(mListener).onNotificationBatchPosted(Arrays.asList(
@@ -212,7 +217,7 @@
 
         // WHEN the time runs out on the remainder of the group
         clearInvocations(mListener);
-        mClock.advanceTime(LINGER_DURATION);
+        mClock.advanceTime(MIN_LINGER_DURATION);
 
         // THEN no lingering batch is applied
         verify(mListener, never()).onNotificationBatchPosted(anyList());
@@ -225,11 +230,13 @@
                 .setPkg(TEST_PACKAGE_A)
                 .setId(1)
                 .setGroup(mContext, GROUP_1));
+        mClock.advanceTime(2);
         NotifEvent notif2a = mNoMan.postNotif(new NotificationEntryBuilder()
                 .setPkg(TEST_PACKAGE_A)
                 .setId(2)
                 .setContentTitle(mContext, "Version 1")
                 .setGroup(mContext, GROUP_1));
+        mClock.advanceTime(4);
 
         // WHEN one of them gets updated
         NotifEvent notif2b = mNoMan.postNotif(new NotificationEntryBuilder()
@@ -248,7 +255,7 @@
                 any(RankingMap.class));
 
         // THEN second, the update is emitted
-        mClock.advanceTime(LINGER_DURATION);
+        mClock.advanceTime(MIN_LINGER_DURATION);
         verify(mListener).onNotificationBatchPosted(Collections.singletonList(
                 new CoalescedEvent(notif2b.key, 0, notif2b.sbn, notif2b.ranking, null)
         ));
@@ -308,14 +315,61 @@
                 .setId(17));
 
         // THEN they have the new rankings when they are eventually emitted
-        mClock.advanceTime(LINGER_DURATION);
+        mClock.advanceTime(MIN_LINGER_DURATION);
         verify(mListener).onNotificationBatchPosted(Arrays.asList(
                 new CoalescedEvent(notif1.key, 0, notif1.sbn, ranking1b, null),
                 new CoalescedEvent(notif2.key, 1, notif2.sbn, ranking2b, null)
         ));
     }
 
-    private static final long LINGER_DURATION = 4700;
+    @Test
+    public void testMaxLingerDuration() {
+        // GIVEN five coalesced notifications that have collectively taken 20ms to arrive, 2ms
+        // longer than the max linger duration
+        NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(1)
+                .setGroup(mContext, GROUP_1));
+        mClock.advanceTime(4);
+        NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(2)
+                .setGroup(mContext, GROUP_1));
+        mClock.advanceTime(4);
+        NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(3)
+                .setGroup(mContext, GROUP_1));
+        mClock.advanceTime(4);
+        NotifEvent notif4 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(4)
+                .setGroup(mContext, GROUP_1));
+        mClock.advanceTime(4);
+        NotifEvent notif5 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(5)
+                .setGroup(mContext, GROUP_1));
+        mClock.advanceTime(4);
+
+        // WHEN a sixth notification arrives
+        NotifEvent notif6 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(6)
+                .setGroup(mContext, GROUP_1));
+
+        // THEN the first five notifications are emitted in a batch
+        verify(mListener).onNotificationBatchPosted(Arrays.asList(
+                new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null),
+                new CoalescedEvent(notif2.key, 1, notif2.sbn, notif2.ranking, null),
+                new CoalescedEvent(notif3.key, 2, notif3.sbn, notif3.ranking, null),
+                new CoalescedEvent(notif4.key, 3, notif4.sbn, notif4.ranking, null),
+                new CoalescedEvent(notif5.key, 4, notif5.sbn, notif5.ranking, null)
+        ));
+    }
+
+    private static final long MIN_LINGER_DURATION = 5;
+    private static final long MAX_LINGER_DURATION = 18;
 
     private static final String TEST_PACKAGE_A = "com.test.package_a";
     private static final String TEST_PACKAGE_B = "com.test.package_b";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 0bf458c..61f0b26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -62,6 +62,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.Button;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -684,6 +685,34 @@
     }
 
     @Test
+    public void testDemote() throws Exception {
+        mNotificationInfo.bindNotification(
+                mShortcutManager,
+                mLauncherApps,
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mEntry,
+                null,
+                null,
+                null,
+                true);
+
+
+        ImageButton demote = mNotificationInfo.findViewById(R.id.demote);
+        demote.performClick();
+        mTestableLooper.processAllMessages();
+
+        ArgumentCaptor<NotificationChannel> captor =
+                ArgumentCaptor.forClass(NotificationChannel.class);
+        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+                anyString(), anyInt(), captor.capture());
+        assertTrue(captor.getValue().isDemoted());
+    }
+
+    @Test
     public void testMute_mute() throws Exception {
         mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
         mConversationChannel.setImportance(IMPORTANCE_DEFAULT);
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 068707f..21100458ad 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -237,6 +237,9 @@
     // Inform the user that the current network may not support using a randomized MAC address.
     NOTE_NETWORK_NO_MAC_RANDOMIZATION_SUPPORT = 56;
 
+    // Inform the user that EAP failure occurs
+    NOTE_WIFI_EAP_FAILURE = 57;
+
     // ADD_NEW_IDS_ABOVE_THIS_LINE
     // Legacy IDs with arbitrary values appear below
     // Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 396b977..bcc3bdb 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -44,6 +44,7 @@
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
+import static com.android.server.storage.StorageUserConnection.REMOTE_TIMEOUT_SECONDS;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -1985,16 +1986,28 @@
             Slog.i(TAG, "Mounting volume " + vol);
             mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
                     @Override
-                    public boolean onVolumeChecking(FileDescriptor deviceFd, String path,
+                    public boolean onVolumeChecking(FileDescriptor fd, String path,
                             String internalPath) {
                         vol.path = path;
                         vol.internalPath = internalPath;
+                        ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
                         try {
-                            mStorageSessionController.onVolumeMount(deviceFd, vol);
+                            mStorageSessionController.onVolumeMount(pfd, vol);
                             return true;
                         } catch (ExternalStorageServiceException e) {
-                            Slog.i(TAG, "Failed to mount volume " + vol, e);
+                            Slog.e(TAG, "Failed to mount volume " + vol, e);
+
+                            Slog.i(TAG, "Scheduling reset in one minute");
+                            mHandler.removeMessages(H_RESET);
+                            mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
+                                    TimeUnit.SECONDS.toMillis(REMOTE_TIMEOUT_SECONDS * 2));
                             return false;
+                        } finally {
+                            try {
+                                pfd.close();
+                            } catch (Exception e) {
+                                Slog.e(TAG, "Failed to close FUSE device fd", e);
+                            }
                         }
                     }
                 });
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 37026fd..a98b83b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -402,7 +402,7 @@
     }
 
     public ParcelFileDescriptor getStatisticsStream() {
-        mContext.enforceCallingPermission(
+        mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BATTERY_STATS, null);
         //Slog.i("foo", "SENDING BATTERY INFO:");
         //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
index 03392ab..87eee4e 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
@@ -28,9 +28,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.TreeSet;
 import java.util.stream.Collectors;
 
 /** Helper class to identify the necessary indexes that needs to be read. */
@@ -93,19 +93,28 @@
         return keyToIndexMap;
     }
 
-    private RuleIndexRange searchIndexingKeysRangeContainingKey(
+    private static RuleIndexRange searchIndexingKeysRangeContainingKey(
             LinkedHashMap<String, Integer> indexMap, String searchedKey) {
-        TreeSet<String> keyTreeSet =
-                indexMap.keySet().stream()
-                        .filter(key -> !key.matches(START_INDEXING_KEY) && !key.matches(
-                                END_INDEXING_KEY))
-                        .collect(Collectors.toCollection(TreeSet::new));
-
-        String minIndex = keyTreeSet.floor(searchedKey);
-        String maxIndex = keyTreeSet.higher(searchedKey);
-
+        List<String> keys = indexMap.keySet().stream().collect(Collectors.toList());
+        List<String> identifiedKeyRange =
+                searchKeysRangeContainingKey(keys, searchedKey, 0, keys.size() - 1);
         return new RuleIndexRange(
-                indexMap.get(minIndex == null ? START_INDEXING_KEY : minIndex),
-                indexMap.get(maxIndex == null ? END_INDEXING_KEY : maxIndex));
+                indexMap.get(identifiedKeyRange.get(0)), indexMap.get(identifiedKeyRange.get(1)));
+    }
+
+    private static List<String> searchKeysRangeContainingKey(
+            List<String> sortedKeyList, String key, int startIndex, int endIndex) {
+        if (endIndex - startIndex == 1) {
+            return Arrays.asList(sortedKeyList.get(startIndex), sortedKeyList.get(endIndex));
+        }
+
+        int midKeyIndex = startIndex + ((endIndex - startIndex) / 2);
+        String midKey = sortedKeyList.get(midKeyIndex);
+
+        if (key.compareTo(midKey) >= 0) {
+            return searchKeysRangeContainingKey(sortedKeyList, key, midKeyIndex, endIndex);
+        } else {
+            return searchKeysRangeContainingKey(sortedKeyList, key, startIndex, midKeyIndex);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 7d0072a..5c0dd9a 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -360,7 +360,7 @@
      */
     boolean enableForPackageInApex(String packageName, long installedVersion,
             int rollbackDataPolicy) {
-        // TODO(b/142712057): Extract the new version number of apk-in-apex
+        // TODO(b/147666157): Extract the new version number of apk-in-apex
         // The new version for the apk-in-apex is set to 0 for now. If the package is then further
         // updated via non-staged install flow, then RollbackManagerServiceImpl#onPackageReplaced()
         // will be called and this rollback will be deleted. Other ways of package update have not
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 7a8ddd4..6686de9 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -213,6 +213,23 @@
                 if (packageRollback.getVersionRolledBackFrom().equals(failedPackage)) {
                     return rollback;
                 }
+                // TODO(b/147666157): Extract version number of apk-in-apex so that we don't have
+                //  to rely on complicated reasoning as below
+
+                // Due to b/147666157, for apk in apex, we do not know the version we are rolling
+                // back from. But if a package X is embedded in apex A exclusively (not embedded in
+                // any other apex), which is not guaranteed, then it is sufficient to check only
+                // package names here, as the version of failedPackage and the PackageRollbackInfo
+                // can't be different. If failedPackage has a higher version, then it must have
+                // been updated somehow. There are two ways: it was updated by an update of apex A
+                // or updated directly as apk. In both cases, this rollback would have gotten
+                // expired when onPackageReplaced() was called. Since the rollback exists, it has
+                // same version as failedPackage.
+                if (packageRollback.isApkInApex()
+                        && packageRollback.getVersionRolledBackFrom().getPackageName()
+                        .equals(failedPackage.getPackageName())) {
+                    return rollback;
+                }
             }
         }
         return null;
diff --git a/services/core/java/com/android/server/stats/StatsPullAtomService.java b/services/core/java/com/android/server/stats/StatsPullAtomService.java
index 03bada4..f78330e 100644
--- a/services/core/java/com/android/server/stats/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/StatsPullAtomService.java
@@ -1214,28 +1214,119 @@
         // No op.
     }
 
-    private void registerDeviceCalculatedPowerUse() {
-        // No op.
+    // TODO: move to top of file when all migrations are complete
+    private BatteryStatsHelper mBatteryStatsHelper = null;
+    private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000;
+    private long mBatteryStatsHelperTimestampMs = -MAX_BATTERY_STATS_HELPER_FREQUENCY_MS;
+    private static final long MILLI_AMP_HR_TO_NANO_AMP_SECS = 1_000_000L * 3600L;
+
+    private BatteryStatsHelper getBatteryStatsHelper() {
+        if (mBatteryStatsHelper == null) {
+            final long callingToken = Binder.clearCallingIdentity();
+            try {
+                // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly().
+                mBatteryStatsHelper = new BatteryStatsHelper(mContext, false);
+            } finally {
+                Binder.restoreCallingIdentity(callingToken);
+            }
+            mBatteryStatsHelper.create((Bundle) null);
+        }
+        long currentTime = SystemClock.elapsedRealtime();
+        if (currentTime - mBatteryStatsHelperTimestampMs >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) {
+            // Load BatteryStats and do all the calculations.
+            mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.USER_ALL);
+            // Calculations are done so we don't need to save the raw BatteryStats data in RAM.
+            mBatteryStatsHelper.clearStats();
+            mBatteryStatsHelperTimestampMs = currentTime;
+        }
+        return mBatteryStatsHelper;
     }
 
-    private void pullDeviceCalculatedPowerUse() {
-        // No op.
+    private long milliAmpHrsToNanoAmpSecs(double mAh) {
+        return (long) (mAh * MILLI_AMP_HR_TO_NANO_AMP_SECS + 0.5);
+    }
+
+    private void registerDeviceCalculatedPowerUse() {
+        int tagId = StatsLog.DEVICE_CALCULATED_POWER_USE;
+        mStatsManager.registerPullAtomCallback(
+                tagId,
+                null, // use default PullAtomMetadata values
+                (atomTag, data) -> pullDeviceCalculatedPowerUse(atomTag, data),
+                BackgroundThread.getExecutor()
+        );
+    }
+
+    private int pullDeviceCalculatedPowerUse(int atomTag, List<StatsEvent> pulledData) {
+        BatteryStatsHelper bsHelper = getBatteryStatsHelper();
+        StatsEvent e = StatsEvent.newBuilder()
+                .setAtomId(atomTag)
+                .writeLong(milliAmpHrsToNanoAmpSecs(bsHelper.getComputedPower()))
+                .build();
+        pulledData.add(e);
+        return StatsManager.PULL_SUCCESS;
     }
 
     private void registerDeviceCalculatedPowerBlameUid() {
-        // No op.
+        int tagId = StatsLog.DEVICE_CALCULATED_POWER_BLAME_UID;
+        mStatsManager.registerPullAtomCallback(
+                tagId,
+                null, // use default PullAtomMetadata values
+                (atomTag, data) -> pullDeviceCalculatedPowerBlameUid(atomTag, data),
+                BackgroundThread.getExecutor()
+        );
     }
 
-    private void pullDeviceCalculatedPowerBlameUid() {
-        // No op.
+    private int pullDeviceCalculatedPowerBlameUid(int atomTag, List<StatsEvent> pulledData) {
+        final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
+        if (sippers == null) {
+            return StatsManager.PULL_SKIP;
+        }
+
+        for (BatterySipper bs : sippers) {
+            if (bs.drainType != bs.drainType.APP) {
+                continue;
+            }
+            StatsEvent e = StatsEvent.newBuilder()
+                    .setAtomId(atomTag)
+                    .writeInt(bs.uidObj.getUid())
+                    .writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah))
+                    .build();
+            pulledData.add(e);
+        }
+        return StatsManager.PULL_SUCCESS;
     }
 
     private void registerDeviceCalculatedPowerBlameOther() {
-        // No op.
+        int tagId = StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER;
+        mStatsManager.registerPullAtomCallback(
+                tagId,
+                null, // use default PullAtomMetadata values
+                (atomTag, data) -> pullDeviceCalculatedPowerBlameOther(atomTag, data),
+                BackgroundThread.getExecutor()
+        );
     }
 
-    private void pullDeviceCalculatedPowerBlameOther() {
-        // No op.
+    private int pullDeviceCalculatedPowerBlameOther(int atomTag, List<StatsEvent> pulledData) {
+        final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
+        if (sippers == null) {
+            return StatsManager.PULL_SKIP;
+        }
+
+        for (BatterySipper bs : sippers) {
+            if (bs.drainType == bs.drainType.APP) {
+                continue; // This is a separate atom; see pullDeviceCalculatedPowerBlameUid().
+            }
+            if (bs.drainType == bs.drainType.USER) {
+                continue; // This is not supported. We purposefully calculate over USER_ALL.
+            }
+            StatsEvent e = StatsEvent.newBuilder()
+                    .setAtomId(atomTag)
+                    .writeInt(bs.drainType.ordinal())
+                    .writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah))
+                    .build();
+            pulledData.add(e);
+        }
+        return StatsManager.PULL_SUCCESS;
     }
 
     private void registerDebugElapsedClock() {
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index f4fb93a..baef5d6 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -40,9 +40,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
-import java.io.FileDescriptor;
 import java.util.Objects;
 
 /**
@@ -82,7 +80,7 @@
      * @throws ExternalStorageServiceException if the session fails to start
      * @throws IllegalStateException if a session has already been created for {@code vol}
      */
-    public void onVolumeMount(FileDescriptor deviceFd, VolumeInfo vol)
+    public void onVolumeMount(ParcelFileDescriptor deviceFd, VolumeInfo vol)
             throws ExternalStorageServiceException {
         if (!shouldHandle(vol)) {
             return;
@@ -102,8 +100,8 @@
                 mConnections.put(userId, connection);
             }
             Slog.i(TAG, "Creating and starting session with id: " + sessionId);
-            connection.startSession(sessionId, new ParcelFileDescriptor(deviceFd),
-                    vol.getPath().getPath(), vol.getInternalPath().getPath());
+            connection.startSession(sessionId, deviceFd, vol.getPath().getPath(),
+                    vol.getInternalPath().getPath());
         }
     }
 
@@ -185,7 +183,7 @@
      * This call removes all sessions for the user that is being stopped;
      * this will make sure that we don't rebind to the service needlessly.
      */
-    public void onUserStopping(int userId) throws ExternalStorageServiceException {
+    public void onUserStopping(int userId) {
         if (!shouldHandle(null)) {
             return;
         }
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index c02ded8..dd18f4e 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -60,7 +60,8 @@
  */
 public final class StorageUserConnection {
     private static final String TAG = "StorageUserConnection";
-    private static final int REMOTE_TIMEOUT_SECONDS = 15;
+
+    public static final int REMOTE_TIMEOUT_SECONDS = 5;
 
     private final Object mLock = new Object();
     private final Context mContext;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 19bc560..3f3408f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6363,6 +6363,14 @@
      *         aspect ratio.
      */
     boolean shouldUseSizeCompatMode() {
+        if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) {
+            final ActivityRecord root = task != null ? task.getRootActivity() : null;
+            if (root != null && root != this && !root.shouldUseSizeCompatMode()) {
+                // If the root activity doesn't use size compatibility mode, the activities above
+                // are forced to be the same for consistent visual appearance.
+                return false;
+            }
+        }
         return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio())
                 // The configuration of non-standard type should be enforced by system.
                 && isActivityTypeStandard()
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index e0a7b18..2cb7d5a 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -33,6 +33,27 @@
     private final HighRefreshRateBlacklist mHighRefreshRateBlacklist;
     private final WindowManagerService mWmService;
 
+    /**
+     * The following constants represent priority of the window. SF uses this information when
+     * deciding which window has a priority when deciding about the refresh rate of the screen.
+     * Priority 0 is considered the highest priority. -1 means that the priority is unset.
+     */
+    static final int LAYER_PRIORITY_UNSET = -1;
+    /** Windows that are in focus and voted for the preferred mode ID have the highest priority. */
+    static final int LAYER_PRIORITY_FOCUSED_WITH_MODE = 0;
+    /**
+     * This is a default priority for all windows that are in focus, but have not requested a
+     * specific mode ID.
+     */
+    static final int LAYER_PRIORITY_FOCUSED_WITHOUT_MODE = 1;
+    /**
+     * Windows that are not in focus, but voted for a specific mode ID should be
+     * acknowledged by SF. For example, there are two applications in a split screen.
+     * One voted for a given mode ID, and the second one doesn't care. Even though the
+     * second one might be in focus, we can honor the mode ID of the first one.
+     */
+    static final int LAYER_PRIORITY_NOT_FOCUSED_WITH_MODE = 2;
+
     RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo,
             HighRefreshRateBlacklist blacklist) {
         mLowRefreshRateId = findLowRefreshRateModeId(displayInfo);
@@ -92,4 +113,28 @@
         }
         return 0;
     }
+
+    /**
+     * Calculate the priority based on whether the window is in focus and whether the application
+     * voted for a specific refresh rate.
+     *
+     * TODO(b/144307188): This is a very basic algorithm version. Explore other signals that might
+     * be useful in edge cases when we are deciding which layer should get priority when deciding
+     * about the refresh rate.
+     */
+    int calculatePriority(WindowState w) {
+        boolean isFocused = w.isFocused();
+        int preferredModeId = getPreferredModeId(w);
+
+        if (!isFocused && preferredModeId > 0) {
+            return LAYER_PRIORITY_NOT_FOCUSED_WITH_MODE;
+        }
+        if (isFocused && preferredModeId == 0) {
+            return LAYER_PRIORITY_FOCUSED_WITHOUT_MODE;
+        }
+        if (isFocused && preferredModeId > 0) {
+            return LAYER_PRIORITY_FOCUSED_WITH_MODE;
+        }
+        return LAYER_PRIORITY_UNSET;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c2eb0e4..36e9273 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -657,6 +657,13 @@
     private KeyInterceptionInfo mKeyInterceptionInfo;
 
     /**
+     * This information is passed to SurfaceFlinger to decide which window should have a priority
+     * when deciding about the refresh rate of the display. All windows have the lowest priority by
+     * default. The variable is cached, so we do not send too many updates to SF.
+     */
+    int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET;
+
+    /**
      * @return The insets state as requested by the client, i.e. the dispatched insets state
      *         for which the visibilities are overridden with what the client requested.
      */
@@ -5165,6 +5172,24 @@
         }
     }
 
+
+    /**
+     * Notifies SF about the priority of the window, if it changed. SF then uses this information
+     * to decide which window's desired rendering rate should have a priority when deciding about
+     * the refresh rate of the screen. Priority
+     * {@link RefreshRatePolicy#LAYER_PRIORITY_FOCUSED_WITH_MODE} is considered the highest.
+     */
+    @VisibleForTesting
+    void updateFrameRateSelectionPriorityIfNeeded() {
+        final int priority = getDisplayContent().getDisplayPolicy().getRefreshRatePolicy()
+                .calculatePriority(this);
+        if (mFrameRateSelectionPriority != priority) {
+            mFrameRateSelectionPriority = priority;
+            getPendingTransaction().setFrameRateSelectionPriority(mSurfaceControl,
+                    mFrameRateSelectionPriority);
+        }
+    }
+
     @Override
     void prepareSurfaces() {
         final Dimmer dimmer = getDimmer();
@@ -5173,6 +5198,8 @@
             applyDims(dimmer);
         }
         updateSurfacePosition();
+        // Send information to SufaceFlinger about the priority of the current window.
+        updateFrameRateSelectionPriorityIfNeeded();
 
         mWinAnimator.prepareSurfaceLocked(true);
         super.prepareSurfaces();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index f2e118d..e0e374b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -50,6 +50,7 @@
 import android.os.BatteryManagerInternal;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 
 import com.android.server.AppStateTracker;
@@ -95,6 +96,7 @@
                 .initMocks(this)
                 .strictness(Strictness.LENIENT)
                 .mockStatic(LocalServices.class)
+                .mockStatic(ServiceManager.class)
                 .startMocking();
 
         // Called in JobSchedulerService constructor.
diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
index 47c7e56..a1810b9 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.integrity;
 
+import static com.android.server.integrity.model.IndexingFileConstants.INDEXING_BLOCK_SIZE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.integrity.AppInstallMetadata;
@@ -159,13 +161,14 @@
         // Create a rule set with 2500 package name indexed, 2500 app certificate indexed and
         // 500 unindexed rules.
         List<Rule> rules = new ArrayList<>();
+        int unindexedRuleCount = 70;
 
         for (int i = 0; i < 2500; i++) {
             rules.add(getPackageNameIndexedRule(String.format("%s%04d", packageName, i)));
             rules.add(getAppCertificateIndexedRule(String.format("%s%04d", appCertificate, i)));
         }
 
-        for (int i = 0; i < 70; i++) {
+        for (int i = 0; i < unindexedRuleCount; i++) {
             rules.add(getInstallerCertificateRule(String.format("%s%04d", installerName, i)));
         }
 
@@ -187,7 +190,8 @@
         List<Rule> rulesFetched = mIntegrityFileManager.readRules(appInstallMetadata);
 
         // Verify that we do not load all the rules and we have the necessary rules to evaluate.
-        assertThat(rulesFetched.size()).isEqualTo(270);
+        assertThat(rulesFetched.size())
+                .isEqualTo(INDEXING_BLOCK_SIZE * 2 + unindexedRuleCount);
         assertThat(rulesFetched)
                 .containsAllOf(
                         getPackageNameIndexedRule(installedPackageName),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 7ac45f0..6f16574 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -227,6 +227,7 @@
         assertEquals(expected.getLightColor(), actual.getLightColor());
         assertEquals(expected.getParentChannelId(), actual.getParentChannelId());
         assertEquals(expected.getConversationId(), actual.getConversationId());
+        assertEquals(expected.isDemoted(), actual.isDemoted());
     }
 
     private void compareChannelsParentChild(NotificationChannel parent,
@@ -355,6 +356,7 @@
         channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
         channel2.setLightColor(Color.BLUE);
         channel2.setConversationId("id1", "conversation");
+        channel2.setDemoted(true);
 
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
new file mode 100644
index 0000000..032edde
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * This file tests WM setting the priority on windows that is used in SF to determine at what
+ * frame rate the Display should run. Any changes to the algorithm should be reflected in these
+ * tests.
+ *
+ * Build/Install/Run: atest FrameRateSelectionPriority
+ */
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class FrameRateSelectionPriorityTests extends WindowTestsBase {
+
+    @Test
+    public void basicTest() {
+        final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+        assertNotNull("Window state is created", appWindow);
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // Priority doesn't change.
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+        // Call the function a few times.
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+
+        // Since nothing changed in the priority state, the transaction should not be updating.
+        verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
+                appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+    }
+
+    @Test
+    public void testApplicationInFocusWithoutModeId() {
+        final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+        assertEquals(appWindow.getDisplayContent().getDisplayPolicy().getRefreshRatePolicy()
+                .getPreferredModeId(appWindow), 0);
+
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // Priority stays MAX_VALUE.
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+        verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
+                appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+        // Application is in focus.
+        appWindow.mToken.mDisplayContent.mCurrentFocus = appWindow;
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // Priority changes to 1.
+        assertEquals(appWindow.mFrameRateSelectionPriority, 1);
+        verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+                appWindow.getSurfaceControl(), 1);
+    }
+
+    @Test
+    public void testApplicationInFocusWithModeId() {
+        final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+        // Application is in focus.
+        appWindow.mToken.mDisplayContent.mCurrentFocus = appWindow;
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // Priority changes.
+        assertEquals(appWindow.mFrameRateSelectionPriority, 1);
+        // Update the mode ID to a requested number.
+        appWindow.mAttrs.preferredDisplayModeId = 1;
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // Priority changes.
+        assertEquals(appWindow.mFrameRateSelectionPriority, 0);
+
+        // Remove the mode ID request.
+        appWindow.mAttrs.preferredDisplayModeId = 0;
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // Priority changes.
+        assertEquals(appWindow.mFrameRateSelectionPriority, 1);
+
+        // Verify we called actions on Transactions correctly.
+        verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
+                appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+        verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+                appWindow.getSurfaceControl(), 0);
+        verify(appWindow.getPendingTransaction(), times(2)).setFrameRateSelectionPriority(
+                appWindow.getSurfaceControl(), 1);
+    }
+
+    @Test
+    public void testApplicationNotInFocusWithModeId() {
+        final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+        final WindowState inFocusWindow = createWindow(null, TYPE_APPLICATION, "inFocus");
+        appWindow.mToken.mDisplayContent.mCurrentFocus = inFocusWindow;
+
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // The window is not in focus.
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+        // Update the mode ID to a requested number.
+        appWindow.mAttrs.preferredDisplayModeId = 1;
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // Priority changes.
+        assertEquals(appWindow.mFrameRateSelectionPriority, 2);
+
+        verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+                appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+        verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+                appWindow.getSurfaceControl(), 2);
+    }
+
+    @Test
+    public void testApplicationNotInFocusWithoutModeId() {
+        final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+        final WindowState inFocusWindow = createWindow(null, TYPE_APPLICATION, "inFocus");
+        appWindow.mToken.mDisplayContent.mCurrentFocus = inFocusWindow;
+
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // The window is not in focus.
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+        // Make sure that the mode ID is not set.
+        appWindow.mAttrs.preferredDisplayModeId = 0;
+        appWindow.updateFrameRateSelectionPriorityIfNeeded();
+        // Priority doesn't change.
+        assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+        verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+                appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 64db897..890e4ab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -391,6 +391,33 @@
         assertEquals(null, compatTokens.get(0));
     }
 
+    @Test
+    public void testShouldUseSizeCompatModeOnResizableTask() {
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
+
+        // Make the task root resizable.
+        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+
+        // Create a size compat activity on the same task.
+        final ActivityRecord activity = new ActivityBuilder(mService)
+                .setTask(mTask)
+                .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
+                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+                .build();
+        assertTrue(activity.shouldUseSizeCompatMode());
+
+        // The non-resizable activity should not be size compat because it is on a resizable task
+        // in multi-window mode.
+        mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+        assertFalse(activity.shouldUseSizeCompatMode());
+
+        // The non-resizable activity should not be size compat because the display support
+        // changing windowing mode from fullscreen to freeform.
+        mStack.mDisplayContent.setDisplayWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+        mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+        assertFalse(activity.shouldUseSizeCompatMode());
+    }
+
     /**
      * Setup {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or
      * orientation.
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index f5d08dc..eda1fb8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -250,4 +250,9 @@
         return this;
     }
 
+    @Override
+    public SurfaceControl.Transaction setFrameRateSelectionPriority(SurfaceControl sc,
+            int priority) {
+        return this;
+    }
 }
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 2abcc76..a7ad884 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -28,6 +28,8 @@
 import android.os.SystemProperties;
 
 import java.io.PrintWriter;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
 
 /**
@@ -137,4 +139,12 @@
         }
         return ret;
     }
+
+    /** Wait for latch to trigger */
+    public static void waitUntilReady(CountDownLatch latch, long timeoutMs) {
+        try {
+            latch.await(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException ignored) {
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 8ed4ee5..fee6d3f 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -25,11 +25,12 @@
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.app.ActivityThread;
 import android.app.PendingIntent;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.database.CursorWindow;
 import android.net.Uri;
 import android.os.Build;
@@ -423,7 +424,7 @@
             String destinationAddress, String scAddress, String text,
             PendingIntent sentIntent, PendingIntent deliveryIntent) {
         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
-                true /* persistMessage*/, ActivityThread.currentPackageName());
+                true /* persistMessage*/, null);
     }
 
     /**
@@ -633,7 +634,7 @@
             String destinationAddress, String scAddress, String text,
             PendingIntent sentIntent, PendingIntent deliveryIntent) {
         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
-                false /* persistMessage */, ActivityThread.currentPackageName());
+                false /* persistMessage */, null);
     }
 
     private void sendTextMessageInternal(
@@ -676,7 +677,7 @@
                         ISms iSms = getISmsServiceOrThrow();
                         if (iSms != null) {
                             iSms.sendTextForSubscriberWithOptions(subId,
-                                    ActivityThread.currentPackageName(), destinationAddress,
+                                    null, destinationAddress,
                                     scAddress,
                                     text, sentIntent, deliveryIntent, persistMessage, finalPriority,
                                     expectMore, finalValidity);
@@ -698,7 +699,7 @@
                 ISms iSms = getISmsServiceOrThrow();
                 if (iSms != null) {
                     iSms.sendTextForSubscriberWithOptions(getSubscriptionId(),
-                            ActivityThread.currentPackageName(), destinationAddress,
+                            null, destinationAddress,
                             scAddress,
                             text, sentIntent, deliveryIntent, persistMessage, finalPriority,
                             expectMore, finalValidity);
@@ -920,7 +921,7 @@
             String destinationAddress, String scAddress, ArrayList<String> parts,
             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
-                deliveryIntents, true /* persistMessage*/, ActivityThread.currentPackageName());
+                deliveryIntents, true /* persistMessage*/, null);
     }
 
     /**
@@ -937,8 +938,9 @@
      * subscription.
      * </p>
      *
-     * @param packageName serves as the default package name if
-     * {@link ActivityThread#currentPackageName()} is null.
+     * @param packageName serves as the default package name if the package name that is
+     *        associated with the user id is null.
+     *
      * @hide
      */
     @SystemApi
@@ -948,9 +950,7 @@
             @NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents,
             @Nullable List<PendingIntent> deliveryIntents, @NonNull String packageName) {
         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
-                deliveryIntents, true /* persistMessage*/,
-                ActivityThread.currentPackageName() == null
-                        ? packageName : ActivityThread.currentPackageName());
+                deliveryIntents, true /* persistMessage*/, packageName);
     }
 
     private void sendMultipartTextMessageInternal(
@@ -1051,7 +1051,7 @@
             String destinationAddress, String scAddress, List<String> parts,
             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
-                deliveryIntents, false /* persistMessage*/, ActivityThread.currentPackageName());
+                deliveryIntents, false /* persistMessage*/, null);
     }
 
     /**
@@ -1213,7 +1213,7 @@
                             ISms iSms = getISmsServiceOrThrow();
                             if (iSms != null) {
                                 iSms.sendMultipartTextForSubscriberWithOptions(subId,
-                                        ActivityThread.currentPackageName(), destinationAddress,
+                                        null, destinationAddress,
                                         scAddress, parts, sentIntents, deliveryIntents,
                                         persistMessage, finalPriority, expectMore, finalValidity);
                             }
@@ -1235,7 +1235,7 @@
                     ISms iSms = getISmsServiceOrThrow();
                     if (iSms != null) {
                         iSms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
-                                ActivityThread.currentPackageName(), destinationAddress,
+                                null, destinationAddress,
                                 scAddress, parts, sentIntents, deliveryIntents,
                                 persistMessage, finalPriority, expectMore, finalValidity);
                     }
@@ -1366,7 +1366,7 @@
             public void onSuccess(int subId) {
                 try {
                     ISms iSms = getISmsServiceOrThrow();
-                    iSms.sendDataForSubscriber(subId, ActivityThread.currentPackageName(),
+                    iSms.sendDataForSubscriber(subId, null,
                             destinationAddress, scAddress, destinationPort & 0xFFFF, data,
                             sentIntent, deliveryIntent);
                 } catch (RemoteException e) {
@@ -1492,7 +1492,6 @@
     private void resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult) {
         int subId = getSubscriptionId();
         boolean isSmsSimPickActivityNeeded = false;
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
         try {
             ISms iSms = getISmsService();
             if (iSms != null) {
@@ -1514,14 +1513,14 @@
             return;
         }
         // We need to ask the user pick an appropriate subid for the operation.
-        Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for package "
-                + context.getPackageName());
+        Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for calling"
+                + " package. ");
         try {
             // Create the SMS pick activity and call back once the activity is complete. Can't do
             // it here because we do not have access to the activity context that is performing this
             // operation.
             // Requires that the calling process has the SEND_SMS permission.
-            getITelephony().enqueueSmsPickResult(context.getOpPackageName(),
+            getITelephony().enqueueSmsPickResult(null,
                     new IIntegerConsumer.Stub() {
                         @Override
                         public void accept(int subId) {
@@ -1539,6 +1538,13 @@
         }
     }
 
+    /**
+     * To check the SDK version for SmsManager.sendResolverResult method.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
+    private static final long GET_TARGET_SDK_VERSION_CODE_CHANGE = 145147528L;
+
     private void sendResolverResult(SubscriptionResolverResult resolverResult, int subId,
             boolean pickActivityShown) {
         if (SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -1546,7 +1552,8 @@
             return;
         }
 
-        if (getTargetSdkVersion() <= Build.VERSION_CODES.P && !pickActivityShown) {
+        if (!Compatibility.isChangeEnabled(GET_TARGET_SDK_VERSION_CODE_CHANGE)
+                && !pickActivityShown) {
             // Do not fail, return a success with an INVALID subid for apps targeting P or below
             // that tried to perform an operation and the SMS disambiguation dialog was never shown,
             // as these applications may not have been written to handle the failure case properly.
@@ -1559,19 +1566,6 @@
         }
     }
 
-    private static int getTargetSdkVersion() {
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
-        int targetSdk;
-        try {
-            targetSdk = context.getPackageManager().getApplicationInfo(
-                    context.getOpPackageName(), 0).targetSdkVersion;
-        } catch (PackageManager.NameNotFoundException e) {
-            // Default to old behavior if we can not find this.
-            targetSdk = -1;
-        }
-        return targetSdk;
-    }
-
     private static ITelephony getITelephony() {
         ITelephony binder = ITelephony.Stub.asInterface(
                 TelephonyFrameworkInitializer
@@ -1657,7 +1651,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 success = iSms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
+                        null,
                         status, pdu, smsc);
             }
         } catch (RemoteException ex) {
@@ -1698,7 +1692,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
+                        null,
                         messageIndex, STATUS_ON_ICC_FREE, null /* pdu */);
             }
         } catch (RemoteException ex) {
@@ -1741,7 +1735,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
+                        null,
                         messageIndex, newStatus, pdu);
             }
         } catch (RemoteException ex) {
@@ -1793,7 +1787,7 @@
             if (iSms != null) {
                 records = iSms.getAllMessagesFromIccEfForSubscriber(
                         getSubscriptionId(),
-                        ActivityThread.currentPackageName());
+                        null);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -2617,7 +2611,7 @@
         try {
             ISms iccSms = getISmsServiceOrThrow();
             return iccSms.createAppSpecificSmsToken(getSubscriptionId(),
-                    ActivityThread.currentPackageName(), intent);
+                    null, intent);
 
         } catch (RemoteException ex) {
             ex.rethrowFromSystemServer();
@@ -2737,7 +2731,7 @@
         try {
             ISms iccSms = getISmsServiceOrThrow();
             return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(),
-                    ActivityThread.currentPackageName(), prefixes, intent);
+                    null, prefixes, intent);
 
         } catch (RemoteException ex) {
             ex.rethrowFromSystemServer();
@@ -2828,7 +2822,7 @@
             ISms iccISms = getISmsServiceOrThrow();
             if (iccISms != null) {
                 return iccISms.checkSmsShortCodeDestination(getSubscriptionId(),
-                        ActivityThread.currentPackageName(), null, destAddress, countryIso);
+                        null, null, destAddress, countryIso);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "checkSmsShortCodeDestination() RemoteException", e);
@@ -2864,7 +2858,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 smsc = iSms.getSmscAddressFromIccEfForSubscriber(
-                        getSubscriptionId(), ActivityThread.currentPackageName());
+                        getSubscriptionId(), null);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -2898,7 +2892,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 return iSms.setSmscAddressOnIccEfForSubscriber(
-                        smsc, getSubscriptionId(), ActivityThread.currentPackageName());
+                        smsc, getSubscriptionId(), null);
             }
         } catch (RemoteException ex) {
             // ignore it
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 36f541f..b42ce35 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2232,6 +2232,7 @@
         } else {
             logd("putPhoneIdAndSubIdExtra: no valid subs");
             intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
+            intent.putExtra(EXTRA_SLOT_INDEX, phoneId);
         }
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 13aad7e..56ca8c7 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -37,7 +37,6 @@
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.WorkerThread;
-import android.app.ActivityThread;
 import android.app.PendingIntent;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
@@ -380,8 +379,17 @@
         // effort and get the context from the current activity thread.
         if (mContext != null) {
             return mContext.getOpPackageName();
+        } else {
+            ITelephony telephony = getITelephony();
+            if (telephony == null) return null;
+            try {
+                return telephony.getCurrentPackageName();
+            } catch (RemoteException ex) {
+                return null;
+            } catch (NullPointerException ex) {
+                return null;
+            }
         }
-        return ActivityThread.currentOpPackageName();
     }
 
     private String getFeatureId() {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index cdb95a8..a8e76b9 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2087,6 +2087,11 @@
     int getRadioHalVersion();
 
     /**
+     * Get the current calling package name.
+     */
+    String getCurrentPackageName();
+
+    /**
      * Returns true if the specified type of application (e.g. {@link #APPTYPE_CSIM} is present
      * on the UICC card.
      * @hide
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 091edd4..98e7b4e 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -19,7 +19,10 @@
     static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
     test_suites: ["general-tests"],
     test_config: "RollbackTest.xml",
-    java_resources: [":com.android.apex.apkrollback.test_v2"],
+    java_resources: [
+        ":com.android.apex.apkrollback.test_v2",
+        ":com.android.apex.apkrollback.test_v2Crashing"
+    ],
 }
 
 java_test_host {
@@ -79,4 +82,14 @@
   key: "com.android.apex.apkrollback.test.key",
   apps: ["TestAppAv2"],
   installable: false,
+}
+
+apex {
+  name: "com.android.apex.apkrollback.test_v2Crashing",
+  manifest: "testdata/manifest_v2.json",
+  androidManifest: "testdata/AndroidManifest.xml",
+  file_contexts: ":apex.test-file_contexts",
+  key: "com.android.apex.apkrollback.test.key",
+  apps: ["TestAppACrashingV2"],
+  installable: false,
 }
\ No newline at end of file
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index ce20311..80491cd 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -500,8 +500,9 @@
             APK_IN_APEX_TESTAPEX_NAME, 1, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
     private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
             APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
-    private static final TestApp TEST_APP_A_V2_UNKNOWN = new TestApp("Av2Unknown", TestApp.A, 0,
-            /*isApex*/false, "TestAppAv2.apk");
+    private static final TestApp TEST_APEX_WITH_APK_V2_CRASHING = new TestApp(
+            "TestApexWithApkV2Crashing", APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true,
+            APK_IN_APEX_TESTAPEX_NAME + "_v2Crashing.apex");
 
     @Test
     public void testRollbackApexWithApk_Phase1() throws Exception {
@@ -523,7 +524,7 @@
         assertThat(available).isStaged();
         assertThat(available).packagesContainsExactly(
                 Rollback.from(TEST_APEX_WITH_APK_V2).to(TEST_APEX_WITH_APK_V1),
-                Rollback.from(TEST_APP_A_V2_UNKNOWN).to(TestApp.A1));
+                Rollback.from(TestApp.A, 0).to(TestApp.A1));
 
         RollbackUtils.rollback(available.getRollbackId(), TEST_APEX_WITH_APK_V2);
         RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
@@ -531,7 +532,7 @@
         assertThat(committed).isStaged();
         assertThat(committed).packagesContainsExactly(
                 Rollback.from(TEST_APEX_WITH_APK_V2).to(TEST_APEX_WITH_APK_V1),
-                Rollback.from(TEST_APP_A_V2_UNKNOWN).to(TestApp.A1));
+                Rollback.from(TestApp.A, 0).to(TestApp.A1));
         assertThat(committed).causePackagesContainsExactly(TEST_APEX_WITH_APK_V2);
         assertThat(committed.getCommittedSessionId()).isNotEqualTo(-1);
 
@@ -548,6 +549,41 @@
         InstallUtils.processUserData(TestApp.A);
     }
 
+    /**
+     * Installs an apex with an apk that can crash.
+     */
+    @Test
+    public void testRollbackApexWithApkCrashing_Phase1() throws Exception {
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        int sessionId = Install.single(TEST_APEX_WITH_APK_V2_CRASHING).setStaged()
+                .setEnableRollback().commit();
+        InstallUtils.waitForSessionReady(sessionId);
+    }
+
+    /**
+     * Verifies rollback has been enabled successfully. Then makes TestApp.A crash.
+     */
+    @Test
+    public void testRollbackApexWithApkCrashing_Phase2() throws Exception {
+        assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+
+        RollbackInfo available = RollbackUtils.getAvailableRollback(APK_IN_APEX_TESTAPEX_NAME);
+        assertThat(available).isStaged();
+        assertThat(available).packagesContainsExactly(
+                Rollback.from(TEST_APEX_WITH_APK_V2).to(TEST_APEX_WITH_APK_V1),
+                Rollback.from(TestApp.A, 0).to(TestApp.A1));
+
+        // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
+        RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
+    }
+
+    @Test
+    public void testRollbackApexWithApkCrashing_Phase3() throws Exception {
+        assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(1);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+    }
+
     private static void runShellCommand(String cmd) {
         ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .executeShellCommand(cmd);
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 181e29a..672cbb0 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -261,6 +261,34 @@
         runPhase("testRollbackApexWithApk_Phase3");
     }
 
+    /**
+     * Tests that RollbackPackageHealthObserver is observing apk-in-apex.
+     */
+    @Test
+    public void testRollbackApexWithApkCrashing() throws Exception {
+        getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
+        final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
+        final File apex = buildHelper.getTestFile(fileName);
+        if (!getDevice().isAdbRoot()) {
+            getDevice().enableAdbRoot();
+        }
+        getDevice().remountSystemWritable();
+        assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
+        getDevice().reboot();
+
+        // Install an apex with apk that crashes
+        runPhase("testRollbackApexWithApkCrashing_Phase1");
+        getDevice().reboot();
+        // Verify apex was installed and then crash the apk
+        runPhase("testRollbackApexWithApkCrashing_Phase2");
+        // Wait for crash to trigger rollback
+        assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+        getDevice().waitForDeviceAvailable();
+        // Verify rollback occurred due to crash of apk-in-apex
+        runPhase("testRollbackApexWithApkCrashing_Phase3");
+    }
+
     private void crashProcess(String processName, int numberOfCrashes) throws Exception {
         String pid = "";
         String lastPid = "invalid";
diff --git a/tests/WindowInsetsTests/Android.bp b/tests/WindowInsetsTests/Android.bp
new file mode 100644
index 0000000..12395e7
--- /dev/null
+++ b/tests/WindowInsetsTests/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "WindowInsetsTests",
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+    certificate: "platform",
+    platform_apis: true,
+}
+
diff --git a/tests/WindowInsetsTests/AndroidManifest.xml b/tests/WindowInsetsTests/AndroidManifest.xml
new file mode 100644
index 0000000..8d33f70
--- /dev/null
+++ b/tests/WindowInsetsTests/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (018C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.test.windowinsetstests">
+
+    <application android:label="@string/activity_title">
+        <activity android:name=".WindowInsetsActivity"
+            android:theme="@android:style/Theme.Material"
+            android:windowSoftInputMode="adjustResize">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml b/tests/WindowInsetsTests/res/layout/window_inset_activity.xml
new file mode 100644
index 0000000..38e0029
--- /dev/null
+++ b/tests/WindowInsetsTests/res/layout/window_inset_activity.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:id="@+id/root">
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:text="Hello insets" />
+
+</LinearLayout>
+
diff --git a/tests/WindowInsetsTests/res/values/strings.xml b/tests/WindowInsetsTests/res/values/strings.xml
new file mode 100644
index 0000000..242823d
--- /dev/null
+++ b/tests/WindowInsetsTests/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <string name="activity_title">Window Insets Tests</string>
+</resources>
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
new file mode 100644
index 0000000..b8b2de5
--- /dev/null
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.google.android.test.windowinsetstests;
+
+import android.animation.ObjectAnimator;
+import android.animation.TypeEvaluator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.graphics.Insets;
+import android.os.Bundle;
+import android.util.Property;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowInsets.Type;
+import android.view.WindowInsetsAnimationCallback;
+import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
+import android.view.WindowInsetsAnimationControlListener;
+import android.view.WindowInsetsAnimationController;
+
+import com.google.android.test.windowinsetstests.R;
+
+public class WindowInsetsActivity extends Activity {
+
+    private View mRoot;
+    private View mButton;
+
+    private static class InsetsProperty extends Property<WindowInsetsAnimationController, Insets> {
+
+        private final View mViewToAnimate;
+        private final Insets mShowingInsets;
+
+        public InsetsProperty(View viewToAnimate, Insets showingInsets) {
+            super(Insets.class, "Insets");
+            mViewToAnimate = viewToAnimate;
+            mShowingInsets = showingInsets;
+        }
+
+        @Override
+        public Insets get(WindowInsetsAnimationController object) {
+            return object.getCurrentInsets();
+        }
+
+        @Override
+        public void set(WindowInsetsAnimationController object, Insets value) {
+            object.setInsetsAndAlpha(value, 1.0f, 0.5f);
+            if (mShowingInsets.bottom != 0) {
+                mViewToAnimate.setTranslationY(mShowingInsets.bottom - value.bottom);
+            } else if (mShowingInsets.right != 0) {
+                mViewToAnimate.setTranslationX(mShowingInsets.right - value.right);
+            } else if (mShowingInsets.left != 0) {
+                mViewToAnimate.setTranslationX(value.left - mShowingInsets.left);
+            }
+        }
+    };
+
+    float showY;
+    float hideY;
+    InsetsAnimation imeAnim;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.window_inset_activity);
+        mRoot = findViewById(R.id.root);
+        mButton = findViewById(R.id.button);
+        mButton.setOnClickListener(v -> {
+            if (!v.getRootWindowInsets().isVisible(Type.ime())) {
+                v.getWindowInsetsController().show(Type.ime());
+            } else {
+                v.getWindowInsetsController().hide(Type.ime());
+            }
+        });
+        mRoot.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
+            if (imeAnim == null) {
+                return;
+            }
+            if (mRoot.getRootWindowInsets().isVisible(Type.ime())) {
+                showY = mButton.getTop();
+            } else {
+                hideY = mButton.getTop();
+            }
+        });
+        mRoot.setWindowInsetsAnimationCallback(new WindowInsetsAnimationCallback() {
+
+            @Override
+            public void onPrepare(InsetsAnimation animation) {
+                if ((animation.getTypeMask() & Type.ime()) != 0) {
+                    imeAnim = animation;
+                }
+                if (mRoot.getRootWindowInsets().isVisible(Type.ime())) {
+                    showY = mButton.getTop();
+                } else {
+                    hideY = mButton.getTop();
+                }
+            }
+
+            @Override
+            public WindowInsets onProgress(WindowInsets insets) {
+                mButton.setY(hideY + (showY - hideY) * imeAnim.getInterpolatedFraction());
+                return insets;
+            }
+
+            @Override
+            public AnimationBounds onStart(InsetsAnimation animation,
+                    AnimationBounds bounds) {
+                return bounds;
+            }
+
+            @Override
+            public void onFinish(InsetsAnimation animation) {
+                imeAnim = null;
+            }
+        });
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        TypeEvaluator<Insets> evaluator = (fraction, startValue, endValue) -> Insets.of(
+                (int)(startValue.left + fraction * (endValue.left - startValue.left)),
+                (int)(startValue.top + fraction * (endValue.top - startValue.top)),
+                (int)(startValue.right + fraction * (endValue.right - startValue.right)),
+                (int)(startValue.bottom + fraction * (endValue.bottom - startValue.bottom)));
+
+        WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() {
+            @Override
+            public void onReady(WindowInsetsAnimationController controller, int types) {
+                ObjectAnimator animator = ObjectAnimator.ofObject(controller,
+                        new InsetsProperty(findViewById(R.id.button),
+                                controller.getShownStateInsets()),
+                        evaluator, controller.getShownStateInsets(),
+                        controller.getHiddenStateInsets());
+                animator.setRepeatCount(ValueAnimator.INFINITE);
+                animator.setRepeatMode(ValueAnimator.REVERSE);
+                animator.start();
+            }
+
+            @Override
+            public void onCancelled() {
+
+            }
+        };
+    }
+}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 99a26dc..3c55237 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -53,36 +53,38 @@
 
         val executor = newThreadPool()
 
-        command.javaSourceArgs.map { path ->
-            executor.submitCallable {
-                val transformer = SourceTransformer(command.protoLogImplClassNameArg,
-                        command.protoLogCacheClassNameArg, processor)
-                val file = File(path)
-                val text = injector.readText(file)
-                val outSrc = try {
-                    val code = tryParse(text, path)
-                    if (containsProtoLogText(text, command.protoLogClassNameArg)) {
-                        transformer.processClass(text, path, packagePath(file, code), code)
-                    } else {
+        try {
+            command.javaSourceArgs.map { path ->
+                executor.submitCallable {
+                    val transformer = SourceTransformer(command.protoLogImplClassNameArg,
+                            command.protoLogCacheClassNameArg, processor)
+                    val file = File(path)
+                    val text = injector.readText(file)
+                    val outSrc = try {
+                        val code = tryParse(text, path)
+                        if (containsProtoLogText(text, command.protoLogClassNameArg)) {
+                            transformer.processClass(text, path, packagePath(file, code), code)
+                        } else {
+                            text
+                        }
+                    } catch (ex: ParsingException) {
+                        // If we cannot parse this file, skip it (and log why). Compilation will
+                        // fail in a subsequent build step.
+                        injector.reportParseError(ex)
                         text
                     }
-                } catch (ex: ParsingException) {
-                    // If we cannot parse this file, skip it (and log why). Compilation will fail
-                    // in a subsequent build step.
-                    injector.reportParseError(ex)
-                    text
+                    path to outSrc
                 }
-                path to outSrc
+            }.map { future ->
+                val (path, outSrc) = future.get()
+                outJar.putNextEntry(ZipEntry(path))
+                outJar.write(outSrc.toByteArray())
+                outJar.closeEntry()
             }
-        }.map { future ->
-            val (path, outSrc) = future.get()
-            outJar.putNextEntry(ZipEntry(path))
-            outJar.write(outSrc.toByteArray())
-            outJar.closeEntry()
+        } finally {
+            executor.shutdown()
         }
 
-        executor.shutdown()
-
         val cacheSplit = command.protoLogCacheClassNameArg.split(".")
         val cacheName = cacheSplit.last()
         val cachePackage = cacheSplit.dropLast(1).joinToString(".")
@@ -153,30 +155,32 @@
 
         val executor = newThreadPool()
 
-        command.javaSourceArgs.map { path ->
-            executor.submitCallable {
-                val file = File(path)
-                val text = injector.readText(file)
-                if (containsProtoLogText(text, command.protoLogClassNameArg)) {
-                    try {
-                        val code = tryParse(text, path)
-                        builder.findLogCalls(code, path, packagePath(file, code))
-                    } catch (ex: ParsingException) {
-                        // If we cannot parse this file, skip it (and log why). Compilation will fail
-                        // in a subsequent build step.
-                        injector.reportParseError(ex)
+        try {
+            command.javaSourceArgs.map { path ->
+                executor.submitCallable {
+                    val file = File(path)
+                    val text = injector.readText(file)
+                    if (containsProtoLogText(text, command.protoLogClassNameArg)) {
+                        try {
+                            val code = tryParse(text, path)
+                            builder.findLogCalls(code, path, packagePath(file, code))
+                        } catch (ex: ParsingException) {
+                            // If we cannot parse this file, skip it (and log why). Compilation will
+                            // fail in a subsequent build step.
+                            injector.reportParseError(ex)
+                            null
+                        }
+                    } else {
                         null
                     }
-                } else {
-                    null
                 }
+            }.forEach { future ->
+                builder.addLogCalls(future.get() ?: return@forEach)
             }
-        }.forEach { future ->
-            builder.addLogCalls(future.get() ?: return@forEach)
+        } finally {
+            executor.shutdown()
         }
 
-        executor.shutdown()
-
         val out = injector.fileOutputStream(command.viewerConfigJsonArg)
         out.write(builder.build().toByteArray())
         out.close()
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a9621fc..b2fbb40 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -856,18 +856,6 @@
 
     /**
      * @hide
-     * For debug: date at which the config was last updated
-     */
-    public String updateTime;
-
-    /**
-     * @hide
-     * For debug: date at which the config was last updated
-     */
-    public String creationTime;
-
-    /**
-     * @hide
      * The WiFi configuration is considered to have no internet access for purpose of autojoining
      * if there has been a report of it having no internet access, and, it never have had
      * internet access in the past.
@@ -1493,12 +1481,6 @@
         private String mConnectChoice;
 
         /**
-         * The system timestamp when we records the connectChoice. This value is obtained from
-         * System.currentTimeMillis
-         */
-        private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
-
-        /**
          * Used to cache the temporary candidate during the network selection procedure. It will be
          * kept updating once a new scan result has a higher score than current one
          */
@@ -1601,25 +1583,6 @@
             mConnectChoice = newConnectChoice;
         }
 
-        /**
-         * get the timeStamp when user select a choice over this configuration
-         * @return returns when current connectChoice is set (time from System.currentTimeMillis)
-         * @hide
-         */
-        public long getConnectChoiceTimestamp() {
-            return mConnectChoiceTimestamp;
-        }
-
-        /**
-         * set the timeStamp when user select a choice over this configuration
-         * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
-         *        be obtained from System.currentTimeMillis
-         * @hide
-         */
-        public void setConnectChoiceTimestamp(long timeStamp) {
-            mConnectChoiceTimestamp = timeStamp;
-        }
-
         /** Get the current Quality network selection status as a String (for debugging). */
         @NonNull
         public String getNetworkStatusString() {
@@ -1902,7 +1865,6 @@
             setCandidate(source.getCandidate());
             setCandidateScore(source.getCandidateScore());
             setConnectChoice(source.getConnectChoice());
-            setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
             setHasEverConnected(source.getHasEverConnected());
         }
 
@@ -1919,7 +1881,6 @@
             if (getConnectChoice() != null) {
                 dest.writeInt(CONNECT_CHOICE_EXISTS);
                 dest.writeString(getConnectChoice());
-                dest.writeLong(getConnectChoiceTimestamp());
             } else {
                 dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
             }
@@ -1938,10 +1899,8 @@
             setNetworkSelectionBSSID(in.readString());
             if (in.readInt() == CONNECT_CHOICE_EXISTS) {
                 setConnectChoice(in.readString());
-                setConnectChoiceTimestamp(in.readLong());
             } else {
                 setConnectChoice(null);
-                setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
             }
             setHasEverConnected(in.readInt() != 0);
         }
@@ -2165,9 +2124,6 @@
         }
         if (mNetworkSelectionStatus.getConnectChoice() != null) {
             sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
-            sbuf.append(" connect choice set time: ")
-                    .append(logTimeOfDay(
-                            mNetworkSelectionStatus.getConnectChoiceTimestamp()));
         }
         sbuf.append(" hasEverConnected: ")
                 .append(mNetworkSelectionStatus.getHasEverConnected()).append("\n");
@@ -2179,12 +2135,6 @@
             sbuf.append(" numNoInternetAccessReports ");
             sbuf.append(this.numNoInternetAccessReports).append("\n");
         }
-        if (this.updateTime != null) {
-            sbuf.append(" update ").append(this.updateTime).append("\n");
-        }
-        if (this.creationTime != null) {
-            sbuf.append(" creation ").append(this.creationTime).append("\n");
-        }
         if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
         if (this.ephemeral) sbuf.append(" ephemeral");
         if (this.osu) sbuf.append(" osu");
@@ -2731,8 +2681,6 @@
             allowAutojoin = source.allowAutojoin;
             numNoInternetAccessReports = source.numNoInternetAccessReports;
             noInternetAccessExpected = source.noInternetAccessExpected;
-            creationTime = source.creationTime;
-            updateTime = source.updateTime;
             shared = source.shared;
             recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus());
             mRandomizedMacAddress = source.mRandomizedMacAddress;