Merge "Add new IncidentManager.requestAuthorization method that takes an executor." into qt-dev
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index abcccf8..d69eced 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -299,6 +299,10 @@
         CarPowerStateChanged car_power_state_changed = 203;
         GarageModeInfo garage_mode_info = 204;
         TestAtomReported test_atom_reported = 205 [(log_from_module) = "cts"];
+        ContentCaptureCallerMismatchReported content_capture_caller_mismatch_reported = 206;
+        ContentCaptureServiceEvents content_capture_service_events = 207;
+        ContentCaptureSessionEvents content_capture_session_events = 208;
+        ContentCaptureFlushed content_capture_flushed = 209;
     }
 
     // Pulled events will start at field 10000.
@@ -4831,6 +4835,95 @@
 }
 
 /**
+ * Logs information about mismatched caller for content capture.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/android/service/contentcapture/ContentCaptureService.java
+ */
+message ContentCaptureCallerMismatchReported {
+    optional string intended_package = 1;
+    optional string calling_package = 2;
+}
+
+/**
+ * Logs information about content capture service events.
+ *
+ * Logged from:
+ *   frameworks/base/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
+ */
+message ContentCaptureServiceEvents {
+    // The type of event.
+    enum Event {
+        UNKNOWN = 0;
+        ON_CONNECTED = 1;
+        ON_DISCONNECTED = 2;
+        SET_WHITELIST = 3;
+        SET_DISABLED = 4;
+        ON_USER_DATA_REMOVED = 5;
+    }
+    optional Event event = 1;
+    // component/package of content capture service.
+    optional string service_info = 2;
+    // component/package of target.
+    // it's a concatenated list of component/package for SET_WHITELIST event
+    // separated by " ".
+    optional string target_info = 3;
+}
+
+/**
+ * Logs information about content capture session events.
+ *
+ * Logged from:
+ *   frameworks/base/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
+ */
+message ContentCaptureSessionEvents {
+    // The type of event.
+    enum Event {
+        UNKNOWN = 0;
+        ON_SESSION_STARTED = 1;
+        ON_SESSION_FINISHED = 2;
+        SESSION_NOT_CREATED = 3;
+    }
+    optional int32 session_id = 1;
+    optional Event event = 2;
+    // (n/a on session finished)
+    optional int32 state_flags = 3;
+    // component/package of content capture service.
+    optional string service_info = 4;
+    // component/package of app.
+    // (n/a on session finished)
+    optional string app_info = 5;
+    optional bool is_child_session = 6;
+}
+
+/**
+ * Logs information about session being flushed.
+ *
+ * Logged from:
+ *   frameworks/base/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
+ */
+message ContentCaptureFlushed {
+    optional int32 session_id = 1;
+    // component/package of content capture service.
+    optional string service_info = 2;
+    // component/package of app.
+    optional string app_info = 3;
+    // session start/finish events
+    optional int32 child_session_started = 4;
+    optional int32 child_session_finished = 5;
+    // count of view events.
+    optional int32 view_appeared_count = 6;
+    optional int32 view_disappeared_count = 7;
+    optional int32 view_text_changed_count = 8;
+
+    // Flush stats.
+    optional int32 max_events = 9;
+    optional int32 idle_flush_freq = 10;
+    optional int32 text_flush_freq = 11;
+    optional int32 flush_reason = 12;
+}
+
+/**
  * Pulls on-device BatteryStats power use calculations for the overall device.
  */
 message DeviceCalculatedPowerUse {
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 4e419b6..a2fd9d4 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -330,6 +330,8 @@
 
   // Class name of the incident report receiver.
   optional string receiver_cls = 4;
+
+  optional string alert_description = 5;
 }
 
 message PerfettoDetails {
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
index ff1cb4f..f2c6f1a 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -36,12 +36,14 @@
 using android::util::ProtoOutputStream;
 using std::vector;
 
-using util::FIELD_TYPE_MESSAGE;
 using util::FIELD_TYPE_INT32;
 using util::FIELD_TYPE_INT64;
+using util::FIELD_TYPE_MESSAGE;
+using util::FIELD_TYPE_STRING;
 
 // field ids in IncidentHeaderProto
 const int FIELD_ID_ALERT_ID = 1;
+const int FIELD_ID_REASON = 2;
 const int FIELD_ID_CONFIG_KEY = 3;
 const int FIELD_ID_CONFIG_KEY_UID = 1;
 const int FIELD_ID_CONFIG_KEY_ID = 2;
@@ -57,9 +59,11 @@
 
 namespace {
 void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensionKey& dimensionKey,
-                  int64_t metricValue, const ConfigKey& configKey, vector<uint8_t>* protoData) {
+                  int64_t metricValue, const ConfigKey& configKey, const string& reason,
+                  vector<uint8_t>* protoData) {
     ProtoOutputStream headerProto;
     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_ID, (long long)rule_id);
+    headerProto.write(FIELD_TYPE_STRING | FIELD_ID_REASON, reason);
     uint64_t token =
             headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
     headerProto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_KEY_UID, configKey.GetUid());
@@ -142,7 +146,8 @@
     IncidentReportArgs incidentReport;
 
     vector<uint8_t> protoData;
-    getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey, &protoData);
+    getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey,
+                 config.alert_description(), &protoData);
     incidentReport.addHeader(protoData);
 
     for (int i = 0; i < config.section_size(); i++) {
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 19f4335..9727621 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -636,6 +636,11 @@
         public int hashCode() {
             return Objects.hash(mEvent, mId);
         }
+
+        /** @hide */
+        public boolean eventEquals(SecurityEvent other) {
+            return other != null && mEvent.equals(other.mEvent);
+        }
     }
     /**
      * Retrieve all security logs and return immediately.
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 7fa4360..749a011 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -281,20 +281,13 @@
 
     /**
      * Gets application usage stats for the given time range, aggregated by the specified interval.
-     * <p>The returned list will contain a {@link UsageStats} object for each package that
-     * has data for an interval that is a subset of the time range given. To illustrate:</p>
-     * <pre>
-     * intervalType = INTERVAL_YEARLY
-     * beginTime = 2013
-     * endTime = 2015 (exclusive)
      *
-     * Results:
-     * 2013 - com.example.alpha
-     * 2013 - com.example.beta
-     * 2014 - com.example.alpha
-     * 2014 - com.example.beta
-     * 2014 - com.example.charlie
-     * </pre>
+     * <p>
+     * The returned list will contain one or more {@link UsageStats} objects for each package, with
+     * usage data that covers at least the given time range.
+     * Note: The begin and end times of the time range may be expanded to the nearest whole interval
+     * period.
+     * </p>
      *
      * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
      *
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 71242fb..7cdd268 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -820,6 +820,7 @@
     private String setCallingPackage(String callingPackage) {
         final String original = mCallingPackage.get();
         mCallingPackage.set(callingPackage);
+        onCallingPackageChanged();
         return original;
     }
 
@@ -845,6 +846,15 @@
         return pkg;
     }
 
+    /** {@hide} */
+    public final @Nullable String getCallingPackageUnchecked() {
+        return mCallingPackage.get();
+    }
+
+    /** {@hide} */
+    public void onCallingPackageChanged() {
+    }
+
     /**
      * Opaque token representing the identity of an incoming IPC.
      */
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index b0142ea..f662b61 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -98,7 +98,7 @@
      * identifiers, while removable cameras have a unique identifier for each
      * individual device, even if they are the same model.</p>
      *
-     * <p>This list doesn't contain physical cameras that can only used as part of a logical
+     * <p>This list doesn't contain physical cameras that can only be used as part of a logical
      * multi-camera device.</p>
      *
      * @return The list of currently connected camera devices.
@@ -263,7 +263,7 @@
      * immutable for a given camera.</p>
      *
      * <p>From API level 29, this function can also be used to query the capabilities of physical
-     * cameras that can only be used as part of logical multi-camera. These cameras cannot not be
+     * cameras that can only be used as part of logical multi-camera. These cameras cannot be
      * opened directly via {@link #openCamera}</p>
      *
      * @param cameraId The id of the camera device to query. This could be either a standalone
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 4ac4850..22ce39d 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -917,8 +917,17 @@
      * @see #getDocumentId(Uri)
      */
     public static Uri buildDocumentUri(String authority, String documentId) {
+        return getBaseDocumentUriBuilder(authority).appendPath(documentId).build();
+    }
+
+    /** {@hide} */
+    public static Uri buildBaseDocumentUri(String authority) {
+        return getBaseDocumentUriBuilder(authority).build();
+    }
+
+    private static Uri.Builder getBaseDocumentUriBuilder(String authority) {
         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
-                .authority(authority).appendPath(PATH_DOCUMENT).appendPath(documentId).build();
+            .authority(authority).appendPath(PATH_DOCUMENT);
     }
 
     /**
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 02ce873..08d9733 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -29,6 +29,7 @@
 import android.annotation.TestApi;
 import android.app.Service;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.os.Binder;
@@ -40,6 +41,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseIntArray;
+import android.util.StatsLog;
 import android.view.contentcapture.ContentCaptureCondition;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureEvent;
@@ -114,6 +116,9 @@
     private Handler mHandler;
     private IContentCaptureServiceCallback mCallback;
 
+    private long mCallerMismatchTimeout = 1000;
+    private long mLastCallerMismatchLog;
+
     /**
      * Binder that receives calls from the system server.
      */
@@ -176,9 +181,10 @@
             new IContentCaptureDirectManager.Stub() {
 
         @Override
-        public void sendEvents(@SuppressWarnings("rawtypes") ParceledListSlice events) {
+        public void sendEvents(@SuppressWarnings("rawtypes") ParceledListSlice events, int reason,
+                ContentCaptureOptions options) {
             mHandler.sendMessage(obtainMessage(ContentCaptureService::handleSendEvents,
-                            ContentCaptureService.this, Binder.getCallingUid(), events));
+                    ContentCaptureService.this, Binder.getCallingUid(), events, reason, options));
         }
     };
 
@@ -424,14 +430,23 @@
     }
 
     private void handleSendEvents(int uid,
-            @NonNull ParceledListSlice<ContentCaptureEvent> parceledEvents) {
+            @NonNull ParceledListSlice<ContentCaptureEvent> parceledEvents, int reason,
+            @Nullable ContentCaptureOptions options) {
+        final List<ContentCaptureEvent> events = parceledEvents.getList();
+        if (events.isEmpty()) {
+            Log.w(TAG, "handleSendEvents() received empty list of events");
+            return;
+        }
+
+        // Metrics.
+        final FlushMetrics metrics = new FlushMetrics();
+        ComponentName activityComponent = null;
 
         // Most events belong to the same session, so we can keep a reference to the last one
         // to avoid creating too many ContentCaptureSessionId objects
         int lastSessionId = NO_SESSION_ID;
         ContentCaptureSessionId sessionId = null;
 
-        final List<ContentCaptureEvent> events = parceledEvents.getList();
         for (int i = 0; i < events.size(); i++) {
             final ContentCaptureEvent event = events.get(i);
             if (!handleIsRightCallerFor(event, uid)) continue;
@@ -439,22 +454,44 @@
             if (sessionIdInt != lastSessionId) {
                 sessionId = new ContentCaptureSessionId(sessionIdInt);
                 lastSessionId = sessionIdInt;
+                if (i != 0) {
+                    writeFlushMetrics(lastSessionId, activityComponent, metrics, options, reason);
+                    metrics.reset();
+                }
+            }
+            final ContentCaptureContext clientContext = event.getContentCaptureContext();
+            if (activityComponent == null && clientContext != null) {
+                activityComponent = clientContext.getActivityComponent();
             }
             switch (event.getType()) {
                 case ContentCaptureEvent.TYPE_SESSION_STARTED:
-                    final ContentCaptureContext clientContext = event.getContentCaptureContext();
                     clientContext.setParentSessionId(event.getParentSessionId());
                     mSessionUids.put(sessionIdInt, uid);
                     onCreateContentCaptureSession(clientContext, sessionId);
+                    metrics.sessionStarted++;
                     break;
                 case ContentCaptureEvent.TYPE_SESSION_FINISHED:
                     mSessionUids.delete(sessionIdInt);
                     onDestroyContentCaptureSession(sessionId);
+                    metrics.sessionFinished++;
+                    break;
+                case ContentCaptureEvent.TYPE_VIEW_APPEARED:
+                    onContentCaptureEvent(sessionId, event);
+                    metrics.viewAppearedCount++;
+                    break;
+                case ContentCaptureEvent.TYPE_VIEW_DISAPPEARED:
+                    onContentCaptureEvent(sessionId, event);
+                    metrics.viewDisappearedCount++;
+                    break;
+                case ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED:
+                    onContentCaptureEvent(sessionId, event);
+                    metrics.viewTextChangedCount++;
                     break;
                 default:
                     onContentCaptureEvent(sessionId, event);
             }
         }
+        writeFlushMetrics(lastSessionId, activityComponent, metrics, options, reason);
     }
 
     private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) {
@@ -499,7 +536,13 @@
         if (rightUid != uid) {
             Log.e(TAG, "invalid call from UID " + uid + ": session " + sessionId + " belongs to "
                     + rightUid);
-            //TODO(b/111276913): log metrics as this could be a malicious app forging a sessionId
+            long now = System.currentTimeMillis();
+            if (now - mLastCallerMismatchLog > mCallerMismatchTimeout) {
+                StatsLog.write(StatsLog.CONTENT_CAPTURE_CALLER_MISMATCH_REPORTED,
+                        getPackageManager().getNameForUid(rightUid),
+                        getPackageManager().getNameForUid(uid));
+                mLastCallerMismatchLog = now;
+            }
             return false;
         }
         return true;
@@ -530,4 +573,22 @@
             Slog.w(TAG, "Error async reporting result to client: " + e);
         }
     }
+
+    /**
+     * Logs the metrics for content capture events flushing.
+     */
+    private void writeFlushMetrics(int sessionId, @Nullable ComponentName app,
+            @NonNull FlushMetrics flushMetrics, @Nullable ContentCaptureOptions options,
+            int flushReason) {
+        if (mCallback == null) {
+            Log.w(TAG, "writeSessionFlush(): no server callback");
+            return;
+        }
+
+        try {
+            mCallback.writeSessionFlush(sessionId, app, flushMetrics, options, flushReason);
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to write flush metrics: " + e);
+        }
+    }
 }
diff --git a/core/java/android/service/contentcapture/FlushMetrics.aidl b/core/java/android/service/contentcapture/FlushMetrics.aidl
new file mode 100644
index 0000000..d0b935f
--- /dev/null
+++ b/core/java/android/service/contentcapture/FlushMetrics.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.contentcapture;
+
+/* @hide */
+parcelable FlushMetrics;
diff --git a/core/java/android/service/contentcapture/FlushMetrics.java b/core/java/android/service/contentcapture/FlushMetrics.java
new file mode 100644
index 0000000..01f3a12
--- /dev/null
+++ b/core/java/android/service/contentcapture/FlushMetrics.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.contentcapture;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Holds metrics for content capture events flushing.
+ *
+ * @hide
+ */
+public final class FlushMetrics implements Parcelable {
+    public int viewAppearedCount;
+    public int viewDisappearedCount;
+    public int viewTextChangedCount;
+    public int sessionStarted;
+    public int sessionFinished;
+
+    /**
+     * Resets all flush metrics.
+     */
+    public void reset() {
+        viewAppearedCount = 0;
+        viewDisappearedCount = 0;
+        viewTextChangedCount = 0;
+        sessionStarted = 0;
+        sessionFinished = 0;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(sessionStarted);
+        out.writeInt(sessionFinished);
+        out.writeInt(viewAppearedCount);
+        out.writeInt(viewDisappearedCount);
+        out.writeInt(viewTextChangedCount);
+    }
+
+    @NonNull
+    public static final Creator<FlushMetrics> CREATOR = new Creator<FlushMetrics>() {
+        @NonNull
+        @Override
+        public FlushMetrics createFromParcel(Parcel in) {
+            final FlushMetrics flushMetrics = new FlushMetrics();
+            flushMetrics.sessionStarted = in.readInt();
+            flushMetrics.sessionFinished = in.readInt();
+            flushMetrics.viewAppearedCount = in.readInt();
+            flushMetrics.viewDisappearedCount = in.readInt();
+            flushMetrics.viewTextChangedCount = in.readInt();
+            return flushMetrics;
+        }
+
+        @Override
+        public FlushMetrics[] newArray(int size) {
+            return new FlushMetrics[size];
+        }
+    };
+}
diff --git a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
index 0550ad3..ea6e76b 100644
--- a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
@@ -18,6 +18,8 @@
 
 import android.content.ComponentName;
 import android.view.contentcapture.ContentCaptureCondition;
+import android.service.contentcapture.FlushMetrics;
+import android.content.ContentCaptureOptions;
 
 import java.util.List;
 
@@ -30,4 +32,8 @@
     void setContentCaptureWhitelist(in List<String> packages, in List<ComponentName> activities);
     void setContentCaptureConditions(String packageName, in List<ContentCaptureCondition> conditions);
     void disableSelf();
- }
+
+    // Logs aggregated content capture flush metrics to Statsd
+    void writeSessionFlush(int sessionId, in ComponentName app, in FlushMetrics flushMetrics,
+            in ContentCaptureOptions options, int flushReason);
+}
diff --git a/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl b/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl
index 8d8117b..959bf13 100644
--- a/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl
@@ -18,6 +18,7 @@
 
 import android.content.pm.ParceledListSlice;
 import android.view.contentcapture.ContentCaptureEvent;
+import android.content.ContentCaptureOptions;
 
 /**
   * Interface between an app (ContentCaptureManager / ContentCaptureSession) and the app providing
@@ -26,5 +27,6 @@
   * @hide
   */
 oneway interface IContentCaptureDirectManager {
-    void sendEvents(in ParceledListSlice events);
+    // reason and options are used only for metrics logging.
+    void sendEvents(in ParceledListSlice events, int reason, in ContentCaptureOptions options);
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 7241664..c5a5f73 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -498,7 +498,7 @@
             }
 
             final ParceledListSlice<ContentCaptureEvent> events = clearEvents();
-            mDirectServiceInterface.sendEvents(events);
+            mDirectServiceInterface.sendEvents(events, reason, mManager.mOptions);
         } catch (RemoteException e) {
             Log.w(TAG, "Error sending " + numberEvents + " for " + getDebugState()
                     + ": " + e);
diff --git a/core/java/com/android/internal/os/ZygoteConfig.java b/core/java/com/android/internal/os/ZygoteConfig.java
index c6af8c2..6ebcae1 100644
--- a/core/java/com/android/internal/os/ZygoteConfig.java
+++ b/core/java/com/android/internal/os/ZygoteConfig.java
@@ -34,4 +34,7 @@
 
     /** The minimum number of processes to keep in the USAP pool */
     public static final String USAP_POOL_SIZE_MIN = "usap_pool_size_min";
+
+    /** The number of milliseconds to delay before refilling the USAP pool */
+    public static final String USAP_POOL_REFILL_DELAY_MS = "usap_pool_refill_delay_ms";
 }
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 7eed9b1..492bc94 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -66,11 +66,8 @@
     /** The default value used for the USAP_POOL_SIZE_MIN device property */
     private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1";
 
-    /**
-     * Number of milliseconds to delay before refilling the pool if it hasn't reached its
-     * minimum value.
-     */
-    private static final int USAP_REFILL_DELAY_MS = 3000;
+    /** The default value used for the USAP_REFILL_DELAY_MS device property */
+    private static final String USAP_POOL_REFILL_DELAY_MS_DEFAULT = "3000";
 
     /** The "not a timestamp" value for the refill delay timestamp mechanism. */
     private static final int INVALID_TIMESTAMP = -1;
@@ -140,6 +137,12 @@
      */
     private int mUsapPoolRefillThreshold = 0;
 
+    /**
+     * Number of milliseconds to delay before refilling the pool if it hasn't reached its
+     * minimum value.
+     */
+    private int mUsapPoolRefillDelayMs = -1;
+
     private enum UsapPoolRefillAction {
         DELAYED,
         IMMEDIATE,
@@ -282,6 +285,13 @@
                         mUsapPoolSizeMax);
             }
 
+            final String usapPoolRefillDelayMsPropString = Zygote.getConfigurationProperty(
+                    ZygoteConfig.USAP_POOL_REFILL_DELAY_MS, USAP_POOL_REFILL_DELAY_MS_DEFAULT);
+
+            if (!usapPoolRefillDelayMsPropString.isEmpty()) {
+                mUsapPoolRefillDelayMs = Integer.parseInt(usapPoolRefillDelayMsPropString);
+            }
+
             // Sanity check
             if (mUsapPoolSizeMin >= mUsapPoolSizeMax) {
                 Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size."
@@ -467,13 +477,13 @@
                 int elapsedTimeMs =
                         (int) (System.currentTimeMillis() - usapPoolRefillTriggerTimestamp);
 
-                if (elapsedTimeMs >= USAP_REFILL_DELAY_MS) {
+                if (elapsedTimeMs >= mUsapPoolRefillDelayMs) {
                     // Normalize the poll timeout value when the time between one poll event and the
                     // next pushes us over the delay value.  This prevents poll receiving a 0
                     // timeout value, which would result in it returning immediately.
                     pollTimeoutMs = -1;
                 } else {
-                    pollTimeoutMs = USAP_REFILL_DELAY_MS - elapsedTimeMs;
+                    pollTimeoutMs = mUsapPoolRefillDelayMs - elapsedTimeMs;
                 }
             }
 
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index d903524..d4c3565 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -26,17 +26,17 @@
         android:id="@+id/autofill_save"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="32dp"
-        android:paddingTop="16dp"
-        android:elevation="32dp"
+        android:layout_marginTop="@dimen/autofill_save_outer_top_margin"
+        android:paddingTop="@dimen/autofill_save_outer_top_padding"
+        android:elevation="@dimen/autofill_elevation"
         android:background="?android:attr/colorBackground"
         android:orientation="vertical">
 
         <LinearLayout
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:paddingStart="16dp"
-            android:paddingEnd="16dp"
+            android:paddingStart="@dimen/autofill_save_inner_padding"
+            android:paddingEnd="@dimen/autofill_save_inner_padding"
             android:orientation="vertical">
 
             <LinearLayout
@@ -47,17 +47,16 @@
                 <ImageView
                     android:id="@+id/autofill_save_icon"
                     android:scaleType="fitStart"
-                    android:layout_width="24dp"
-                    android:layout_height="24dp"/>
+                    android:layout_width="@dimen/autofill_save_icon_size"
+                    android:layout_height="@dimen/autofill_save_icon_size"/>
 
                 <TextView
                     android:id="@+id/autofill_save_title"
-                    android:paddingStart="8dp"
+                    android:paddingStart="@dimen/autofill_save_title_start_padding"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/autofill_save_title"
-                    android:textSize="16sp"
-                    android:textColor="?android:attr/textColorPrimary"
+                    android:textAppearance="@style/TextAppearance.DeviceDefault.Subhead"
                     android:layout_weight="1">
                 </TextView>
 
@@ -67,7 +66,7 @@
                 android:id="@+id/autofill_save_custom_subtitle"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginTop="4dp"
+                android:layout_marginTop="@dimen/autofill_save_scroll_view_top_margin"
                 android:visibility="gone"/>
 
         </LinearLayout>
@@ -76,7 +75,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="end"
-            android:padding="16dp"
+            android:padding="@dimen/autofill_save_button_bar_padding"
             android:clipToPadding="false"
             android:layout_weight="1"
             android:orientation="horizontal">
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 167e672..6f11432 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -73,6 +73,11 @@
     <dimen name="navigation_bar_width_car_mode">96dp</dimen>
     <!-- Height of notification icons in the status bar -->
     <dimen name="status_bar_icon_size">22dip</dimen>
+    <!-- Desired size of system icons in status bar. -->
+    <dimen name="status_bar_system_icon_size">15dp</dimen>
+    <!-- Intrinsic size of most system icons in status bar. This is the default value that
+         is used if a Drawable reports an intrinsic size of 0. -->
+    <dimen name="status_bar_system_icon_intrinsic_size">17dp</dimen>
     <!-- Size of the giant number (unread count) in the notifications -->
     <dimen name="status_bar_content_number_size">48sp</dimen>
     <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
@@ -668,6 +673,16 @@
     <dimen name="autofill_dataset_picker_max_width">90%</dimen>
     <dimen name="autofill_dataset_picker_max_height">90%</dimen>
 
+    <!-- Autofill save dialog padding -->
+    <dimen name="autofill_save_outer_top_margin">32dp</dimen>
+    <dimen name="autofill_save_outer_top_padding">16dp</dimen>
+    <dimen name="autofill_elevation">32dp</dimen>
+    <dimen name="autofill_save_inner_padding">16dp</dimen>
+    <dimen name="autofill_save_icon_size">24dp</dimen>
+    <dimen name="autofill_save_title_start_padding">8dp</dimen>
+    <dimen name="autofill_save_scroll_view_top_margin">4dp</dimen>
+    <dimen name="autofill_save_button_bar_padding">16dp</dimen>
+
     <!-- Max height of the the autofill save custom subtitle as a fraction of the screen width/height -->
     <dimen name="autofill_save_custom_subtitle_max_height">20%</dimen>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7de6ca5..37678dd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1561,7 +1561,7 @@
     <!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=69] -->
     <string name="face_error_hw_not_available">Can\u2019t verify face. Hardware not available.</string>
     <!-- Error message shown when the face hardware timer has expired and the user needs to restart the operation. [CHAR LIMIT=50] -->
-    <string name="face_error_timeout">Face timeout reached. Try again.</string>
+    <string name="face_error_timeout">Try face authentication again.</string>
     <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=69] -->
     <string name="face_error_no_space">Can\u2019t store new face data. Delete an old one first.</string>
     <!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1ef2eb4..3a348f0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2279,6 +2279,8 @@
 
   <java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
   <java-symbol type="dimen" name="status_bar_icon_size" />
+  <java-symbol type="dimen" name="status_bar_system_icon_size" />
+  <java-symbol type="dimen" name="status_bar_system_icon_intrinsic_size" />
   <java-symbol type="drawable" name="list_selector_pressed_holo_dark" />
   <java-symbol type="drawable" name="scrubber_control_disabled_holo" />
   <java-symbol type="drawable" name="scrubber_control_selector_holo" />
diff --git a/libs/protoutil/tests/EncodedBuffer_test.cpp b/libs/protoutil/tests/EncodedBuffer_test.cpp
index 398af60..f895154 100644
--- a/libs/protoutil/tests/EncodedBuffer_test.cpp
+++ b/libs/protoutil/tests/EncodedBuffer_test.cpp
@@ -29,101 +29,101 @@
 }
 
 TEST(EncodedBufferTest, WriteSimple) {
-    EncodedBuffer buffer(TEST_CHUNK_SIZE);
-    EXPECT_EQ(buffer.size(), 0UL);
-    expectPointer(buffer.wp(), 0);
-    EXPECT_EQ(buffer.currentToWrite(), TEST_CHUNK_SIZE);
+    sp<EncodedBuffer> buffer = new EncodedBuffer(TEST_CHUNK_SIZE);
+    EXPECT_EQ(buffer->size(), 0UL);
+    expectPointer(buffer->wp(), 0);
+    EXPECT_EQ(buffer->currentToWrite(), TEST_CHUNK_SIZE);
     for (size_t i = 0; i < TEST_CHUNK_HALF_SIZE; i++) {
-        buffer.writeRawByte(50 + i);
+        buffer->writeRawByte(50 + i);
     }
-    EXPECT_EQ(buffer.size(), TEST_CHUNK_HALF_SIZE);
-    expectPointer(buffer.wp(), TEST_CHUNK_HALF_SIZE);
-    EXPECT_EQ(buffer.currentToWrite(), TEST_CHUNK_HALF_SIZE);
+    EXPECT_EQ(buffer->size(), TEST_CHUNK_HALF_SIZE);
+    expectPointer(buffer->wp(), TEST_CHUNK_HALF_SIZE);
+    EXPECT_EQ(buffer->currentToWrite(), TEST_CHUNK_HALF_SIZE);
     for (size_t i = 0; i < TEST_CHUNK_SIZE; i++) {
-        buffer.writeRawByte(80 + i);
+        buffer->writeRawByte(80 + i);
     }
-    EXPECT_EQ(buffer.size(), TEST_CHUNK_SIZE + TEST_CHUNK_HALF_SIZE);
-    expectPointer(buffer.wp(), TEST_CHUNK_SIZE + TEST_CHUNK_HALF_SIZE);
-    EXPECT_EQ(buffer.currentToWrite(), TEST_CHUNK_HALF_SIZE);
+    EXPECT_EQ(buffer->size(), TEST_CHUNK_SIZE + TEST_CHUNK_HALF_SIZE);
+    expectPointer(buffer->wp(), TEST_CHUNK_SIZE + TEST_CHUNK_HALF_SIZE);
+    EXPECT_EQ(buffer->currentToWrite(), TEST_CHUNK_HALF_SIZE);
 
     // verifies the buffer's data
-    expectPointer(buffer.ep(), 0);
+    expectPointer(buffer->ep(), 0);
     for (size_t i = 0; i < TEST_CHUNK_HALF_SIZE; i++) {
-        EXPECT_EQ(buffer.readRawByte(), 50 + i);
+        EXPECT_EQ(buffer->readRawByte(), 50 + i);
     }
     for (size_t i = 0; i < TEST_CHUNK_SIZE; i++) {
-        EXPECT_EQ(buffer.readRawByte(), 80 + i);
+        EXPECT_EQ(buffer->readRawByte(), 80 + i);
     }
 
     // clears the buffer
-    buffer.clear();
-    EXPECT_EQ(buffer.size(), 0UL);
-    expectPointer(buffer.wp(), 0);
+    buffer->clear();
+    EXPECT_EQ(buffer->size(), 0UL);
+    expectPointer(buffer->wp(), 0);
 }
 
 TEST(EncodedBufferTest, WriteVarint) {
-    EncodedBuffer buffer(TEST_CHUNK_SIZE);
+    sp<EncodedBuffer> buffer = new EncodedBuffer(TEST_CHUNK_SIZE);
     size_t expected_buffer_size = 0;
-    EXPECT_EQ(buffer.writeRawVarint32(13), 1);
+    EXPECT_EQ(buffer->writeRawVarint32(13), 1);
     expected_buffer_size += 1;
-    EXPECT_EQ(buffer.size(), expected_buffer_size);
-    EXPECT_EQ(buffer.writeRawVarint32(UINT32_C(-1)), 5);
+    EXPECT_EQ(buffer->size(), expected_buffer_size);
+    EXPECT_EQ(buffer->writeRawVarint32(UINT32_C(-1)), 5);
     expected_buffer_size += 5;
-    EXPECT_EQ(buffer.size(), expected_buffer_size);
+    EXPECT_EQ(buffer->size(), expected_buffer_size);
 
-    EXPECT_EQ(buffer.writeRawVarint64(200), 2);
+    EXPECT_EQ(buffer->writeRawVarint64(200), 2);
     expected_buffer_size += 2;
-    EXPECT_EQ(buffer.size(), expected_buffer_size);
-    EXPECT_EQ(buffer.writeRawVarint64(UINT64_C(-1)), 10);
+    EXPECT_EQ(buffer->size(), expected_buffer_size);
+    EXPECT_EQ(buffer->writeRawVarint64(UINT64_C(-1)), 10);
     expected_buffer_size += 10;
-    EXPECT_EQ(buffer.size(), expected_buffer_size);
+    EXPECT_EQ(buffer->size(), expected_buffer_size);
 
-    buffer.writeRawFixed32(UINT32_C(-1));
+    buffer->writeRawFixed32(UINT32_C(-1));
     expected_buffer_size += 4;
-    EXPECT_EQ(buffer.size(), expected_buffer_size);
-    buffer.writeRawFixed64(UINT64_C(-1));
+    EXPECT_EQ(buffer->size(), expected_buffer_size);
+    buffer->writeRawFixed64(UINT64_C(-1));
     expected_buffer_size += 8;
-    EXPECT_EQ(buffer.size(), expected_buffer_size);
+    EXPECT_EQ(buffer->size(), expected_buffer_size);
 
-    EXPECT_EQ(buffer.writeHeader(32, 2), 2);
+    EXPECT_EQ(buffer->writeHeader(32, 2), 2);
     expected_buffer_size += 2;
-    EXPECT_EQ(buffer.size(), expected_buffer_size);
+    EXPECT_EQ(buffer->size(), expected_buffer_size);
 
     // verify data are correctly written to the buffer.
-    expectPointer(buffer.ep(), 0);
-    EXPECT_EQ(buffer.readRawVarint(), UINT32_C(13));
-    EXPECT_EQ(buffer.readRawVarint(), UINT32_C(-1));
-    EXPECT_EQ(buffer.readRawVarint(), UINT64_C(200));
-    EXPECT_EQ(buffer.readRawVarint(), UINT64_C(-1));
-    EXPECT_EQ(buffer.readRawFixed32(), UINT32_C(-1));
-    EXPECT_EQ(buffer.readRawFixed64(), UINT64_C(-1));
-    EXPECT_EQ(buffer.readRawVarint(), UINT64_C((32 << 3) + 2));
-    expectPointer(buffer.ep(), expected_buffer_size);
+    expectPointer(buffer->ep(), 0);
+    EXPECT_EQ(buffer->readRawVarint(), UINT32_C(13));
+    EXPECT_EQ(buffer->readRawVarint(), UINT32_C(-1));
+    EXPECT_EQ(buffer->readRawVarint(), UINT64_C(200));
+    EXPECT_EQ(buffer->readRawVarint(), UINT64_C(-1));
+    EXPECT_EQ(buffer->readRawFixed32(), UINT32_C(-1));
+    EXPECT_EQ(buffer->readRawFixed64(), UINT64_C(-1));
+    EXPECT_EQ(buffer->readRawVarint(), UINT64_C((32 << 3) + 2));
+    expectPointer(buffer->ep(), expected_buffer_size);
 }
 
 TEST(EncodedBufferTest, Edit) {
-    EncodedBuffer buffer(TEST_CHUNK_SIZE);
-    buffer.writeRawFixed64(0xdeadbeefdeadbeef);
-    EXPECT_EQ(buffer.readRawFixed64(), UINT64_C(0xdeadbeefdeadbeef));
+    sp<EncodedBuffer> buffer = new EncodedBuffer(TEST_CHUNK_SIZE);
+    buffer->writeRawFixed64(0xdeadbeefdeadbeef);
+    EXPECT_EQ(buffer->readRawFixed64(), UINT64_C(0xdeadbeefdeadbeef));
 
-    buffer.editRawFixed32(4, 0x12345678);
+    buffer->editRawFixed32(4, 0x12345678);
     // fixed 64 is little endian order.
-    buffer.ep()->rewind(); // rewind ep for readRawFixed64 from 0
-    EXPECT_EQ(buffer.readRawFixed64(), UINT64_C(0x12345678deadbeef));
+    buffer->ep()->rewind(); // rewind ep for readRawFixed64 from 0
+    EXPECT_EQ(buffer->readRawFixed64(), UINT64_C(0x12345678deadbeef));
 
-    buffer.wp()->rewind();
-    expectPointer(buffer.wp(), 0);
-    buffer.copy(4, 3);
-    buffer.ep()->rewind(); // rewind ep for readRawFixed64 from 0
-    EXPECT_EQ(buffer.readRawFixed64(), UINT64_C(0x12345678de345678));
+    buffer->wp()->rewind();
+    expectPointer(buffer->wp(), 0);
+    buffer->copy(4, 3);
+    buffer->ep()->rewind(); // rewind ep for readRawFixed64 from 0
+    EXPECT_EQ(buffer->readRawFixed64(), UINT64_C(0x12345678de345678));
 }
 
 TEST(EncodedBufferTest, ReadSimple) {
-    EncodedBuffer buffer(TEST_CHUNK_SIZE);
+    sp<EncodedBuffer> buffer = new EncodedBuffer(TEST_CHUNK_SIZE);
     for (size_t i = 0; i < TEST_CHUNK_3X_SIZE; i++) {
-        buffer.writeRawByte(i);
+        buffer->writeRawByte(i);
     }
-    sp<ProtoReader> reader1 = buffer.read();
+    sp<ProtoReader> reader1 = buffer->read();
     EXPECT_EQ(reader1->size(), TEST_CHUNK_3X_SIZE);
     EXPECT_EQ(reader1->bytesRead(), 0);
 
@@ -132,7 +132,7 @@
     }
     EXPECT_EQ(reader1->bytesRead(), TEST_CHUNK_3X_SIZE);
 
-    sp<ProtoReader> reader2 = buffer.read();
+    sp<ProtoReader> reader2 = buffer->read();
     uint8_t val = 0;
     while (reader2->hasNext()) {
         EXPECT_EQ(reader2->next(), val);
@@ -143,10 +143,10 @@
 }
 
 TEST(EncodedBufferTest, ReadVarint) {
-    EncodedBuffer buffer;
+    sp<EncodedBuffer> buffer = new EncodedBuffer();
     uint64_t val = UINT64_C(1522865904593);
-    size_t len = buffer.writeRawVarint64(val);
-    sp<ProtoReader> reader = buffer.read();
+    size_t len = buffer->writeRawVarint64(val);
+    sp<ProtoReader> reader = buffer->read();
     EXPECT_EQ(reader->size(), len);
     EXPECT_EQ(reader->readRawVarint(), val);
 }
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 43d7d8f..e731b45 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -70,6 +70,10 @@
 
     private static final String TAG = "DynSystemInstallationService";
 
+
+    // TODO (b/131866826): This is currently for test only. Will move this to System API.
+    static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED";
+
     /*
      * Intent actions
      */
@@ -122,6 +126,9 @@
     private long mInstalledSize;
     private boolean mJustCancelledByUser;
 
+    // This is for testing only now
+    private boolean mEnableWhenCompleted;
+
     private InstallationAsyncTask mInstallTask;
 
 
@@ -178,6 +185,11 @@
     public void onResult(int result, Throwable detail) {
         if (result == RESULT_OK) {
             postStatus(STATUS_READY, CAUSE_INSTALL_COMPLETED, null);
+
+            // For testing: enable DSU and restart the device when install completed
+            if (mEnableWhenCompleted) {
+                executeRebootToDynSystemCommand();
+            }
             return;
         }
 
@@ -224,6 +236,7 @@
         String url = intent.getDataString();
         mSystemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0);
         mUserdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
+        mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false);
 
         mInstallTask = new InstallationAsyncTask(
                 url, mSystemSize, mUserdataSize, this, mDynSystem, this);
@@ -275,7 +288,7 @@
     private void executeRebootToDynSystemCommand() {
         boolean enabled = false;
 
-        if (mInstallTask != null && mInstallTask.getStatus() == FINISHED) {
+        if (mInstallTask != null && mInstallTask.getResult() == RESULT_OK) {
             enabled = mInstallTask.commit();
         } else if (isDynamicSystemInstalled()) {
             enabled = mDynSystem.setEnable(true);
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
index b1c09381..8a2948b 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
@@ -92,6 +92,8 @@
         Uri url = callingIntent.getData();
         long systemSize = callingIntent.getLongExtra(KEY_SYSTEM_SIZE, 0);
         long userdataSize = callingIntent.getLongExtra(KEY_USERDATA_SIZE, 0);
+        boolean enableWhenCompleted = callingIntent.getBooleanExtra(
+                DynamicSystemInstallationService.KEY_ENABLE_WHEN_COMPLETED, false);
 
         sVerifiedUrl = url.toString();
 
@@ -101,6 +103,8 @@
         intent.setAction(DynamicSystemClient.ACTION_START_INSTALL);
         intent.putExtra(KEY_SYSTEM_SIZE, systemSize);
         intent.putExtra(KEY_USERDATA_SIZE, userdataSize);
+        intent.putExtra(
+                DynamicSystemInstallationService.KEY_ENABLE_WHEN_COMPLETED, enableWhenCompleted);
 
         Log.d(TAG, "Starting Installation Service");
         startServiceAsUser(intent, UserHandle.SYSTEM);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 1d351a5..9a95288 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -826,11 +826,22 @@
     }
 
     /**
-     * @return resource for string that discribes the connection state of this device.
-     * case 1: idle or playing media, show "Active" on the only one A2DP active device.
-     * case 2: in phone call, show "Active" on the only one HFP active device
+     * Return full summary that describes connection state of this device
+     *
+     * @see #getConnectionSummary(boolean shortSummary)
      */
     public String getConnectionSummary() {
+        return getConnectionSummary(false /* shortSummary */);
+    }
+
+    /**
+     * Return summary that describes connection state of this device. Summary depends on:
+     * 1. Whether device has battery info
+     * 2. Whether device is in active usage(or in phone call)
+     *
+     * @param shortSummary {@code true} if need to return short version summary
+     */
+    public String getConnectionSummary(boolean shortSummary) {
         boolean profileConnected = false;    // Updated as long as BluetoothProfile is connected
         boolean a2dpConnected = true;        // A2DP is connected
         boolean hfpConnected = true;         // HFP is connected
@@ -909,9 +920,9 @@
                 if ((mIsActiveDeviceHearingAid)
                         || (mIsActiveDeviceHeadset && isOnCall)
                         || (mIsActiveDeviceA2dp && !isOnCall)) {
-                    if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+                    if (isTwsBatteryAvailable(leftBattery, rightBattery) && !shortSummary) {
                         stringRes = R.string.bluetooth_active_battery_level_untethered;
-                    } else if (batteryLevelPercentageString != null) {
+                    } else if (batteryLevelPercentageString != null && !shortSummary) {
                         stringRes = R.string.bluetooth_active_battery_level;
                     } else {
                         stringRes = R.string.bluetooth_active_no_battery_level;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index c0a1f11..93dcbfe 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -192,6 +192,27 @@
     }
 
     @Test
+    public void getConnectionSummary_shortSummary_returnShortSummary() {
+        // Test without battery level
+        // Set A2DP profile to be connected and test connection state summary
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary(true /* shortSummary */)).isNull();
+
+        // Set device as Active for A2DP and test connection state summary
+        mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
+        assertThat(mCachedDevice.getConnectionSummary(true /* shortSummary */)).isEqualTo("Active");
+
+        // Test with battery level
+        mBatteryLevel = 10;
+        assertThat(mCachedDevice.getConnectionSummary(true /* shortSummary */)).isEqualTo(
+                "Active");
+
+        // Set A2DP profile to be disconnected and test connection state summary
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+
+    @Test
     public void getConnectionSummary_testA2dpBatteryInactive_returnBattery() {
         // Arrange:
         //   1. Profile:       {A2DP, CONNECTED, Inactive}
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid.xml b/packages/SystemUI/res/layout-land/global_actions_grid.xml
index 86b103d..4619430 100644
--- a/packages/SystemUI/res/layout-land/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout-land/global_actions_grid.xml
@@ -6,16 +6,15 @@
     android:layout_height="match_parent"
     android:orientation="horizontal"
     android:theme="@style/qs_theme"
-    android:gravity="right"
+    android:gravity="right | center_vertical"
     android:clipChildren="false"
     android:clipToPadding="false"
     android:paddingRight="@dimen/global_actions_grid_container_shadow_offset"
     android:layout_marginRight="@dimen/global_actions_grid_container_negative_shadow_offset"
 >
     <LinearLayout
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:layout_width="wrap_content"
-        android:gravity="top|right"
         android:orientation="vertical"
         android:layout_marginRight="@dimen/global_actions_grid_container_bottom_margin"
         android:clipChildren="false"
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
index 4c3fcc0..4ece03b 100644
--- a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
+++ b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
@@ -6,16 +6,15 @@
     android:layout_height="match_parent"
     android:orientation="horizontal"
     android:theme="@style/qs_theme"
-    android:gravity="left"
+    android:gravity="left | center_vertical"
     android:clipChildren="false"
     android:clipToPadding="false"
     android:paddingLeft="@dimen/global_actions_grid_container_shadow_offset"
     android:layout_marginLeft="@dimen/global_actions_grid_container_negative_shadow_offset"
 >
     <LinearLayout
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:layout_width="wrap_content"
-        android:gravity="bottom|left"
         android:padding="0dp"
         android:orientation="vertical"
         android:clipChildren="false"
diff --git a/packages/SystemUI/res/layout/global_actions_grid.xml b/packages/SystemUI/res/layout/global_actions_grid.xml
index 43e6b49..3928062 100644
--- a/packages/SystemUI/res/layout/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid.xml
@@ -6,7 +6,7 @@
     android:layout_height="match_parent"
     android:orientation="horizontal"
     android:theme="@style/qs_theme"
-    android:gravity="bottom"
+    android:gravity="bottom | center_horizontal"
     android:clipChildren="false"
     android:clipToPadding="false"
     android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset"
@@ -14,8 +14,7 @@
 >
     <LinearLayout
         android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:gravity="bottom | right"
+        android:layout_width="wrap_content"
         android:layoutDirection="ltr"
         android:clipChildren="false"
         android:clipToPadding="false"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6dbc385..e00e5f2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -41,10 +41,10 @@
 
     <!-- Size of the nav bar edge panels, should be greater to the
          edge sensitivity + the drag threshold -->
-    <dimen name="navigation_edge_panel_width">76dp</dimen>
+    <dimen name="navigation_edge_panel_width">70dp</dimen>
     <!-- Padding at the end of the navigation panel to allow the arrow not to be clipped off -->
-    <dimen name="navigation_edge_panel_padding">24dp</dimen>
-    <dimen name="navigation_edge_panel_height">84dp</dimen>
+    <dimen name="navigation_edge_panel_padding">8dp</dimen>
+    <dimen name="navigation_edge_panel_height">96dp</dimen>
     <!-- The threshold to drag to trigger the edge action -->
     <dimen name="navigation_edge_action_drag_threshold">16dp</dimen>
     <!-- The minimum display position of the arrow on the screen -->
@@ -89,7 +89,7 @@
     <dimen name="status_bar_wifi_signal_spacer_width">2.5dp</dimen>
 
     <!-- Size of the view displaying the wifi signal icon in the status bar. -->
-    <dimen name="status_bar_wifi_signal_size">15dp</dimen>
+    <dimen name="status_bar_wifi_signal_size">@*android:dimen/status_bar_system_icon_size</dimen>
 
     <!-- Spacing before the airplane mode icon if there are any icons preceding it. -->
     <dimen name="status_bar_airplane_spacer_width">4dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 55499da..0e91e41 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -68,6 +68,9 @@
     private final AppearAnimationUtils mAppearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
+    private final int[] mTmpPosition = new int[2];
+    private final Rect mTempRect = new Rect();
+    private final Rect mLockPatternScreenBounds = new Rect();
 
     private CountDownTimer mCountdownTimer = null;
     private LockPatternUtils mLockPatternUtils;
@@ -92,7 +95,6 @@
             mLockPatternView.clearPattern();
         }
     };
-    private Rect mTempRect = new Rect();
     @VisibleForTesting
     KeyguardMessageArea mSecurityMessageDisplay;
     private View mEcaView;
@@ -199,6 +201,15 @@
     }
 
     @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        mLockPatternView.getLocationOnScreen(mTmpPosition);
+        mLockPatternScreenBounds.set(mTmpPosition[0], mTmpPosition[1],
+                mTmpPosition[0] + mLockPatternView.getWidth(),
+                mTmpPosition[1] + mLockPatternView.getHeight());
+    }
+
+    @Override
     public void reset() {
         // reset lock pattern
         mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
@@ -233,9 +244,7 @@
 
     @Override
     public boolean disallowInterceptTouch(MotionEvent event) {
-        mTempRect.set(mLockPatternView.getLeft(), mLockPatternView.getTop(),
-                mLockPatternView.getRight(), mLockPatternView.getBottom());
-        return mTempRect.contains((int) event.getX(), (int) event.getY());
+        return mLockPatternScreenBounds.contains((int) event.getRawX(), (int) event.getRawY());
     }
 
     /** TODO: hook this up */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index af2b767..a9fe54b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -21,7 +21,6 @@
 import android.annotation.ColorInt;
 import android.annotation.UserIdInt;
 import android.app.Activity;
-import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
@@ -32,9 +31,7 @@
 import android.content.IntentFilter;
 import android.graphics.Color;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.UserHandle;
-import android.util.Log;
 import android.view.View;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -56,7 +53,9 @@
      */
     static final String EXTRA_TASK_DESCRIPTION =
             "com.android.systemui.keyguard.extra.TASK_DESCRIPTION";
-  
+
+    private static final int REQUEST_CODE_CONFIRM_CREDENTIALS = 1;
+
     /**
      * Cached keyguard manager instance populated by {@link #getKeyguardManager}.
      * @see KeyguardManager
@@ -111,7 +110,6 @@
     @Override
     public void onBackPressed() {
         // Ignore back presses.
-        return;
     }
 
     @Override
@@ -151,26 +149,26 @@
                 PendingIntent.FLAG_ONE_SHOT |
                 PendingIntent.FLAG_IMMUTABLE, options.toBundle());
 
-        credential.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
-        try {
-            ActivityManager.getService().startConfirmDeviceCredentialIntent(credential,
-                    getChallengeOptions().toBundle());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to start confirm credential intent", e);
+        if (target != null) {
+            credential.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
+        }
+
+        startActivityForResult(credential, REQUEST_CODE_CONFIRM_CREDENTIALS);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_CODE_CONFIRM_CREDENTIALS &&  resultCode != RESULT_OK) {
+            // The user dismissed the challenge, don't show it again.
+            goToHomeScreen();
         }
     }
 
-    private ActivityOptions getChallengeOptions() {
-        // If we are taking up the whole screen, just use the default animation of clipping the
-        // credentials activity into the entire foreground.
-        if (!isInMultiWindowMode()) {
-            return ActivityOptions.makeBasic();
-        }
-
-        // Otherwise, animate the transition from this part of the screen to fullscreen
-        // using our own decor as the starting position.
-        final View view = getWindow().getDecorView();
-        return ActivityOptions.makeScaleUpAnimation(view, 0, 0, view.getWidth(), view.getHeight());
+    private void goToHomeScreen() {
+        final Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+        homeIntent.addCategory(Intent.CATEGORY_HOME);
+        homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        startActivity(homeIntent);
     }
 
     private KeyguardManager getKeyguardManager() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 033c4fb..6552fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -40,7 +40,6 @@
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 import android.util.FloatProperty;
 import android.util.Log;
 import android.util.Property;
@@ -72,12 +71,12 @@
     /**
      * Status icons are currently drawn with the intention of being 17dp tall, but we
      * want to scale them (in a way that doesn't require an asset dump) down 2dp. So
-     * 17dp * (15 / 17) = 15dp, the new height.
+     * 17dp * (15 / 17) = 15dp, the new height. After the first call to {@link #reloadDimens} all
+     * values will be in px.
      */
-    private static final float SYSTEM_ICON_DESIRED_HEIGHT = 15f;
-    private static final float SYSTEM_ICON_INTRINSIC_HEIGHT = 17f;
-    private static final float SYSTEM_ICON_SCALE =
-            SYSTEM_ICON_DESIRED_HEIGHT / SYSTEM_ICON_INTRINSIC_HEIGHT;
+    private float mSystemIconDesiredHeight = 15f;
+    private float mSystemIconIntrinsicHeight = 17f;
+    private float mSystemIconDefaultScale = mSystemIconDesiredHeight / mSystemIconIntrinsicHeight;
     private final int ANIMATION_DURATION_FAST = 100;
 
     public static final int STATE_ICON = 0;
@@ -209,21 +208,20 @@
     // Makes sure that all icons are scaled to the same height (15dp). If we cannot get a height
     // for the icon, it uses the default SCALE (15f / 17f) which is the old behavior
     private void updateIconScaleForSystemIcons() {
-        float iconHeight = getIconHeightInDps();
+        float iconHeight = getIconHeight();
         if (iconHeight != 0) {
-            mIconScale = SYSTEM_ICON_DESIRED_HEIGHT / iconHeight;
+            mIconScale = mSystemIconDesiredHeight / iconHeight;
         } else {
-            mIconScale = SYSTEM_ICON_SCALE;
+            mIconScale = mSystemIconDefaultScale;
         }
     }
 
-    private float getIconHeightInDps() {
+    private float getIconHeight() {
         Drawable d = getDrawable();
         if (d != null) {
-            return ((float) getDrawable().getIntrinsicHeight() * DisplayMetrics.DENSITY_DEFAULT)
-                    / mDensity;
+            return (float) getDrawable().getIntrinsicHeight();
         } else {
-            return SYSTEM_ICON_INTRINSIC_HEIGHT;
+            return mSystemIconIntrinsicHeight;
         }
     }
 
@@ -265,6 +263,11 @@
         if (applyRadius) {
             mDotRadius = mStaticDotRadius;
         }
+        mSystemIconDesiredHeight = res.getDimension(
+                com.android.internal.R.dimen.status_bar_system_icon_size);
+        mSystemIconIntrinsicHeight = res.getDimension(
+                com.android.internal.R.dimen.status_bar_system_icon_intrinsic_size);
+        mSystemIconDefaultScale = mSystemIconDesiredHeight / mSystemIconIntrinsicHeight;
     }
 
     public void setNotification(StatusBarNotification notification) {
@@ -272,6 +275,7 @@
         if (notification != null) {
             setContentDescription(notification.getNotification());
         }
+        maybeUpdateIconScaleDimens();
     }
 
     public StatusBarIconView(Context context, AttributeSet attrs) {
@@ -280,7 +284,7 @@
         mBlocked = false;
         mAlwaysScaleIcon = true;
         reloadDimens();
-        updateIconScaleForNotifications();
+        maybeUpdateIconScaleDimens();
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
     }
 
@@ -854,7 +858,7 @@
     public void setDark(boolean dark, boolean fade, long delay) {
         mDozer.setIntensityDark(f -> {
             mDarkAmount = f;
-            updateIconScaleForNotifications();
+            maybeUpdateIconScaleDimens();
             updateDecorColor();
             updateIconColor();
             updateAllowAnimation();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index f93c5f0..a3e3426 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -46,6 +46,7 @@
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
 
 import javax.inject.Inject;
@@ -71,6 +72,7 @@
     private final AccessibilityController mAccessibilityController;
     private final DockManager mDockManager;
     private final Handler mMainHandler;
+    private final KeyguardMonitor mKeyguardMonitor;
 
     private int mLastState = 0;
     private boolean mTransientBiometricsError;
@@ -91,7 +93,16 @@
     private int mIconRes;
     private boolean mWasPulsingOnThisFrame;
     private boolean mWakeAndUnlockRunning;
+    private boolean mKeyguardShowing;
 
+    private final KeyguardMonitor.Callback mKeyguardMonitorCallback =
+            new KeyguardMonitor.Callback() {
+                @Override
+                public void onKeyguardShowingChanged() {
+                    mKeyguardShowing = mKeyguardMonitor.isShowing();
+                    update(false /* force */);
+                }
+            };
     private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
     private final DockManager.DockEventListener mDockEventListener =
             new DockManager.DockEventListener() {
@@ -150,6 +161,7 @@
             StatusBarStateController statusBarStateController,
             ConfigurationController configurationController,
             AccessibilityController accessibilityController,
+            KeyguardMonitor keyguardMonitor,
             @Nullable DockManager dockManager,
             @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
         super(context, attrs);
@@ -159,6 +171,7 @@
         mAccessibilityController = accessibilityController;
         mConfigurationController = configurationController;
         mStatusBarStateController = statusBarStateController;
+        mKeyguardMonitor = keyguardMonitor;
         mDockManager = dockManager;
         mMainHandler = mainHandler;
     }
@@ -168,6 +181,7 @@
         super.onAttachedToWindow();
         mStatusBarStateController.addCallback(this);
         mConfigurationController.addCallback(this);
+        mKeyguardMonitor.addCallback(mKeyguardMonitorCallback);
         mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
         mUnlockMethodCache.addListener(this);
         mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
@@ -183,6 +197,7 @@
         mStatusBarStateController.removeCallback(this);
         mConfigurationController.removeCallback(this);
         mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
+        mKeyguardMonitor.removeCallback(mKeyguardMonitorCallback);
         mUnlockMethodCache.removeListener(this);
         if (mDockManager != null) {
             mDockManager.removeListener(mDockEventListener);
@@ -379,7 +394,7 @@
         KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
         if (mTransientBiometricsError) {
             return STATE_BIOMETRICS_ERROR;
-        } else if (mUnlockMethodCache.canSkipBouncer() && !mSimLocked) {
+        } else if ((mUnlockMethodCache.canSkipBouncer() || !mKeyguardShowing) && !mSimLocked) {
             return STATE_LOCK_OPEN;
         } else if (updateMonitor.isFaceDetectionRunning()) {
             return STATE_SCANNING_FACE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
index 4603ba6..4f223c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.os.SystemClock;
 import android.os.VibrationEffect;
+import android.util.DisplayMetrics;
 import android.util.MathUtils;
 import android.view.ContextThemeWrapper;
 import android.view.MotionEvent;
@@ -47,14 +48,14 @@
 
 public class NavigationBarEdgePanel extends View {
 
-    private static final long COLOR_ANIMATION_DURATION_MS = 100;
-    private static final long DISAPPEAR_FADE_ANIMATION_DURATION_MS = 140;
+    private static final long COLOR_ANIMATION_DURATION_MS = 120;
+    private static final long DISAPPEAR_FADE_ANIMATION_DURATION_MS = 80;
     private static final long DISAPPEAR_ARROW_ANIMATION_DURATION_MS = 100;
 
     /**
-     * The minimum time required since the first vibration effect to receive a second one
+     * The time required since the first vibration effect to automatically trigger a click
      */
-    private static final int MIN_TIME_BETWEEN_EFFECTS_MS = 120;
+    private static final int GESTURE_DURATION_FOR_CLICK_MS = 400;
 
     /**
      * The size of the protection of the arrow in px. Only used if this is not background protected
@@ -79,7 +80,7 @@
     /**
      * The angle that is added per 1000 px speed to the angle of the leg
      */
-    private static final int ARROW_ANGLE_ADDED_PER_1000_SPEED = 8;
+    private static final int ARROW_ANGLE_ADDED_PER_1000_SPEED = 4;
 
     /**
      * The maximum angle offset allowed due to speed
@@ -92,15 +93,15 @@
     private static final float ARROW_THICKNESS_DP = 2.5f;
 
     /**
-     * The amount of rubber banding we do for the horizontal translation beyond the base translation
+     * The amount of rubber banding we do for the vertical translation
      */
-    private static final int RUBBER_BAND_AMOUNT = 10;
+    private static final int RUBBER_BAND_AMOUNT = 15;
 
     /**
      * The interpolator used to rubberband
      */
     private static final Interpolator RUBBER_BAND_INTERPOLATOR
-            = new PathInterpolator(1.0f / RUBBER_BAND_AMOUNT, 1.0f, 1.0f, 1.0f);
+            = new PathInterpolator(1.0f / 5.0f, 1.0f, 1.0f, 1.0f);
 
     /**
      * The amount of rubber banding we do for the translation before base translation
@@ -189,6 +190,7 @@
     private int mCurrentArrowColor;
     private float mDisappearAmount;
     private long mVibrationTime;
+    private int mScreenSize;
 
     private DynamicAnimation.OnAnimationEndListener mSetGoneEndListener
             = new DynamicAnimation.OnAnimationEndListener() {
@@ -281,9 +283,8 @@
         mAngleAnimation =
                 new SpringAnimation(this, CURRENT_ANGLE);
         mAngleAppearForce = new SpringForce()
-                .setStiffness(SpringForce.STIFFNESS_LOW)
-                .setDampingRatio(0.4f)
-                .setFinalPosition(ARROW_ANGLE_WHEN_EXTENDED_DEGREES);
+                .setStiffness(500)
+                .setDampingRatio(0.5f);
         mAngleDisappearForce = new SpringForce()
                 .setStiffness(SpringForce.STIFFNESS_MEDIUM)
                 .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
@@ -447,13 +448,14 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
-        // TODO: read the gesture length from the nav controller.
         mMaxTranslation = getWidth() - mArrowPaddingEnd;
     }
 
     private void loadDimens() {
         mArrowPaddingEnd = getContext().getResources().getDimensionPixelSize(
                 R.dimen.navigation_edge_panel_padding);
+        DisplayMetrics metrics = getResources().getDisplayMetrics();
+        mScreenSize = Math.min(metrics.widthPixels, metrics.heightPixels);
     }
 
     private void updateArrowDirection() {
@@ -510,7 +512,7 @@
         if (!mArrowsPointLeft) {
             x = -x;
         }
-        float extent = 1.0f - mDisappearAmount;
+        float extent = MathUtils.lerp(1.0f, 0.75f, mDisappearAmount);
         x = x * extent;
         y = y * extent;
         mArrowPath.reset();
@@ -529,27 +531,29 @@
     }
 
     private void triggerBack() {
-        if (SystemClock.uptimeMillis() - mVibrationTime >= MIN_TIME_BETWEEN_EFFECTS_MS) {
-            mVibratorHelper.vibrate(VibrationEffect.EFFECT_CLICK);
-        }
         mVelocityTracker.computeCurrentVelocity(1000);
         // Only do the extra translation if we're not already flinging
-        boolean doExtraTranslation = Math.abs(mVelocityTracker.getXVelocity()) < 1000;
-        if (doExtraTranslation) {
-            setDesiredTranslation(mDesiredTranslation + dp(16), true /* animate */);
+        boolean isSlow = Math.abs(mVelocityTracker.getXVelocity()) < 500;
+        if (isSlow
+                || SystemClock.uptimeMillis() - mVibrationTime >= GESTURE_DURATION_FOR_CLICK_MS) {
+            mVibratorHelper.vibrate(VibrationEffect.EFFECT_CLICK);
         }
 
         // Let's also snap the angle a bit
-        if (mAngleOffset < -4) {
-            mAngleOffset = Math.max(-16, mAngleOffset - 16);
+        if (mAngleOffset > -4) {
+            mAngleOffset = Math.max(-8, mAngleOffset - 8);
             updateAngle(true /* animated */);
         }
 
         // Finally, after the translation, animate back and disappear the arrow
         Runnable translationEnd = () -> {
-            setTriggerBack(false /* false */, true /* animate */);
+            // let's snap it back
+            mAngleOffset = Math.max(0, mAngleOffset + 8);
+            updateAngle(true /* animated */);
+
             mTranslationAnimation.setSpring(mTriggerBackSpring);
-            setDesiredTranslation(0, true /* animated */);
+            // Translate the arrow back a bit to make for a nice transition
+            setDesiredTranslation(mDesiredTranslation - dp(32), true /* animated */);
             animate().alpha(0f).setDuration(DISAPPEAR_FADE_ANIMATION_DURATION_MS)
                     .withEndAction(() -> setVisibility(GONE));
             mArrowDisappearAnimation.start();
@@ -584,6 +588,7 @@
         setTriggerBack(false /* triggerBack */, false /* animated */);
         setDesiredTranslation(0, false /* animated */);
         setCurrentTranslation(0);
+        updateAngle(false /* animate */);
         mPreviousTouchTranslation = 0;
         mTotalTouchDelta = 0;
         mVibrationTime = 0;
@@ -621,7 +626,7 @@
         // Let's make sure we only go to the baseextend and apply rubberbanding afterwards
         if (touchTranslation > mBaseTranslation) {
             float diff = touchTranslation - mBaseTranslation;
-            float progress = MathUtils.saturate(diff / (mBaseTranslation * RUBBER_BAND_AMOUNT));
+            float progress = MathUtils.saturate(diff / (mScreenSize - mBaseTranslation));
             progress = RUBBER_BAND_INTERPOLATOR.getInterpolation(progress)
                     * (mMaxTranslation - mBaseTranslation);
             touchTranslation = mBaseTranslation + progress;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java
index d59319e..2b0bb21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java
@@ -27,6 +27,7 @@
 import android.view.CompositionSamplingListener;
 import android.view.SurfaceControl;
 import android.view.View;
+import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 
 import com.android.systemui.R;
@@ -153,8 +154,12 @@
         boolean isSamplingEnabled = mSamplingEnabled && !mSamplingRequestBounds.isEmpty()
                 && (mSampledView.isAttachedToWindow() || mFirstSamplingAfterStart);
         if (isSamplingEnabled) {
-            SurfaceControl stopLayerControl = mSampledView.getViewRootImpl().getSurfaceControl();
-            if (!stopLayerControl.isValid()) {
+            ViewRootImpl viewRootImpl = mSampledView.getViewRootImpl();
+            SurfaceControl stopLayerControl = null;
+            if (viewRootImpl != null) {
+                 stopLayerControl = viewRootImpl.getSurfaceControl();
+            }
+            if (stopLayerControl == null || !stopLayerControl.isValid()) {
                 if (!mWaitingOnDraw) {
                     mWaitingOnDraw = true;
                     // The view might be attached but we haven't drawn yet, so wait until the
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 5fd14a3..a5a4fec 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7294,6 +7294,7 @@
     ACTION_VERIFY_SLICE_OTHER_EXCEPTION = 1727;
 
     // ---- Skipping ahead to avoid conflicts between master and release branches.
+
     // OPEN: Settings > System > Gestures > Global Actions Panel
     // CATEGORY: SETTINGS
     // OS: Q
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
new file mode 100644
index 0000000..dd1b84b
--- /dev/null
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2019 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.contentcapture;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
+import android.service.contentcapture.FlushMetrics;
+import android.util.StatsLog;
+
+import java.util.List;
+
+/** @hide */
+public final class ContentCaptureMetricsLogger {
+    /**
+     * Class only contains static utility functions, and should not be instantiated
+     */
+    private ContentCaptureMetricsLogger() {
+    }
+
+    /** @hide */
+    public static void writeServiceEvent(int eventType, @NonNull String serviceName,
+            @Nullable String targetPackage) {
+        StatsLog.write(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS, eventType, serviceName,
+                targetPackage);
+    }
+
+    /** @hide */
+    public static void writeServiceEvent(int eventType, @NonNull ComponentName service,
+            @Nullable ComponentName target) {
+        writeServiceEvent(eventType, ComponentName.flattenToShortString(service),
+                ComponentName.flattenToShortString(target));
+    }
+
+    /** @hide */
+    public static void writeServiceEvent(int eventType, @NonNull ComponentName service,
+            @Nullable String targetPackage) {
+        writeServiceEvent(eventType, ComponentName.flattenToShortString(service), targetPackage);
+    }
+
+    /** @hide */
+    public static void writeServiceEvent(int eventType, @NonNull ComponentName service) {
+        writeServiceEvent(eventType, ComponentName.flattenToShortString(service), null);
+    }
+
+    /** @hide */
+    public static void writeSetWhitelistEvent(@Nullable ComponentName service,
+            @Nullable List<String> packages, @Nullable List<ComponentName> activities) {
+        final String serviceName = ComponentName.flattenToShortString(service);
+        StringBuilder stringBuilder = new StringBuilder();
+        if (packages != null && packages.size() > 0) {
+            final int size = packages.size();
+            stringBuilder.append(packages.get(0));
+            for (int i = 1; i < size; i++) {
+                stringBuilder.append(" ");
+                stringBuilder.append(packages.get(i));
+            }
+        }
+        if (activities != null && activities.size() > 0) {
+            stringBuilder.append(" ");
+            stringBuilder.append(activities.get(0).flattenToShortString());
+            final int size = activities.size();
+            for (int i = 1; i < size; i++) {
+                stringBuilder.append(" ");
+                stringBuilder.append(activities.get(i).flattenToShortString());
+            }
+        }
+        StatsLog.write(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS,
+                StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__SET_WHITELIST,
+                serviceName, stringBuilder.toString());
+    }
+
+    /** @hide */
+    public static void writeSessionEvent(int sessionId, int event, int flags,
+            @NonNull ComponentName service, @Nullable ComponentName app, boolean isChildSession) {
+        StatsLog.write(StatsLog.CONTENT_CAPTURE_SESSION_EVENTS, sessionId, event, flags,
+                ComponentName.flattenToShortString(service),
+                ComponentName.flattenToShortString(app), isChildSession);
+    }
+
+    /** @hide */
+    public static void writeSessionFlush(int sessionId, @NonNull ComponentName service,
+            @Nullable ComponentName app, @NonNull FlushMetrics fm,
+            @NonNull ContentCaptureOptions options, int flushReason) {
+        StatsLog.write(StatsLog.CONTENT_CAPTURE_FLUSHED, sessionId,
+                ComponentName.flattenToShortString(service),
+                ComponentName.flattenToShortString(app), fm.sessionStarted, fm.sessionFinished,
+                fm.viewAppearedCount, fm.viewDisappearedCount, fm.viewTextChangedCount,
+                options.maxBufferSize, options.idleFlushingFrequencyMs,
+                options.textChangeFlushingFrequencyMs, flushReason);
+    }
+}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 67c3d01..a186d4e 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -24,6 +24,9 @@
 import static android.view.contentcapture.ContentCaptureSession.STATE_NOT_WHITELISTED;
 import static android.view.contentcapture.ContentCaptureSession.STATE_NO_SERVICE;
 
+import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeServiceEvent;
+import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeSessionEvent;
+import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeSetWhitelistEvent;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
@@ -35,6 +38,7 @@
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.pm.ActivityPresentationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -48,6 +52,7 @@
 import android.service.contentcapture.ActivityEvent.ActivityEventType;
 import android.service.contentcapture.ContentCaptureService;
 import android.service.contentcapture.ContentCaptureServiceInfo;
+import android.service.contentcapture.FlushMetrics;
 import android.service.contentcapture.IContentCaptureServiceCallback;
 import android.service.contentcapture.SnapshotData;
 import android.util.ArrayMap;
@@ -55,6 +60,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.StatsLog;
 import android.view.contentcapture.ContentCaptureCondition;
 import android.view.contentcapture.DataRemovalRequest;
 
@@ -231,7 +237,6 @@
         resurrectSessionsLocked();
     }
 
-    // TODO(b/119613670): log metrics
     @GuardedBy("mLock")
     public void startSessionLocked(@NonNull IBinder activityToken,
             @NonNull ActivityPresentationInfo activityPresentationInfo, int sessionId, int uid,
@@ -263,9 +268,14 @@
 
         if (!enabled) {
             // TODO: it would be better to split in differet reasons, like
-            // STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY
+            // STATE_DISABLED_NO and STATE_DISABLED_BY_DEVICE_POLICY
             setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
                     /* binder= */ null);
+            // Log metrics.
+            writeSessionEvent(sessionId,
+                    StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED,
+                    STATE_DISABLED | STATE_NO_SERVICE, serviceComponentName,
+                    componentName, /* isChildSession= */ false);
             return;
         }
         if (serviceComponentName == null) {
@@ -285,6 +295,11 @@
             }
             setClientState(clientReceiver, STATE_DISABLED | STATE_NOT_WHITELISTED,
                     /* binder= */ null);
+            // Log metrics.
+            writeSessionEvent(sessionId,
+                    StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED,
+                    STATE_DISABLED | STATE_NOT_WHITELISTED, serviceComponentName,
+                    componentName, /* isChildSession= */ false);
             return;
         }
 
@@ -294,6 +309,11 @@
                     + ": ignoring because it already exists for " + existingSession.mActivityToken);
             setClientState(clientReceiver, STATE_DISABLED | STATE_DUPLICATED_ID,
                     /* binder=*/ null);
+            // Log metrics.
+            writeSessionEvent(sessionId,
+                    StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED,
+                    STATE_DISABLED | STATE_DUPLICATED_ID,
+                    serviceComponentName, componentName, /* isChildSession= */ false);
             return;
         }
 
@@ -302,11 +322,15 @@
         }
 
         if (mRemoteService == null) {
-            // TODO(b/119613670): log metrics
             Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
                     + ": ignoring because service is not set");
             setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
                     /* binder= */ null);
+            // Log metrics.
+            writeSessionEvent(sessionId,
+                    StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED,
+                    STATE_DISABLED | STATE_NO_SERVICE, serviceComponentName,
+                    componentName, /* isChildSession= */ false);
             return;
         }
 
@@ -324,7 +348,6 @@
         newSession.notifySessionStartedLocked(clientReceiver);
     }
 
-    // TODO(b/119613670): log metrics
     @GuardedBy("mLock")
     public void finishSessionLocked(int sessionId) {
         if (!isEnabledLocked()) {
@@ -553,6 +576,7 @@
                         + " for user " + mUserId);
             }
             mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities);
+            writeSetWhitelistEvent(getServiceComponentName(), packages, activities);
 
             // Must disable session that are not the whitelist anymore...
             final int numSessions = mSessions.size();
@@ -602,7 +626,6 @@
                     mConditionsByPkg.put(packageName, new ArraySet<>(conditions));
                 }
             }
-            // TODO(b/119613670): log metrics
         }
 
         @Override
@@ -616,6 +639,15 @@
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
+            writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__SET_DISABLED,
+                    getServiceComponentName());
+        }
+
+        @Override
+        public void writeSessionFlush(int sessionId, ComponentName app, FlushMetrics flushMetrics,
+                ContentCaptureOptions options, int flushReason) {
+            ContentCaptureMetricsLogger.writeSessionFlush(sessionId, getServiceComponentName(), app,
+                    flushMetrics, options, flushReason);
         }
     }
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 2171033..18daf32 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -18,6 +18,9 @@
 import static android.view.contentcapture.ContentCaptureHelper.sDebug;
 import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
 
+import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeServiceEvent;
+import static com.android.server.contentcapture.ContentCaptureMetricsLogger.writeSessionEvent;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
@@ -28,6 +31,7 @@
 import android.service.contentcapture.IContentCaptureServiceCallback;
 import android.service.contentcapture.SnapshotData;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.DataRemovalRequest;
 
@@ -77,6 +81,8 @@
             if (connected) {
                 try {
                     mService.onConnected(mServerCallback, sVerbose, sDebug);
+                    writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_CONNECTED,
+                            mComponentName);
                 } finally {
                     // Update the system-service state, in case the service reconnected after
                     // dying
@@ -84,6 +90,8 @@
                 }
             } else {
                 mService.onDisconnected();
+                writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_DISCONNECTED,
+                        mComponentName);
             }
         } catch (Exception e) {
             Slog.w(mTag, "Exception calling onConnectedStateChanged(" + connected + "): " + e);
@@ -102,6 +110,10 @@
             @NonNull IResultReceiver clientReceiver, int initialState) {
         scheduleAsyncRequest(
                 (s) -> s.onSessionStarted(context, sessionId, uid, clientReceiver, initialState));
+        // Metrics logging.
+        writeSessionEvent(sessionId,
+                StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_STARTED, initialState,
+                getComponentName(), context.getActivityComponent(), /* is_child_session= */ false);
     }
 
     /**
@@ -110,6 +122,11 @@
      */
     public void onSessionFinished(int sessionId) {
         scheduleAsyncRequest((s) -> s.onSessionFinished(sessionId));
+        // Metrics logging.
+        writeSessionEvent(sessionId,
+                StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_FINISHED,
+                /* flags= */ 0, getComponentName(), /* app= */ null,
+                /* is_child_session= */ false);
     }
 
     /**
@@ -124,6 +141,8 @@
      */
     public void onDataRemovalRequest(@NonNull DataRemovalRequest request) {
         scheduleAsyncRequest((s) -> s.onDataRemovalRequest(request));
+        writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_USER_DATA_REMOVED,
+                mComponentName);
     }
 
     /**
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 72899f6..cb61259 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1138,8 +1138,8 @@
                     ? clampPositive(whenElapsed + a.windowLength)
                     : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
         }
-        a.whenElapsed = whenElapsed;
-        a.maxWhenElapsed = maxElapsed;
+        a.expectedWhenElapsed = a.whenElapsed = whenElapsed;
+        a.expectedMaxWhenElapsed = a.maxWhenElapsed = maxElapsed;
         setImplLocked(a, true, doValidate);
     }
 
@@ -1243,7 +1243,7 @@
                 alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;
                 // Also schedule its next recurrence
                 final long delta = alarm.count * alarm.repeatInterval;
-                final long nextElapsed = alarm.whenElapsed + delta;
+                final long nextElapsed = alarm.expectedWhenElapsed + delta;
                 setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
                         maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
                         alarm.repeatInterval, alarm.operation, null, null, alarm.flags, true,
@@ -3596,10 +3596,9 @@
                     // this adjustment will be zero if we're late by
                     // less than one full repeat interval
                     alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;
-
                     // Also schedule its next recurrence
                     final long delta = alarm.count * alarm.repeatInterval;
-                    final long nextElapsed = alarm.whenElapsed + delta;
+                    final long nextElapsed = alarm.expectedWhenElapsed + delta;
                     setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
                             maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
                             alarm.repeatInterval, alarm.operation, null, null, alarm.flags, true,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d8f5937..ea71a3b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -735,11 +735,11 @@
          * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
          * method.
          */
-        void put(int key, ProcessRecord value) {
+        void put(ProcessRecord app) {
             synchronized (this) {
-                mPidMap.put(key, value);
+                mPidMap.put(app.pid, app);
             }
-            mAtmInternal.onProcessMapped(key, value.getWindowProcessController());
+            mAtmInternal.onProcessMapped(app.pid, app.getWindowProcessController());
         }
 
         /**
@@ -747,11 +747,18 @@
          * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
          * method.
          */
-        void remove(int pid) {
+        void remove(ProcessRecord app) {
+            boolean removed = false;
             synchronized (this) {
-                mPidMap.remove(pid);
+                final ProcessRecord existingApp = mPidMap.get(app.pid);
+                if (existingApp != null && existingApp.startSeq == app.startSeq) {
+                    mPidMap.remove(app.pid);
+                    removed = true;
+                }
             }
-            mAtmInternal.onProcessUnMapped(pid);
+            if (removed) {
+                mAtmInternal.onProcessUnMapped(app.pid);
+            }
         }
 
         /**
@@ -759,17 +766,18 @@
          * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
          * method.
          */
-        boolean removeIfNoThread(int pid) {
+        boolean removeIfNoThread(ProcessRecord app) {
             boolean removed = false;
             synchronized (this) {
-                final ProcessRecord app = get(pid);
-                if (app != null && app.thread == null) {
-                    mPidMap.remove(pid);
+                final ProcessRecord existingApp = get(app.pid);
+                if (existingApp != null && existingApp.startSeq == app.startSeq
+                        && app.thread == null) {
+                    mPidMap.remove(app.pid);
                     removed = true;
                 }
             }
             if (removed) {
-                mAtmInternal.onProcessUnMapped(pid);
+                mAtmInternal.onProcessUnMapped(app.pid);
             }
             return removed;
         }
@@ -1970,7 +1978,7 @@
                 app.getWindowProcessController().setPid(MY_PID);
                 app.maxAdj = ProcessList.SYSTEM_ADJ;
                 app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
-                mPidsSelfLocked.put(app.pid, app);
+                mPidsSelfLocked.put(app);
                 mProcessList.updateLruProcessLocked(app, false, null);
                 updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
             }
@@ -4601,7 +4609,7 @@
     @GuardedBy("this")
     private final void processStartTimedOutLocked(ProcessRecord app) {
         final int pid = app.pid;
-        boolean gone = mPidsSelfLocked.removeIfNoThread(pid);
+        boolean gone = mPidsSelfLocked.removeIfNoThread(app);
 
         if (gone) {
             Slog.w(TAG, "Process " + app + " failed to attach");
@@ -4658,6 +4666,26 @@
             synchronized (mPidsSelfLocked) {
                 app = mPidsSelfLocked.get(pid);
             }
+            if (app != null && (app.startUid != callingUid || app.startSeq != startSeq)) {
+                String processName = null;
+                final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
+                if (pending != null) {
+                    processName = pending.processName;
+                }
+                final String msg = "attachApplicationLocked process:" + processName
+                        + " startSeq:" + startSeq
+                        + " pid:" + pid
+                        + " belongs to another existing app:" + app.processName
+                        + " startSeq:" + app.startSeq;
+                Slog.wtf(TAG, msg);
+                // SafetyNet logging for b/131105245.
+                EventLog.writeEvent(0x534e4554, "131105245", app.startUid, msg);
+                // If there is already an app occupying that pid that hasn't been cleaned up
+                cleanUpApplicationRecordLocked(app, false, false, -1,
+                            true /*replacingPid*/);
+                mPidsSelfLocked.remove(app);
+                app = null;
+            }
         } else {
             app = null;
         }
@@ -4666,7 +4694,7 @@
         // update the internal state.
         if (app == null && startSeq > 0) {
             final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
-            if (pending != null && pending.startUid == callingUid
+            if (pending != null && pending.startUid == callingUid && pending.startSeq == startSeq
                     && mProcessList.handleProcessStartedLocked(pending, pid, pending
                             .isUsingWrapper(),
                             startSeq, true)) {
@@ -13642,7 +13670,7 @@
             return true;
         } else if (app.pid > 0 && app.pid != MY_PID) {
             // Goodbye!
-            mPidsSelfLocked.remove(app.pid);
+            mPidsSelfLocked.remove(app);
             mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
             if (app.isolated) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b394eea..dc94c1e 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1445,10 +1445,11 @@
         long startTime = SystemClock.elapsedRealtime();
         if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
             checkSlow(startTime, "startProcess: removing from pids map");
-            mService.mPidsSelfLocked.remove(app.pid);
+            mService.mPidsSelfLocked.remove(app);
             mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             checkSlow(startTime, "startProcess: done removing from pids map");
             app.setPid(0);
+            app.startSeq = 0;
         }
 
         if (DEBUG_PROCESSES && mService.mProcessesOnHold.contains(app)) Slog.v(
@@ -1656,6 +1657,14 @@
         app.killedByAm = false;
         app.removed = false;
         app.killed = false;
+        if (app.startSeq != 0) {
+            Slog.wtf(TAG, "startProcessLocked processName:" + app.processName
+                    + " with non-zero startSeq:" + app.startSeq);
+        }
+        if (app.pid != 0) {
+            Slog.wtf(TAG, "startProcessLocked processName:" + app.processName
+                    + " with non-zero pid:" + app.pid);
+        }
         final long startSeq = app.startSeq = ++mProcStartSeqCounter;
         app.setStartParams(uid, hostingRecord, seInfo, startTime);
         app.setUsingWrapper(invokeWith != null
@@ -2063,12 +2072,15 @@
         // If there is already an app occupying that pid that hasn't been cleaned up
         if (oldApp != null && !app.isolated) {
             // Clean up anything relating to this pid first
-            Slog.w(TAG, "Reusing pid " + pid
-                    + " while app is still mapped to it");
+            Slog.wtf(TAG, "handleProcessStartedLocked process:" + app.processName
+                    + " startSeq:" + app.startSeq
+                    + " pid:" + pid
+                    + " belongs to another existing app:" + oldApp.processName
+                    + " startSeq:" + oldApp.startSeq);
             mService.cleanUpApplicationRecordLocked(oldApp, false, false, -1,
                     true /*replacingPid*/);
         }
-        mService.mPidsSelfLocked.put(pid, app);
+        mService.mPidsSelfLocked.put(app);
         synchronized (mService.mPidsSelfLocked) {
             if (!procAttached) {
                 Message msg = mService.mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
@@ -2241,7 +2253,7 @@
                 .pendingStart)) {
             int pid = app.pid;
             if (pid > 0) {
-                mService.mPidsSelfLocked.remove(pid);
+                mService.mPidsSelfLocked.remove(app);
                 mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
                 mService.mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
                 if (app.isolated) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index 7ee167a..99f5839 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -120,42 +120,65 @@
                     return 1;
             }
         }
-        final String packageName = getNextArg();
 
+        final String packageName = getNextArg();
+        if (packageName != null) {
+            List<OverlayInfo> overlaysForTarget = mInterface.getOverlayInfosForTarget(
+                    packageName, userId);
+
+            // If the package is not targeted by any overlays, check if the package is an overlay.
+            if (overlaysForTarget.isEmpty()) {
+                final OverlayInfo info = mInterface.getOverlayInfo(packageName, userId);
+                if (info != null) {
+                    printListOverlay(out, info);
+                }
+                return 0;
+            }
+
+            out.println(packageName);
+
+            // Print the overlays for the target.
+            final int n = overlaysForTarget.size();
+            for (int i = 0; i < n; i++) {
+                printListOverlay(out, overlaysForTarget.get(i));
+            }
+
+            return 0;
+        }
+
+        // Print all overlays grouped by target package name.
         final Map<String, List<OverlayInfo>> allOverlays = mInterface.getAllOverlays(userId);
         for (final String targetPackageName : allOverlays.keySet()) {
-            if (targetPackageName.equals(packageName)) {
-                out.println(targetPackageName);
-            }
+            out.println(targetPackageName);
+
             List<OverlayInfo> overlaysForTarget = allOverlays.get(targetPackageName);
             final int n = overlaysForTarget.size();
             for (int i = 0; i < n; i++) {
-                final OverlayInfo oi = overlaysForTarget.get(i);
-                if (!targetPackageName.equals(packageName) && !oi.packageName.equals(packageName)) {
-                    continue;
-                }
-                String status;
-                switch (oi.state) {
-                    case OverlayInfo.STATE_ENABLED_STATIC:
-                    case OverlayInfo.STATE_ENABLED:
-                        status = "[x]";
-                        break;
-                    case OverlayInfo.STATE_DISABLED:
-                        status = "[ ]";
-                        break;
-                    default:
-                        status = "---";
-                        break;
-                }
-                out.println(String.format("%s %s", status, oi.packageName));
+                printListOverlay(out, overlaysForTarget.get(i));
             }
-            if (targetPackageName.equals(packageName)) {
-                out.println();
-            }
+            out.println();
         }
+
         return 0;
     }
 
+    private void printListOverlay(PrintWriter out, OverlayInfo oi) {
+        String status;
+        switch (oi.state) {
+            case OverlayInfo.STATE_ENABLED_STATIC:
+            case OverlayInfo.STATE_ENABLED:
+                status = "[x]";
+                break;
+            case OverlayInfo.STATE_DISABLED:
+                status = "[ ]";
+                break;
+            default:
+                status = "---";
+                break;
+        }
+        out.println(String.format("%s %s", status, oi.packageName));
+    }
+
     private int runEnableDisable(final boolean enable) throws RemoteException {
         final PrintWriter err = getErrPrintWriter();
 
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index fe0b9a6..b7e18c3 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -537,6 +537,7 @@
             Slog.d(TAG, "doAutoBatterySaverLocked: mBootCompleted=" + mBootCompleted
                     + " mSettingsLoaded=" + mSettingsLoaded
                     + " mBatteryStatusSet=" + mBatteryStatusSet
+                    + " mState=" + mState
                     + " mIsBatteryLevelLow=" + mIsBatteryLevelLow
                     + " mIsPowered=" + mIsPowered
                     + " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver
@@ -689,9 +690,9 @@
                 final boolean isStickyDisabled =
                         mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky;
                 if (isStickyDisabled || shouldTurnOffSticky) {
+                    mState = STATE_OFF;
                     setStickyActive(false);
                     triggerStickyDisabledNotification();
-                    mState = STATE_OFF;
                 } else if (!mIsPowered) {
                     // Re-enable BS.
                     enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
@@ -797,7 +798,8 @@
                         Intent.ACTION_POWER_USAGE_SUMMARY));
     }
 
-    private void triggerStickyDisabledNotification() {
+    @VisibleForTesting
+    void triggerStickyDisabledNotification() {
         NotificationManager manager = mContext.getSystemService(NotificationManager.class);
         ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID,
                 R.string.battery_saver_notification_channel_name);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1344727..66b305e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1085,6 +1085,22 @@
         if (root == this) {
             task.setRootProcess(proc);
         }
+        // Override the process configuration to match the display where the first activity in
+        // the process was launched. This can help with compat issues on secondary displays when
+        // apps use Application to obtain configuration or metrics instead of Activity.
+        final ActivityDisplay display = getDisplay();
+        if (display == null || display.mDisplayId == INVALID_DISPLAY) {
+            return;
+        }
+        if (!proc.hasActivities() && display.mDisplayId != DEFAULT_DISPLAY) {
+            proc.registerDisplayConfigurationListenerLocked(display);
+        } else if (display.mDisplayId == DEFAULT_DISPLAY) {
+            // Once an activity is launched on default display - stop listening for other displays
+            // configurations to maintain compatibility with previous platform releases. E.g. when
+            // an activity is launched in a Bubble and then moved to default screen, we should match
+            // the global device config.
+            proc.unregisterDisplayConfigurationListenerLocked();
+        }
     }
 
     boolean hasProcess() {
@@ -3233,7 +3249,7 @@
         // Update last reported values.
         final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
 
-        setLastReportedConfiguration(mAtmService.getGlobalConfiguration(), newMergedOverrideConfig);
+        setLastReportedConfiguration(getProcessGlobalConfiguration(), newMergedOverrideConfig);
 
         if (mState == INITIALIZING) {
             // No need to relaunch or schedule new config for activity that hasn't been launched
@@ -3342,6 +3358,14 @@
         return true;
     }
 
+    /** Get process configuration, or global config if the process is not set. */
+    private Configuration getProcessGlobalConfiguration() {
+        if (app != null) {
+            return app.getConfiguration();
+        }
+        return mAtmService.getGlobalConfiguration();
+    }
+
     /**
      * When assessing a configuration change, decide if the changes flags and the new configurations
      * should cause the Activity to relaunch.
@@ -3449,7 +3473,7 @@
             mStackSupervisor.activityRelaunchingLocked(this);
             final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
                     pendingNewIntents, configChangeFlags,
-                    new MergedConfiguration(mAtmService.getGlobalConfiguration(),
+                    new MergedConfiguration(getProcessGlobalConfiguration(),
                             getMergedOverrideConfiguration()),
                     preserveWindow);
             final ActivityLifecycleItem lifecycleItem;
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 1cdb49d..9d08e10 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -280,13 +280,6 @@
             mActivityOptions = ActivityOptions.makeBasic();
         }
 
-        ActivityRecord homeActivityRecord = mRootActivityContainer.getDefaultDisplayHomeActivity();
-        if (homeActivityRecord != null && homeActivityRecord.getTaskRecord() != null) {
-            // Showing credential confirmation activity in home task to avoid stopping
-            // multi-windowed mode after showing the full-screen credential confirmation activity.
-            mActivityOptions.setLaunchTaskId(homeActivityRecord.getTaskRecord().taskId);
-        }
-
         final UserInfo parent = mUserManager.getProfileParent(mUserId);
         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 89962a5..772e5e6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -39,7 +39,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ApplicationInfo.FLAG_FACTORY_TEST;
 import static android.content.pm.ConfigurationInfo.GL_ES_VERSION_UNDEFINED;
 import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
@@ -6892,15 +6891,9 @@
             synchronized (mGlobalLock) {
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
-                            FLAG_ACTIVITY_TASK_ON_HOME);
-                    ActivityOptions activityOptions = options != null
+                    intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                    final ActivityOptions activityOptions = options != null
                             ? new ActivityOptions(options) : ActivityOptions.makeBasic();
-                    final ActivityRecord homeActivity =
-                            mRootActivityContainer.getDefaultDisplayHomeActivity();
-                    if (homeActivity != null) {
-                        activityOptions.setLaunchTaskId(homeActivity.getTaskRecord().taskId);
-                    }
                     mContext.startActivityAsUser(intent, activityOptions.toBundle(),
                             UserHandle.CURRENT);
                 } finally {
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index ef2a21d..b30da5e 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -819,7 +819,7 @@
         } catch (Settings.SettingNotFoundException e) {
             // Log to SafetyNet for b/127605586
             android.util.EventLog.writeEvent(0x534e4554, "127605586", -1, "");
-            return mLockPatternUtils.isSecure(USER_CURRENT);
+            return getLockPatternUtils().isSecure(USER_CURRENT);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ab5e071..d838691 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -319,7 +319,8 @@
      * Sets the bounds animation target bounds ahead of an animation.  This can't currently be done
      * in onAnimationStart() since that is started on the UiThread.
      */
-    void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds, boolean toFullscreen) {
+    private void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds,
+            boolean toFullscreen) {
         mBoundsAnimatingRequested = true;
         mBoundsAnimatingToFullscreen = toFullscreen;
         if (destBounds != null) {
@@ -329,7 +330,11 @@
         }
         if (sourceHintBounds != null) {
             mBoundsAnimationSourceHintBounds.set(sourceHintBounds);
-        } else {
+        } else if (!mBoundsAnimating) {
+            // If the bounds are already animating, we don't want to reset the source hint. This is
+            // because the source hint is sent when starting the animation from the client that
+            // requested to enter pip. Other requests can adjust the pip bounds during an animation,
+            // but could accidentally reset the source hint bounds.
             mBoundsAnimationSourceHintBounds.setEmpty();
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 12b62b9..5fc3997 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -439,7 +439,10 @@
 
     @Override
     protected ConfigurationContainer getParent() {
-        return null;
+        // Returning RootActivityContainer as the parent, so that this process controller always
+        // has full configuration and overrides (e.g. from display) are always added on top of
+        // global config.
+        return mAtm.mRootActivityContainer;
     }
 
     @HotPath(caller = HotPath.PROCESS_CHANGE)
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5ef184a..c35e866 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3104,7 +3104,7 @@
             if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
                     + ": " + mWindowFrames.mCompatFrame);
             final MergedConfiguration mergedConfiguration =
-                    new MergedConfiguration(mWmService.mRoot.getConfiguration(),
+                    new MergedConfiguration(getProcessGlobalConfiguration(),
                     getMergedOverrideConfiguration());
 
             setLastReportedMergedConfiguration(mergedConfiguration);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index fb34913..1ab3b98 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -349,7 +349,7 @@
                 lastPos++;
             } else {
                 // Two events have the same timestamp, check if they are the same.
-                if (lastEvent.equals(curEvent)) {
+                if (lastEvent.eventEquals(curEvent)) {
                     // Actual overlap, just skip the event.
                     if (DEBUG) Slog.d(TAG, "Skipped dup event with timestamp: " + lastNanos);
                 } else {
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 6517303..77e2517 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -43,6 +43,8 @@
 import static com.android.server.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
 import static com.android.server.AlarmManagerService.Constants.KEY_MIN_FUTURITY;
 import static com.android.server.AlarmManagerService.Constants.KEY_MIN_INTERVAL;
+import static com.android.server.AlarmManagerService.IS_WAKEUP_MASK;
+import static com.android.server.AlarmManagerService.TIME_CHANGED_MASK;
 import static com.android.server.AlarmManagerService.WORKING_INDEX;
 
 import static org.junit.Assert.assertEquals;
@@ -126,13 +128,15 @@
     private MockitoSession mMockingSession;
     private Injector mInjector;
     private volatile long mNowElapsedTest;
+    private volatile long mNowRtcTest;
     @GuardedBy("mTestTimer")
     private TestTimer mTestTimer = new TestTimer();
 
     static class TestTimer {
         private long mElapsed;
         boolean mExpired;
-        int mType;
+        private int mType;
+        private int mFlags; // Flags used to decide what needs to be evaluated.
 
         synchronized long getElapsed() {
             return mElapsed;
@@ -147,7 +151,16 @@
             return mType;
         }
 
+        synchronized int getFlags() {
+            return mFlags;
+        }
+
         synchronized void expire() throws InterruptedException {
+            expire(IS_WAKEUP_MASK); // Default: evaluate eligibility of all alarms
+        }
+
+        synchronized void expire(int flags) throws InterruptedException {
+            mFlags = flags;
             mExpired = true;
             notifyAll();
             // Now wait for the alarm thread to finish execution.
@@ -181,7 +194,7 @@
                 }
                 mTestTimer.mExpired = false;
             }
-            return AlarmManagerService.IS_WAKEUP_MASK; // Doesn't matter, just evaluate.
+            return mTestTimer.getFlags();
         }
 
         @Override
@@ -215,6 +228,11 @@
         }
 
         @Override
+        long getCurrentTimeMillis() {
+            return mNowRtcTest;
+        }
+
+        @Override
         AlarmManagerService.ClockReceiver getClockReceiver(AlarmManagerService service) {
             return mClockReceiver;
         }
@@ -340,7 +358,7 @@
     }
 
     @Test
-    public void testSingleAlarmSet() {
+    public void singleElapsedAlarmSet() {
         final long triggerTime = mNowElapsedTest + 5000;
         final PendingIntent alarmPi = getNewMockPendingIntent();
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, alarmPi);
@@ -348,6 +366,33 @@
     }
 
     @Test
+    public void singleRtcAlarmSet() {
+        mNowElapsedTest = 54;
+        mNowRtcTest = 1243;     // arbitrary values of time
+        final long triggerRtc = mNowRtcTest + 5000;
+        final PendingIntent alarmPi = getNewMockPendingIntent();
+        setTestAlarm(RTC_WAKEUP, triggerRtc, alarmPi);
+        final long triggerElapsed = triggerRtc - (mNowRtcTest - mNowElapsedTest);
+        assertEquals(triggerElapsed, mTestTimer.getElapsed());
+    }
+
+    @Test
+    public void timeChangeMovesRtcAlarm() throws Exception {
+        mNowElapsedTest = 42;
+        mNowRtcTest = 4123;     // arbitrary values of time
+        final long triggerRtc = mNowRtcTest + 5000;
+        final PendingIntent alarmPi = getNewMockPendingIntent();
+        setTestAlarm(RTC_WAKEUP, triggerRtc, alarmPi);
+        final long triggerElapsed1 = mTestTimer.getElapsed();
+        final long timeDelta = -123;
+        mNowRtcTest += timeDelta;
+        mTestTimer.expire(TIME_CHANGED_MASK);
+        final long triggerElapsed2 = mTestTimer.getElapsed();
+        assertEquals("Invalid movement of triggerElapsed following time change", triggerElapsed2,
+                triggerElapsed1 - timeDelta);
+    }
+
+    @Test
     public void testSingleAlarmExpiration() throws Exception {
         final long triggerTime = mNowElapsedTest + 5000;
         final PendingIntent alarmPi = getNewMockPendingIntent();
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 212d2a8..a8faa54 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -15,6 +15,10 @@
  */
 package com.android.server.power.batterysaver;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -22,6 +26,8 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.NotificationManager;
@@ -37,6 +43,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
 
 import java.util.HashMap;
 import java.util.Objects;
@@ -201,6 +208,8 @@
         mDevice = new Device();
 
         mTarget = new TestableBatterySaverStateMachine();
+        spyOn(mTarget);
+        doNothing().when(mTarget).triggerStickyDisabledNotification();
 
         mDevice.pushBatteryStatus();
         mTarget.onBootCompleted();
@@ -423,7 +432,7 @@
         assertEquals(70, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
 
-        // Bump ump the threshold.
+        // Bump up the threshold.
         mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 70);
         mDevice.setBatteryLevel(mPersistedState.batteryLevel);
 
@@ -545,6 +554,8 @@
 
     @Test
     public void testAutoBatterySaver_withSticky_withAutoOffEnabled() {
+        InOrder inOrder = inOrder(mTarget);
+
         mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
         mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
         mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
@@ -569,6 +580,7 @@
         assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
         assertEquals(95, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
+        inOrder.verify(mTarget, never()).triggerStickyDisabledNotification();
 
         // Scenario 2: User turns BS on manually above the threshold then charges device. BS
         // shouldn't turn back on.
@@ -584,6 +596,7 @@
         assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
         assertEquals(97, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
+        inOrder.verify(mTarget).triggerStickyDisabledNotification();
 
         // Scenario 3: User turns BS on manually above the threshold. Device drains below
         // threshold and then charged to below threshold. Sticky BS should activate.
@@ -612,6 +625,7 @@
         assertEquals(true, mDevice.batterySaverEnabled);
         assertEquals(30, mPersistedState.batteryLevel);
         assertEquals(true, mPersistedState.batteryLow);
+        inOrder.verify(mTarget, never()).triggerStickyDisabledNotification();
 
         // Scenario 4: User turns BS on manually above the threshold. Device drains below
         // threshold and is eventually charged to above threshold. Sticky BS should turn off.
@@ -627,6 +641,7 @@
         assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
         assertEquals(90, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
+        inOrder.verify(mTarget).triggerStickyDisabledNotification();
 
         // Scenario 5: User turns BS on manually below threshold and charges to below threshold.
         // Sticky BS should activate.
@@ -654,6 +669,7 @@
         assertEquals(true, mDevice.batterySaverEnabled); // Sticky BS still on.
         assertEquals(80, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
+        inOrder.verify(mTarget, never()).triggerStickyDisabledNotification();
 
         // Scenario 6: User turns BS on manually below threshold and eventually charges to above
         // threshold. Sticky BS should turn off.
@@ -665,6 +681,7 @@
         assertEquals(false, mDevice.batterySaverEnabled);
         assertEquals(95, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
+        inOrder.verify(mTarget).triggerStickyDisabledNotification();
 
         // Scenario 7: User turns BS on above threshold and then reboots device. Sticky BS
         // shouldn't activate.
@@ -676,6 +693,8 @@
         assertEquals(false, mDevice.batterySaverEnabled);
         assertEquals(93, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
+        // initDevice() changes the mTarget reference, so inOrder is invalid here.
+        verify(mTarget).triggerStickyDisabledNotification();
 
         // Scenario 8: User turns BS on below threshold and then reboots device without charging.
         // Sticky BS should activate.
@@ -690,6 +709,8 @@
         assertEquals(true, mDevice.batterySaverEnabled);
         assertEquals(75, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
+        // initDevice() changes the mTarget reference, so inOrder is invalid here.
+        verify(mTarget, never()).triggerStickyDisabledNotification();
 
         // Scenario 9: User turns BS on below threshold and then reboots device after charging
         // above threshold. Sticky BS shouldn't activate.
@@ -702,6 +723,8 @@
         assertEquals(false, mDevice.batterySaverEnabled);
         assertEquals(100, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
+        // initDevice() changes the mTarget reference, so inOrder is invalid here.
+        verify(mTarget).triggerStickyDisabledNotification();
 
         // Scenario 10: Somehow autoDisableLevel is set to a value below lowPowerModeTriggerLevel
         // and then user enables manually above both thresholds, discharges below
@@ -738,6 +761,8 @@
         assertEquals(true, mDevice.batterySaverEnabled);
         assertEquals(65, mPersistedState.batteryLevel);
         assertEquals(true, mPersistedState.batteryLow);
+        // initDevice() changes the mTarget reference, so inOrder is invalid here.
+        verify(mTarget, never()).triggerStickyDisabledNotification();
     }
 
     @Test
@@ -780,6 +805,7 @@
         assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
         assertEquals(95, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
+        verify(mTarget).triggerStickyDisabledNotification();
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 11a177a..f8fd64a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_90;
@@ -38,6 +40,7 @@
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -56,10 +59,10 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.util.MergedConfiguration;
 import android.util.MutableBoolean;
+import android.view.DisplayInfo;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner.Stub;
 import android.view.RemoteAnimationAdapter;
@@ -598,6 +601,67 @@
         assertNull(mActivity.pendingOptions);
     }
 
+    @Test
+    public void testSetProcessOverridesConfig() {
+        final ActivityRecord defaultDisplayActivity =
+                createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
+        assertFalse(defaultDisplayActivity.app.registeredForDisplayConfigChanges());
+
+        final ActivityRecord secondaryDisplayActivity =
+                createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
+        assertTrue(secondaryDisplayActivity.app.registeredForDisplayConfigChanges());
+        assertEquals(secondaryDisplayActivity.getDisplay().getResolvedOverrideConfiguration(),
+                secondaryDisplayActivity.app.getRequestedOverrideConfiguration());
+
+        assertNotEquals(defaultDisplayActivity.getConfiguration(),
+                secondaryDisplayActivity.getConfiguration());
+    }
+
+    @Test
+    public void testSetProcessDoesntOverrideConfigIfAnotherActivityPresent() {
+        final ActivityRecord defaultDisplayActivity =
+                createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
+        assertFalse(defaultDisplayActivity.app.registeredForDisplayConfigChanges());
+
+        final ActivityRecord secondaryDisplayActivity =
+                createActivityOnDisplay(false /* defaultDisplay */, defaultDisplayActivity.app);
+        assertFalse(secondaryDisplayActivity.app.registeredForDisplayConfigChanges());
+    }
+
+    @Test
+    public void testActivityOnDefaultDisplayClearsProcessOverride() {
+        final ActivityRecord secondaryDisplayActivity =
+                createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
+        assertTrue(secondaryDisplayActivity.app.registeredForDisplayConfigChanges());
+
+        final ActivityRecord defaultDisplayActivity =
+                createActivityOnDisplay(true /* defaultDisplay */,
+                        secondaryDisplayActivity.app);
+        assertFalse(defaultDisplayActivity.app.registeredForDisplayConfigChanges());
+        assertFalse(secondaryDisplayActivity.app.registeredForDisplayConfigChanges());
+    }
+
+    /**
+     * Creates an activity on display. For non-default display request it will also create a new
+     * display with custom DisplayInfo.
+     */
+    private ActivityRecord createActivityOnDisplay(boolean defaultDisplay,
+            WindowProcessController process) {
+        final ActivityDisplay display;
+        if (defaultDisplay) {
+            display = mRootActivityContainer.getDefaultDisplay();
+        } else {
+            final DisplayInfo info = new DisplayInfo();
+            info.logicalWidth = 100;
+            info.logicalHeight = 100;
+            display = addNewActivityDisplayAt(info, POSITION_TOP);
+        }
+        final TestActivityStack stack = display.createStack(WINDOWING_MODE_UNDEFINED,
+                ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+        return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build();
+    }
+
     /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
     private void prepareFixedAspectRatioUnresizableActivity() {
         setupDisplayContentForCompatDisplayInsets();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 53b0add..d8c0de7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -195,6 +195,7 @@
         private ActivityStack mStack;
         private int mActivityFlags;
         private int mLaunchMode;
+        private WindowProcessController mWpc;
 
         ActivityBuilder(ActivityTaskManagerService service) {
             mService = service;
@@ -245,6 +246,11 @@
             return this;
         }
 
+        ActivityBuilder setUseProcess(WindowProcessController wpc) {
+            mWpc = wpc;
+            return this;
+        }
+
         ActivityRecord build() {
             if (mComponent == null) {
                 final int id = sCurrentActivityId++;
@@ -290,12 +296,18 @@
                 mTaskRecord.addActivityToTop(activity);
             }
 
-            final WindowProcessController wpc = new WindowProcessController(mService,
-                    mService.mContext.getApplicationInfo(), "name", 12345,
-                    UserHandle.getUserId(12345), mock(Object.class),
-                    mock(WindowProcessListener.class));
-            wpc.setThread(mock(IApplicationThread.class));
+            final WindowProcessController wpc;
+            if (mWpc != null) {
+                wpc = mWpc;
+            } else {
+                wpc = new WindowProcessController(mService,
+                        mService.mContext.getApplicationInfo(), "name", 12345,
+                        UserHandle.getUserId(12345), mock(Object.class),
+                        mock(WindowProcessListener.class));
+                wpc.setThread(mock(IApplicationThread.class));
+            }
             activity.setProcess(wpc);
+            wpc.addActivityIfNeeded(activity);
             return activity;
         }
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index fe45411..8528954 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -153,7 +153,6 @@
     @FlakyTest(bugId = 131005232)
     public void testLandscapeSeascapeRotationByApp() {
         // Some plumbing to get the service ready for rotation updates.
-        mWm.mDisplayReady = true;
         mWm.mDisplayEnabled = true;
 
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
@@ -186,7 +185,6 @@
     @Test
     public void testLandscapeSeascapeRotationByPolicy() {
         // Some plumbing to get the service ready for rotation updates.
-        mWm.mDisplayReady = true;
         mWm.mDisplayEnabled = true;
 
         final DisplayRotation spiedRotation = spy(mDisplayContent.getDisplayRotation());
@@ -379,6 +377,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 131176283)
     public void testCreateRemoveStartingWindow() {
         mToken.addStartingWindow(mPackageName,
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 366acea..427a929 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -41,6 +41,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManagerInternal;
 import android.net.Uri;
@@ -175,6 +176,12 @@
         // Display creation is driven by the ActivityManagerService via
         // ActivityStackSupervisor. We emulate those steps here.
         mWindowManagerService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
+        mWindowManagerService.displayReady();
+
+        final Configuration defaultDisplayConfig =
+                mWindowManagerService.computeNewConfiguration(DEFAULT_DISPLAY);
+        doReturn(defaultDisplayConfig).when(atms).getGlobalConfiguration();
+        doReturn(defaultDisplayConfig).when(atms).getGlobalConfigurationForPid(anyInt());
 
         mMockTracker.stopTracking();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index a7c84a1..7b8fba0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -26,7 +26,9 @@
 import static org.mockito.Mockito.mock;
 
 import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
 import android.platform.test.annotations.Presubmit;
+import android.view.DisplayInfo;
 
 import org.junit.Test;
 
@@ -78,6 +80,26 @@
         assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
     }
 
+    @Test
+    public void testConfigurationForSecondaryScreen() {
+        final WindowProcessController wpc = new WindowProcessController(
+                mService, mock(ApplicationInfo.class), null, 0, -1, null, null);
+        //By default, the process should not listen to any display.
+        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+
+        // Register to a new display as a listener.
+        final DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = 100;
+        info.logicalHeight = 100;
+        TestActivityDisplay display = addNewActivityDisplayAt(info, WindowContainer.POSITION_TOP);
+        wpc.registerDisplayConfigurationListenerLocked(display);
+
+        assertEquals(display.mDisplayId, wpc.getDisplayId());
+        final Configuration expectedConfig = mService.mRootActivityContainer.getConfiguration();
+        expectedConfig.updateFrom(display.getConfiguration());
+        assertEquals(expectedConfig, wpc.getConfiguration());
+    }
+
     private TestActivityDisplay createTestActivityDisplayInContainer() {
         final TestActivityDisplay testActivityDisplay = createNewActivityDisplay();
         mRootActivityContainer.addChild(testActivityDisplay, POSITION_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 3a702cb9..de28b5f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -154,7 +154,6 @@
             context.getDisplay().getDisplayInfo(mDisplayInfo);
             mDisplayContent = createNewDisplay();
             mWm.mDisplayEnabled = true;
-            mWm.mDisplayReady = true;
 
             // Set-up some common windows.
             mCommonWindows = new HashSet<>();
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 14ae689..9d732ba 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntRange;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -46,7 +47,7 @@
     private int mRssi; // in dBm [-113, -51] or UNAVAILABLE
     @UnsupportedAppUsage
     private int mBitErrorRate; // bit error rate (0-7, 99) TS 27.007 8.5 or UNAVAILABLE
-    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private int mTimingAdvance; // range from 0-219 or CellInfo.UNAVAILABLE if unknown
     private int mLevel;
 
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index f191f6c..6683e2a 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -490,11 +490,6 @@
 def flag_sequence(territory_code):
     return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code)
 
-UNSUPPORTED_FLAGS = frozenset({
-    flag_sequence('BL'), flag_sequence('BQ'), flag_sequence('MQ'),
-    flag_sequence('RE'), flag_sequence('TF'),
-})
-
 EQUIVALENT_FLAGS = {
     flag_sequence('BV'): flag_sequence('NO'),
     flag_sequence('CP'): flag_sequence('FR'),
@@ -600,9 +595,6 @@
     for first, second in SAME_FLAG_MAPPINGS:
         equivalent_emoji[first] = second
 
-    # Remove unsupported flags
-    all_sequences.difference_update(UNSUPPORTED_FLAGS)
-
     # Add all tag characters used in flags
     sequence_pieces.update(range(0xE0030, 0xE0039 + 1))
     sequence_pieces.update(range(0xE0061, 0xE007A + 1))