Merge "Remove StructGroupSourceReq" into oc-mr1-dev-plus-aosp
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index e2b4edf..df68f14 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -5242,7 +5242,6 @@
 com.android.internal.app.IVoiceInteractor$Stub
 com.android.internal.app.NightDisplayController
 com.android.internal.app.NightDisplayController$Callback
-com.android.internal.app.NightDisplayController$LocalTime
 com.android.internal.app.ProcessMap
 com.android.internal.app.ResolverActivity
 com.android.internal.app.ToolbarActionBar
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 4f83531..0539942 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2783,7 +2783,6 @@
 com.android.internal.app.IVoiceInteractor
 com.android.internal.app.IVoiceInteractor$Stub
 com.android.internal.app.NightDisplayController
-com.android.internal.app.NightDisplayController$1
 com.android.internal.appwidget.IAppWidgetService
 com.android.internal.appwidget.IAppWidgetService$Stub
 com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index bf9bd79..a3b3a9f 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -175,6 +175,9 @@
                 }
                 if (result != null) {
                     response.onResult(result);
+                } else {
+                    response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                            "null bundle returned");
                 }
             } catch (Exception e) {
                 handleException(response, "addAccount", accountType, e);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index dd6ad55..bd9c9fa 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2321,6 +2321,10 @@
         private class Response extends IAccountManagerResponse.Stub {
             @Override
             public void onResult(Bundle bundle) {
+                if (bundle == null) {
+                    onError(ERROR_CODE_INVALID_RESPONSE, "null bundle returned");
+                    return;
+                }
                 Intent intent = bundle.getParcelable(KEY_INTENT);
                 if (intent != null && mActivity != null) {
                     // since the user provided an Activity we will silently start intents
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 897e42b..1811748 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -308,7 +308,15 @@
     boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
     boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
             in Intent resultData);
-    void setLockScreenShown(boolean showing);
+    /**
+     * Informs ActivityManagerService that the keyguard is showing.
+     *
+     * @param showing True if the keyguard is showing, false otherwise.
+     * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard
+     *        is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if
+     *        showing is true.
+     */
+    void setLockScreenShown(boolean showing, int secondaryDisplayShowing);
     boolean finishActivityAffinity(in IBinder token);
     // This is not public because you need to be very careful in how you
     // manage your activity to make sure it is always the uid you expect.
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index ac6d83f..2623830 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -287,8 +287,10 @@
         mPublisher = in.readString();
         mName = in.readString();
 
+        mHandle = in.readInt();
         mAppId = in.readLong();
         mAppVersion = in.readInt();
+        mContexthubId = in.readInt();
         mNeededReadMemBytes = in.readInt();
         mNeededWriteMemBytes = in.readInt();
         mNeededExecMemBytes = in.readInt();
@@ -309,6 +311,8 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mPublisher);
         out.writeString(mName);
+
+        out.writeInt(mHandle);
         out.writeLong(mAppId);
         out.writeInt(mAppVersion);
         out.writeInt(mContexthubId);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 80766f0..4438edb 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6945,8 +6945,9 @@
         public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
 
         /**
-         * Time in milliseconds (since epoch) when Night display was last activated. Use to decide
-         * whether to apply the current activated state after a reboot or user change.
+         * A String representing the LocalDateTime when Night display was last activated. Use to
+         * decide whether to apply the current activated state after a reboot or user change. In
+         * legacy cases, this is represented by the time in milliseconds (since epoch).
          * @hide
          */
         public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME =
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index cac27af..462dad3 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -231,6 +231,7 @@
         updateRequestedVisibility();
 
         mAttachedToWindow = true;
+        mParent.requestTransparentRegion(SurfaceView.this);
         if (!mGlobalListenersAdded) {
             ViewTreeObserver observer = getViewTreeObserver();
             observer.addOnScrollChangedListener(mScrollChangedListener);
@@ -269,8 +270,6 @@
         if (mPendingReportDraws > 0) {
             mDrawFinished = true;
             if (mAttachedToWindow) {
-                mParent.requestTransparentRegion(SurfaceView.this);
-                
                 notifyDrawFinished();
                 invalidate();
             }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 27eeb2e..f888ba2 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -37,7 +37,6 @@
 import android.service.autofill.FillEventHistory;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.DebugUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
@@ -202,9 +201,12 @@
      * Initial state of the autofill context, set when there is no session (i.e., when
      * {@link #mSessionId} is {@link #NO_SESSION}).
      *
+     * <p>In this state, app callbacks (such as {@link #notifyViewEntered(View)}) are notified to
+     * the server.
+     *
      * @hide
      */
-    public static final int STATE_UNKNOWN = 1;
+    public static final int STATE_UNKNOWN = 0;
 
     /**
      * State where the autofill context hasn't been {@link #commit() finished} nor
@@ -212,7 +214,18 @@
      *
      * @hide
      */
-    public static final int STATE_ACTIVE = 2;
+    public static final int STATE_ACTIVE = 1;
+
+    /**
+     * State where the autofill context was finished by the server because the autofill
+     * service could not autofill the page.
+     *
+     * <p>In this state, most apps callback (such as {@link #notifyViewEntered(View)}) are ignored,
+     * exception {@link #requestAutofill(View)} (and {@link #requestAutofill(View, int, Rect)}).
+     *
+     * @hide
+     */
+    public static final int STATE_FINISHED = 2;
 
     /**
      * State where the autofill context has been {@link #commit() finished} but the server still has
@@ -220,7 +233,7 @@
      *
      * @hide
      */
-    public static final int STATE_SHOWING_SAVE_UI = 4;
+    public static final int STATE_SHOWING_SAVE_UI = 3;
 
     /**
      * Makes an authentication id from a request id and a dataset id.
@@ -559,6 +572,14 @@
         }
         AutofillCallback callback = null;
         synchronized (mLock) {
+            if (isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
+                if (sVerbose) {
+                    Log.v(TAG, "notifyViewEntered(flags=" + flags + ", view=" + view
+                            + "): ignored on state " + getStateAsStringLocked());
+                }
+                return;
+            }
+
             ensureServiceClientAddedIfNeededLocked();
 
             if (!mEnabled) {
@@ -682,6 +703,14 @@
         }
         AutofillCallback callback = null;
         synchronized (mLock) {
+            if (isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
+                if (sVerbose) {
+                    Log.v(TAG, "notifyViewEntered(flags=" + flags + ", view=" + view
+                            + ", virtualId=" + virtualId
+                            + "): ignored on state " + getStateAsStringLocked());
+                }
+                return;
+            }
             ensureServiceClientAddedIfNeededLocked();
 
             if (!mEnabled) {
@@ -765,6 +794,10 @@
             }
 
             if (!mEnabled || !isActiveLocked()) {
+                if (sVerbose && mEnabled) {
+                    Log.v(TAG, "notifyValueChanged(" + view + "): ignoring on state "
+                            + getStateAsStringLocked());
+                }
                 return;
             }
 
@@ -950,10 +983,13 @@
             @NonNull AutofillValue value, int flags) {
         if (sVerbose) {
             Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
-                    + ", flags=" + flags + ", state=" + mState);
+                    + ", flags=" + flags + ", state=" + getStateAsStringLocked());
         }
-        if (mState != STATE_UNKNOWN) {
-            if (sDebug) Log.d(TAG, "not starting session for " + id + " on state " + mState);
+        if (mState != STATE_UNKNOWN && (flags & FLAG_MANUAL_REQUEST) == 0) {
+            if (sVerbose) {
+                Log.v(TAG, "not automatically starting session for " + id
+                        + " on state " + getStateAsStringLocked());
+            }
             return;
         }
         try {
@@ -973,7 +1009,7 @@
     }
 
     private void finishSessionLocked() {
-        if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + mState);
+        if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + getStateAsStringLocked());
 
         if (!isActiveLocked()) return;
 
@@ -987,7 +1023,7 @@
     }
 
     private void cancelSessionLocked() {
-        if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + mState);
+        if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + getStateAsStringLocked());
 
         if (!isActiveLocked()) return;
 
@@ -1306,6 +1342,14 @@
         }
     }
 
+    private void setSessionFinished() {
+        if (sVerbose) Log.v(TAG, "setSessionFinished()");
+        synchronized (mLock) {
+            resetSessionLocked();
+            mState = STATE_FINISHED;
+        }
+    }
+
     private void requestHideFillUi(AutofillId id) {
         final View anchor = findView(id);
         if (sVerbose) Log.v(TAG, "requestHideFillUi(" + id + "): anchor = " + anchor);
@@ -1341,7 +1385,11 @@
         }
     }
 
-    private void notifyNoFillUi(int sessionId, AutofillId id) {
+    private void notifyNoFillUi(int sessionId, AutofillId id, boolean sessionFinished) {
+        if (sVerbose) {
+            Log.v(TAG, "notifyNoFillUi(): sessionId=" + sessionId + ", autofillId=" + id
+                    + ", finished=" + sessionFinished);
+        }
         final View anchor = findView(id);
         if (anchor == null) {
             return;
@@ -1361,7 +1409,11 @@
             } else {
                 callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
             }
+        }
 
+        if (sessionFinished) {
+            // Callback call was "hijacked" to also update the session state.
+            setSessionFinished();
         }
     }
 
@@ -1434,8 +1486,7 @@
         pw.print(outerPrefix); pw.println("AutofillManager:");
         final String pfx = outerPrefix + "  ";
         pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
-        pw.print(pfx); pw.print("state: "); pw.println(
-                DebugUtils.flagsToString(AutofillManager.class, "STATE_", mState));
+        pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
         pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
         pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
         pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
@@ -1452,10 +1503,29 @@
         pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
     }
 
+    private String getStateAsStringLocked() {
+        switch (mState) {
+            case STATE_UNKNOWN:
+                return "STATE_UNKNOWN";
+            case STATE_ACTIVE:
+                return "STATE_ACTIVE";
+            case STATE_FINISHED:
+                return "STATE_FINISHED";
+            case STATE_SHOWING_SAVE_UI:
+                return "STATE_SHOWING_SAVE_UI";
+            default:
+                return "INVALID:" + mState;
+        }
+    }
+
     private boolean isActiveLocked() {
         return mState == STATE_ACTIVE;
     }
 
+    private boolean isFinishedLocked() {
+        return mState == STATE_FINISHED;
+    }
+
     private void post(Runnable runnable) {
         final AutofillClient client = getClientLocked();
         if (client == null) {
@@ -1787,10 +1857,10 @@
         }
 
         @Override
-        public void notifyNoFillUi(int sessionId, AutofillId id) {
+        public void notifyNoFillUi(int sessionId, AutofillId id, boolean sessionFinished) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() -> afm.notifyNoFillUi(sessionId, id));
+                afm.post(() -> afm.notifyNoFillUi(sessionId, id, sessionFinished));
             }
         }
 
@@ -1823,7 +1893,15 @@
         public void setSaveUiState(int sessionId, boolean shown) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() ->afm.setSaveUiState(sessionId, shown));
+                afm.post(() -> afm.setSaveUiState(sessionId, shown));
+            }
+        }
+
+        @Override
+        public void setSessionFinished() {
+            final AutofillManager afm = mAfm.get();
+            if (afm != null) {
+                afm.post(() -> afm.setSessionFinished());
             }
         }
     }
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 0eae858..db6855a 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -67,9 +67,9 @@
     void requestHideFillUi(int sessionId, in AutofillId id);
 
     /**
-     * Notifies no fill UI will be shown.
+     * Notifies no fill UI will be shown, and also mark the state as finished if necessary.
      */
-    void notifyNoFillUi(int sessionId, in AutofillId id);
+    void notifyNoFillUi(int sessionId, in AutofillId id, boolean sessionFinished);
 
     /**
      * Starts the provided intent sender.
@@ -80,4 +80,10 @@
      * Sets the state of the Autofill Save UI for a given session.
      */
    void setSaveUiState(int sessionId, boolean shown);
+
+   /**
+     * Marks the state of the session as finished (because the AutofillService returned a null
+     * FillResponse).
+     */
+   void setSessionFinished();
 }
diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java
index 860c5c4..7a1383c 100644
--- a/core/java/com/android/internal/app/NightDisplayController.java
+++ b/core/java/com/android/internal/app/NightDisplayController.java
@@ -32,8 +32,12 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Calendar;
-import java.util.Locale;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeParseException;
 
 /**
  * Controller for managing Night display settings.
@@ -116,8 +120,9 @@
      */
     public boolean setActivated(boolean activated) {
         if (isActivated() != activated) {
-            Secure.putLongForUser(mContext.getContentResolver(),
-                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, System.currentTimeMillis(),
+            Secure.putStringForUser(mContext.getContentResolver(),
+                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                    LocalDateTime.now().toString(),
                     mUserId);
         }
         return Secure.putIntForUser(mContext.getContentResolver(),
@@ -128,17 +133,22 @@
      * Returns the time when Night display's activation state last changed, or {@code null} if it
      * has never been changed.
      */
-    public Calendar getLastActivatedTime() {
+    public LocalDateTime getLastActivatedTime() {
         final ContentResolver cr = mContext.getContentResolver();
-        final long lastActivatedTimeMillis = Secure.getLongForUser(
-                cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1, mUserId);
-        if (lastActivatedTimeMillis < 0) {
-            return null;
+        final String lastActivatedTime = Secure.getStringForUser(
+                cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, mUserId);
+        if (lastActivatedTime != null) {
+            try {
+                return LocalDateTime.parse(lastActivatedTime);
+            } catch (DateTimeParseException ignored) {}
+            // Uses the old epoch time.
+            try {
+                return LocalDateTime.ofInstant(
+                    Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
+                    ZoneId.systemDefault());
+            } catch (DateTimeException|NumberFormatException ignored) {}
         }
-
-        final Calendar lastActivatedTime = Calendar.getInstance();
-        lastActivatedTime.setTimeInMillis(lastActivatedTimeMillis);
-        return lastActivatedTime;
+        return null;
     }
 
     /**
@@ -183,8 +193,10 @@
         }
 
         if (getAutoMode() != autoMode) {
-            Secure.putLongForUser(mContext.getContentResolver(),
-                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1L, mUserId);
+            Secure.putStringForUser(mContext.getContentResolver(),
+                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                    null,
+                    mUserId);
         }
         return Secure.putIntForUser(mContext.getContentResolver(),
                 Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
@@ -206,7 +218,7 @@
                     R.integer.config_defaultNightDisplayCustomStartTime);
         }
 
-        return LocalTime.valueOf(startTimeValue);
+        return LocalTime.ofSecondOfDay(startTimeValue / 1000);
     }
 
     /**
@@ -221,7 +233,7 @@
             throw new IllegalArgumentException("startTime cannot be null");
         }
         return Secure.putIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toMillis(), mUserId);
+                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toSecondOfDay() * 1000, mUserId);
     }
 
     /**
@@ -240,7 +252,7 @@
                     R.integer.config_defaultNightDisplayCustomEndTime);
         }
 
-        return LocalTime.valueOf(endTimeValue);
+        return LocalTime.ofSecondOfDay(endTimeValue / 1000);
     }
 
     /**
@@ -255,7 +267,7 @@
             throw new IllegalArgumentException("endTime cannot be null");
         }
         return Secure.putIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toMillis(), mUserId);
+                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toSecondOfDay() * 1000, mUserId);
     }
 
     /**
@@ -379,106 +391,6 @@
     }
 
     /**
-     * A time without a time-zone or date.
-     */
-    public static class LocalTime {
-
-        /**
-         * The hour of the day from 0 - 23.
-         */
-        public final int hourOfDay;
-        /**
-         * The minute within the hour from 0 - 59.
-         */
-        public final int minute;
-
-        public LocalTime(int hourOfDay, int minute) {
-            if (hourOfDay < 0 || hourOfDay > 23) {
-                throw new IllegalArgumentException("Invalid hourOfDay: " + hourOfDay);
-            } else if (minute < 0 || minute > 59) {
-                throw new IllegalArgumentException("Invalid minute: " + minute);
-            }
-
-            this.hourOfDay = hourOfDay;
-            this.minute = minute;
-        }
-
-        /**
-         * Returns the first date time corresponding to this local time that occurs before the
-         * provided date time.
-         *
-         * @param time the date time to compare against
-         * @return the prior date time corresponding to this local time
-         */
-        public Calendar getDateTimeBefore(Calendar time) {
-            final Calendar c = Calendar.getInstance();
-            c.set(Calendar.YEAR, time.get(Calendar.YEAR));
-            c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
-
-            c.set(Calendar.HOUR_OF_DAY, hourOfDay);
-            c.set(Calendar.MINUTE, minute);
-            c.set(Calendar.SECOND, 0);
-            c.set(Calendar.MILLISECOND, 0);
-
-            // Check if the local time has past, if so return the same time tomorrow.
-            if (c.after(time)) {
-                c.add(Calendar.DATE, -1);
-            }
-
-            return c;
-        }
-
-        /**
-         * Returns the first date time corresponding to this local time that occurs after the
-         * provided date time.
-         *
-         * @param time the date time to compare against
-         * @return the next date time corresponding to this local time
-         */
-        public Calendar getDateTimeAfter(Calendar time) {
-            final Calendar c = Calendar.getInstance();
-            c.set(Calendar.YEAR, time.get(Calendar.YEAR));
-            c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
-
-            c.set(Calendar.HOUR_OF_DAY, hourOfDay);
-            c.set(Calendar.MINUTE, minute);
-            c.set(Calendar.SECOND, 0);
-            c.set(Calendar.MILLISECOND, 0);
-
-            // Check if the local time has past, if so return the same time tomorrow.
-            if (c.before(time)) {
-                c.add(Calendar.DATE, 1);
-            }
-
-            return c;
-        }
-
-        /**
-         * Returns a local time corresponding the given number of milliseconds from midnight.
-         *
-         * @param millis the number of milliseconds from midnight
-         * @return the corresponding local time
-         */
-        private static LocalTime valueOf(int millis) {
-            final int hourOfDay = (millis / 3600000) % 24;
-            final int minutes = (millis / 60000) % 60;
-            return new LocalTime(hourOfDay, minutes);
-        }
-
-        /**
-         * Returns the local time represented as milliseconds from midnight.
-         */
-        private int toMillis() {
-            return hourOfDay * 3600000 + minute * 60000;
-        }
-
-        @Override
-        public String toString() {
-            return String.format(Locale.US, "%02d:%02d", hourOfDay, minute);
-        }
-    }
-
-    /**
      * Callback invoked whenever the Night display settings are changed.
      */
     public interface Callback {
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 3a77195..afb1193 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -40,7 +40,7 @@
 
 constexpr int sHistogramSize = ProfileData::HistogramSize();
 
-static void mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
+static bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
         const std::string& package, int versionCode, int64_t startTime, int64_t endTime,
         const ProfileData* data);
 static void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd);
@@ -159,7 +159,7 @@
     return success;
 }
 
-void mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
+bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
         int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
     if (proto->stats_start() == 0 || proto->stats_start() > startTime) {
         proto->set_stats_start(startTime);
@@ -188,23 +188,31 @@
         proto->mutable_histogram()->Reserve(sHistogramSize);
         creatingHistogram = true;
     } else if (proto->histogram_size() != sHistogramSize) {
-        LOG_ALWAYS_FATAL("Histogram size mismatch, proto is %d expected %d",
+        ALOGE("Histogram size mismatch, proto is %d expected %d",
                 proto->histogram_size(), sHistogramSize);
+        return false;
     }
     int index = 0;
+    bool hitMergeError = false;
     data->histogramForEach([&](ProfileData::HistogramEntry entry) {
+        if (hitMergeError) return;
+
         service::GraphicsStatsHistogramBucketProto* bucket;
         if (creatingHistogram) {
             bucket = proto->add_histogram();
             bucket->set_render_millis(entry.renderTimeMs);
         } else {
             bucket = proto->mutable_histogram(index);
-            LOG_ALWAYS_FATAL_IF(bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs),
-                    "Frame time mistmatch %d vs. %u", bucket->render_millis(), entry.renderTimeMs);
+            if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) {
+                ALOGW("Frame time mistmatch %d vs. %u", bucket->render_millis(), entry.renderTimeMs);
+                hitMergeError = true;
+                return;
+            }
         }
         bucket->set_frame_count(bucket->frame_count() + entry.frameCount);
         index++;
     });
+    return !hitMergeError;
 }
 
 static int32_t findPercentile(service::GraphicsStatsProto* proto, int percentile) {
@@ -221,9 +229,11 @@
 
 void dumpAsTextToFd(service::GraphicsStatsProto* proto, int fd) {
     // This isn't a full validation, just enough that we can deref at will
-    LOG_ALWAYS_FATAL_IF(proto->package_name().empty()
-            || !proto->has_summary(), "package_name() '%s' summary %d",
-            proto->package_name().c_str(), proto->has_summary());
+    if (proto->package_name().empty() || !proto->has_summary()) {
+        ALOGW("Skipping dump, invalid package_name() '%s' or summary %d",
+                proto->package_name().c_str(), proto->has_summary());
+        return;
+    }
     dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
     dprintf(fd, "\nVersion: %d", proto->version_code());
     dprintf(fd, "\nStats since: %lldns", proto->stats_start());
@@ -254,14 +264,20 @@
     if (!parseFromFile(path, &statsProto)) {
         statsProto.Clear();
     }
-    mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data);
+    if (!mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data)) {
+        return;
+    }
     // Although we might not have read any data from the file, merging the existing data
     // should always fully-initialize the proto
-    LOG_ALWAYS_FATAL_IF(!statsProto.IsInitialized(), "%s",
-            statsProto.InitializationErrorString().c_str());
-    LOG_ALWAYS_FATAL_IF(statsProto.package_name().empty()
-            || !statsProto.has_summary(), "package_name() '%s' summary %d",
-            statsProto.package_name().c_str(), statsProto.has_summary());
+    if (!statsProto.IsInitialized()) {
+        ALOGE("proto initialization error %s", statsProto.InitializationErrorString().c_str());
+        return;
+    }
+    if (statsProto.package_name().empty() || !statsProto.has_summary()) {
+        ALOGE("missing package_name() '%s' summary %d",
+                statsProto.package_name().c_str(), statsProto.has_summary());
+        return;
+    }
     int outFd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0660);
     if (outFd <= 0) {
         int err = errno;
@@ -312,8 +328,9 @@
     if (!path.empty() && !parseFromFile(path, &statsProto)) {
         statsProto.Clear();
     }
-    if (data) {
-        mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data);
+    if (data && !mergeProfileDataIntoProto(
+            &statsProto, package, versionCode, startTime, endTime, data)) {
+        return;
     }
     if (!statsProto.IsInitialized()) {
         ALOGW("Failed to load profile data from path '%s' and data %p",
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 2894e89..b072f65 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -202,7 +202,6 @@
                 audioRoutesChanged = true;
             }
 
-            final int mainType = mCurAudioRoutesInfo.mainType;
             if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
                 mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
                 if (mCurAudioRoutesInfo.bluetoothName != null) {
@@ -229,8 +228,11 @@
             }
 
             if (audioRoutesChanged) {
-                selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
                 Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
+                if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo
+                        || mSelectedRoute == mBluetoothA2dpRoute) {
+                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
+                }
             }
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index ba9c9e7..6e676bc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -26,7 +26,6 @@
 import android.content.res.Resources;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -327,6 +326,15 @@
             Context context, UserHandle user, Intent intent,
             Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
             boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon) {
+        getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
+                usePriority, checkCategory, forceTintExternalIcon, false /* shouldUpdateTiles */);
+    }
+
+    public static void getTilesForIntent(
+            Context context, UserHandle user, Intent intent,
+            Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
+            boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon,
+            boolean shouldUpdateTiles) {
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                 PackageManager.GET_META_DATA, user.getIdentifier());
@@ -364,9 +372,11 @@
                 updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
                         pm, providerMap, forceTintExternalIcon);
                 if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);
-
                 addedCache.put(key, tile);
+            } else if (shouldUpdateTiles) {
+                updateSummaryAndTitle(context, providerMap, tile);
             }
+
             if (!tile.userHandle.contains(user)) {
                 tile.userHandle.add(user);
             }
@@ -387,7 +397,6 @@
             String summary = null;
             String keyHint = null;
             boolean isIconTintable = false;
-            RemoteViews remoteViews = null;
 
             // Get the activity's meta-data
             try {
@@ -442,7 +451,8 @@
                     }
                     if (metaData.containsKey(META_DATA_PREFERENCE_CUSTOM_VIEW)) {
                         int layoutId = metaData.getInt(META_DATA_PREFERENCE_CUSTOM_VIEW);
-                        remoteViews = new RemoteViews(applicationInfo.packageName, layoutId);
+                        tile.remoteViews = new RemoteViews(applicationInfo.packageName, layoutId);
+                        updateSummaryAndTitle(context, providerMap, tile);
                     }
                 }
             } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
@@ -474,7 +484,6 @@
             // Suggest a key for this tile
             tile.key = keyHint;
             tile.isIconTintable = isIconTintable;
-            tile.remoteViews = remoteViews;
 
             return true;
         }
@@ -482,6 +491,26 @@
         return false;
     }
 
+    private static void updateSummaryAndTitle(
+            Context context, Map<String, IContentProvider> providerMap, Tile tile) {
+        if (tile == null || tile.metaData == null
+                || !tile.metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
+            return;
+        }
+
+        String uriString = tile.metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI);
+        Bundle bundle = getBundleFromUri(context, uriString, providerMap);
+        String overrideSummary = getString(bundle, META_DATA_PREFERENCE_SUMMARY);
+        String overrideTitle = getString(bundle, META_DATA_PREFERENCE_TITLE);
+        if (overrideSummary != null) {
+            tile.remoteViews.setTextViewText(android.R.id.summary, overrideSummary);
+        }
+
+        if (overrideTitle != null) {
+            tile.remoteViews.setTextViewText(android.R.id.title, overrideTitle);
+        }
+    }
+
     /**
      * Gets the icon package name and resource id from content provider.
      * @param Context context
@@ -547,37 +576,6 @@
         }
     }
 
-    public static void updateTileUsingSummaryUri(Context context, final Tile tile) {
-        if (tile == null || tile.metaData == null ||
-                !tile.metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
-            return;
-        }
-
-        new AsyncTask<Void, Void, Bundle>() {
-            @Override
-            protected Bundle doInBackground(Void... params) {
-                return getBundleFromUri(context,
-                        tile.metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI), new HashMap<>());
-            }
-
-            @Override
-            protected void onPostExecute(Bundle bundle) {
-                if (bundle == null) {
-                    return;
-                }
-                final String overrideSummary = getString(bundle, META_DATA_PREFERENCE_SUMMARY);
-                final String overrideTitle = getString(bundle, META_DATA_PREFERENCE_TITLE);
-
-                if (overrideSummary != null) {
-                    tile.remoteViews.setTextViewText(android.R.id.summary, overrideSummary);
-                }
-                if (overrideTitle != null) {
-                    tile.remoteViews.setTextViewText(android.R.id.title, overrideTitle);
-                }
-            }
-        }.execute();
-    }
-
     private static String getString(Bundle bundle, String key) {
         return bundle == null ? null : bundle.getString(key);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
index 00f32b2..56b8441 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
@@ -195,7 +195,7 @@
             intent.setPackage(category.pkg);
         }
         TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
-                mAddCache, null, suggestions, true, false, false);
+                mAddCache, null, suggestions, true, false, false, true /* shouldUpdateTiles */);
         filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled);
         if (!category.multiple && suggestions.size() > (countBefore + 1)) {
             // If there are too many, remove them all and only re-add the one with the highest
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 3fd7c39..682b85e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -133,7 +133,7 @@
     private final Map<String, TimestampedScoredNetwork> mScoredNetworkCache = new HashMap<>();
 
     /** Maximum age of scan results to hold onto while actively scanning. **/
-    private static final long MAX_SCAN_RESULT_AGE_MILLIS = 15000;
+    private static final long MAX_SCAN_RESULT_AGE_MILLIS = 25000;
 
     static final String KEY_NETWORKINFO = "key_networkinfo";
     static final String KEY_WIFIINFO = "key_wifiinfo";
@@ -426,6 +426,11 @@
         }
         builder.append(",metered=").append(isMetered());
 
+        if (WifiTracker.sVerboseLogging) {
+            builder.append(",rssi=").append(mRssi);
+            builder.append(",scan cache size=").append(mScanResultCache.size());
+        }
+
         return builder.append(')').toString();
     }
 
@@ -951,6 +956,7 @@
         evictOldScanResults();
 
         // TODO: sort list by RSSI or age
+        long nowMs = SystemClock.elapsedRealtime();
         for (ScanResult result : mScanResultCache.values()) {
             if (result.frequency >= LOWER_FREQ_5GHZ
                     && result.frequency <= HIGHER_FREQ_5GHZ) {
@@ -961,7 +967,7 @@
                     maxRssi5 = result.level;
                 }
                 if (num5 <= maxDisplayedScans) {
-                    scans5GHz.append(verboseScanResultSummary(result, bssid));
+                    scans5GHz.append(verboseScanResultSummary(result, bssid, nowMs));
                 }
             } else if (result.frequency >= LOWER_FREQ_24GHZ
                     && result.frequency <= HIGHER_FREQ_24GHZ) {
@@ -972,7 +978,7 @@
                     maxRssi24 = result.level;
                 }
                 if (num24 <= maxDisplayedScans) {
-                    scans24GHz.append(verboseScanResultSummary(result, bssid));
+                    scans24GHz.append(verboseScanResultSummary(result, bssid, nowMs));
                 }
             }
         }
@@ -1000,7 +1006,7 @@
     }
 
     @VisibleForTesting
-    /* package */ String verboseScanResultSummary(ScanResult result, String bssid) {
+    /* package */ String verboseScanResultSummary(ScanResult result, String bssid, long nowMs) {
         StringBuilder stringBuilder = new StringBuilder();
         stringBuilder.append(" \n{").append(result.BSSID);
         if (result.BSSID.equals(bssid)) {
@@ -1013,6 +1019,8 @@
             stringBuilder.append(",")
                     .append(getSpeedLabel(speed));
         }
+        int ageSeconds = (int) (nowMs - result.timestamp / 1000) / 1000;
+        stringBuilder.append(",").append(ageSeconds).append("s");
         stringBuilder.append("}");
         return stringBuilder.toString();
     }
@@ -1209,6 +1217,7 @@
     /** Attempt to update the AccessPoint and return true if an update occurred. */
     public boolean update(
             @Nullable WifiConfiguration config, WifiInfo info, NetworkInfo networkInfo) {
+
         boolean updated = false;
         final int oldLevel = getLevel();
         if (info != null && isInfoForThisAccessPoint(config, info)) {
@@ -1240,6 +1249,7 @@
                 mAccessPointListener.onLevelChanged(this);
             }
         }
+
         return updated;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 6895550..3c664b0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -624,7 +624,7 @@
                 String prevSsid = prevAccessPoint.getSsidStr();
                 boolean found = false;
                 for (AccessPoint newAccessPoint : accessPoints) {
-                    if (newAccessPoint.getSsid() != null && newAccessPoint.getSsid()
+                    if (newAccessPoint.getSsidStr() != null && newAccessPoint.getSsidStr()
                             .equals(prevSsid)) {
                         found = true;
                         break;
@@ -676,24 +676,23 @@
     private void updateNetworkInfo(NetworkInfo networkInfo) {
         /* sticky broadcasts can call this when wifi is disabled */
         if (!mWifiManager.isWifiEnabled()) {
-            mMainHandler.sendEmptyMessage(MainHandler.MSG_PAUSE_SCANNING);
             clearAccessPointsAndConditionallyUpdate();
             return;
         }
 
-        if (networkInfo != null &&
-                networkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR) {
-            mMainHandler.sendEmptyMessage(MainHandler.MSG_PAUSE_SCANNING);
-        } else {
-            mMainHandler.sendEmptyMessage(MainHandler.MSG_RESUME_SCANNING);
-        }
-
         if (networkInfo != null) {
             mLastNetworkInfo = networkInfo;
+            if (DBG()) {
+                Log.d(TAG, "mLastNetworkInfo set: " + mLastNetworkInfo);
+            }
         }
 
         WifiConfiguration connectionConfig = null;
+
         mLastInfo = mWifiManager.getConnectionInfo();
+        if (DBG()) {
+            Log.d(TAG, "mLastInfo set as: " + mLastInfo);
+        }
         if (mLastInfo != null) {
             connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(),
                     mWifiManager.getConfiguredNetworks());
@@ -717,7 +716,6 @@
             }
 
             if (reorder) Collections.sort(mInternalAccessPoints);
-
             if (updated) mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
         }
     }
@@ -866,6 +864,9 @@
                     if (mScanner != null) {
                         mScanner.pause();
                     }
+                    synchronized (mLock) {
+                        mStaleScanResults = true;
+                    }
                     break;
             }
         }
@@ -928,6 +929,9 @@
                         if (mScanner != null) {
                             mScanner.pause();
                         }
+                        synchronized (mLock) {
+                            mStaleScanResults = true;
+                        }
                     }
                     mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
                             .sendToTarget();
@@ -982,7 +986,7 @@
                 }
                 return;
             }
-            sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);
+            sendEmptyMessageDelayed(MSG_SCAN, WIFI_RESCAN_INTERVAL_MS);
         }
     }
 
@@ -1075,10 +1079,12 @@
             oldAccessPoints.put(accessPoint.mId, accessPoint);
         }
 
-        if (DBG()) {
-            Log.d(TAG, "Starting to copy AP items on the MainHandler");
-        }
         synchronized (mLock) {
+            if (DBG()) {
+                Log.d(TAG, "Starting to copy AP items on the MainHandler. Internal APs: "
+                        + mInternalAccessPoints);
+            }
+
             if (notifyListeners) {
                 notificationMap = mAccessPointListenerAdapter.mPendingNotifications.clone();
             }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index b99584f..230b200 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -454,7 +454,7 @@
 
         ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
                 MAX_SCORE_CACHE_AGE_MILLIS);
-        String summary = ap.verboseScanResultSummary(scanResults.get(0), null);
+        String summary = ap.verboseScanResultSummary(scanResults.get(0), null, 0);
 
         assertThat(summary.contains(mContext.getString(R.string.speed_label_very_fast))).isTrue();
     }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index df6587e..7cce648 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -105,15 +105,30 @@
     private static final byte SCORE_2 = 15;
     private static final int BADGE_2 = AccessPoint.Speed.FAST;
 
-    private static final int CONNECTED_NETWORK_ID = 123;
+    // TODO(b/65594609): Convert mutable Data objects to instance variables / builder pattern
+    private static final int NETWORK_ID_1 = 123;
     private static final int CONNECTED_RSSI = -50;
     private static final WifiInfo CONNECTED_AP_1_INFO = new WifiInfo();
     static {
         CONNECTED_AP_1_INFO.setSSID(WifiSsid.createFromAsciiEncoded(SSID_1));
         CONNECTED_AP_1_INFO.setBSSID(BSSID_1);
-        CONNECTED_AP_1_INFO.setNetworkId(CONNECTED_NETWORK_ID);
+        CONNECTED_AP_1_INFO.setNetworkId(NETWORK_ID_1);
         CONNECTED_AP_1_INFO.setRssi(CONNECTED_RSSI);
     }
+    private static final WifiConfiguration CONFIGURATION_1 = new WifiConfiguration();
+    static {
+        CONFIGURATION_1.SSID = SSID_1;
+        CONFIGURATION_1.BSSID = BSSID_1;
+        CONFIGURATION_1.networkId = NETWORK_ID_1;
+    }
+
+    private static final int NETWORK_ID_2 = 2;
+    private static final WifiConfiguration CONFIGURATION_2 = new WifiConfiguration();
+    static {
+        CONFIGURATION_2.SSID = SSID_2;
+        CONFIGURATION_2.BSSID = BSSID_2;
+        CONFIGURATION_2.networkId = NETWORK_ID_2;
+    }
 
     @Captor ArgumentCaptor<WifiNetworkScoreCache> mScoreCacheCaptor;
     @Mock private ConnectivityManager mockConnectivityManager;
@@ -159,6 +174,8 @@
         when(mockWifiManager.isWifiEnabled()).thenReturn(true);
         when(mockWifiManager.getScanResults())
                 .thenReturn(Arrays.asList(buildScanResult1(), buildScanResult2()));
+        when(mockWifiManager.getConfiguredNetworks())
+                .thenReturn(Arrays.asList(CONFIGURATION_1, CONFIGURATION_2));
 
 
         when(mockCurve1.lookupScore(RSSI_1)).thenReturn(SCORE_1);
@@ -333,8 +350,7 @@
         WifiConfiguration configuration = new WifiConfiguration();
         configuration.SSID = SSID_1;
         configuration.BSSID = BSSID_1;
-        configuration.networkId = CONNECTED_NETWORK_ID;
-        when(mockWifiManager.getConfiguredNetworks()).thenReturn(Arrays.asList(configuration));
+        configuration.networkId = NETWORK_ID_1;
 
         NetworkInfo networkInfo = new NetworkInfo(
                 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
@@ -365,6 +381,24 @@
                 mainLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
+    private void switchToNetwork2(WifiTracker tracker) throws InterruptedException {
+        NetworkInfo networkInfo = new NetworkInfo(
+                ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
+        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "connecting", "test");
+
+        WifiInfo info = new WifiInfo();
+        info.setSSID(WifiSsid.createFromAsciiEncoded(SSID_2));
+        info.setBSSID(BSSID_2);
+        info.setRssi(CONNECTED_RSSI);
+        info.setNetworkId(NETWORK_ID_2);
+        when(mockWifiManager.getConnectionInfo()).thenReturn(info);
+
+        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
+        tracker.mReceiver.onReceive(mContext, intent);
+        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
+    }
+
     @Test
     public void testAccessPointListenerSetWhenLookingUpUsingScanResults() {
         ScanResult scanResult = new ScanResult();
@@ -722,12 +756,6 @@
 
         when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO);
 
-        WifiConfiguration configuration = new WifiConfiguration();
-        configuration.SSID = SSID_1;
-        configuration.BSSID = BSSID_1;
-        configuration.networkId = CONNECTED_NETWORK_ID;
-        when(mockWifiManager.getConfiguredNetworks()).thenReturn(Arrays.asList(configuration));
-
         NetworkInfo networkInfo = new NetworkInfo(
                 ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
         networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
@@ -881,4 +909,17 @@
         assertThat(tracker.isConnected()).isFalse();
         verify(mockWifiListener, times(2)).onConnectedChanged();
     }
+
+    @Test
+    public void updateNetworkInfoWithNewConnectedNetwork_switchesNetworks() throws Exception {
+        WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
+
+        switchToNetwork2(tracker);
+
+        List<AccessPoint> aps = tracker.getAccessPoints();
+        assertThat(aps.get(0).getSsidStr()).isEqualTo(SSID_2);
+
+        assertThat(aps.get(0).isReachable()).isTrue();
+        assertThat(aps.get(1).isReachable()).isTrue();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 386e820..e9ca753 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -22,12 +22,10 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.RuntimeEnvironment.application;
@@ -66,7 +64,9 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.internal.ShadowExtractor;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -75,7 +75,8 @@
 
 @RunWith(RobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH,
-        sdk = TestConfig.SDK_VERSION)
+        sdk = TestConfig.SDK_VERSION,
+        shadows = {TileUtilsTest.TileUtilsShadowRemoteViews.class})
 public class TileUtilsTest {
 
     @Mock
@@ -420,12 +421,24 @@
     }
 
     @Test
-    public void updateTileUsingSummaryUri_summaryUriSpecified_shouldOverrideRemoteViewSummary()
+    public void getTilesForIntent_summaryUriSpecified_shouldOverrideRemoteViewSummary()
             throws RemoteException {
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
+                null, URI_GET_SUMMARY);
+        resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
+                R.layout.user_preference);
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
         // Mock the content provider interaction.
         Bundle bundle = new Bundle();
-        String expectedSummary = "new summary text";
-        bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, expectedSummary);
+        bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
         when(mIContentProvider.call(anyString(),
                 eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
                 any())).thenReturn(bundle);
@@ -434,14 +447,57 @@
         when(mContentResolver.acquireUnstableProvider(any(Uri.class)))
                 .thenReturn(mIContentProvider);
 
-        Tile tile = new Tile();
-        tile.metaData = new Bundle();
-        tile.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY);
-        tile.remoteViews = mock(RemoteViews.class);
-        TileUtils.updateTileUsingSummaryUri(mContext, tile);
-        ShadowApplication.runBackgroundTasks();
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */, true /* forceTintExternalIcon */);
 
-        verify(tile.remoteViews, times(1)).setTextViewText(anyInt(), eq(expectedSummary));
+        assertThat(outTiles.size()).isEqualTo(1);
+        Tile tile = outTiles.get(0);
+        assertThat(tile.remoteViews).isNotNull();
+        assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
+        // Make sure the summary TextView got a new text string.
+        TileUtilsShadowRemoteViews shadowRemoteViews =
+                (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+        assertThat(shadowRemoteViews.overrideViewId).isEqualTo(android.R.id.summary);
+        assertThat(shadowRemoteViews.overrideText).isEqualTo("new summary text");
+    }
+
+    @Test
+    public void getTilesForIntent_providerUnavailable_shouldNotOverrideRemoteViewSummary()
+            throws RemoteException {
+        Intent intent = new Intent();
+        Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+        List<Tile> outTiles = new ArrayList<>();
+        List<ResolveInfo> info = new ArrayList<>();
+        ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
+                null, URI_GET_SUMMARY);
+        resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
+                R.layout.user_preference);
+        info.add(resolveInfo);
+
+        when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+                .thenReturn(info);
+
+        // Mock the content provider interaction.
+        Bundle bundle = new Bundle();
+        bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
+        when(mIContentProvider.call(anyString(),
+                eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
+                any())).thenReturn(bundle);
+
+        TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+                null /* defaultCategory */, outTiles, false /* usePriority */,
+                false /* checkCategory */, true /* forceTintExternalIcon */);
+
+        assertThat(outTiles.size()).isEqualTo(1);
+        Tile tile = outTiles.get(0);
+        assertThat(tile.remoteViews).isNotNull();
+        assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
+        // Make sure the summary TextView didn't get any text view updates.
+        TileUtilsShadowRemoteViews shadowRemoteViews =
+                (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+        assertThat(shadowRemoteViews.overrideViewId).isNull();
+        assertThat(shadowRemoteViews.overrideText).isNull();
     }
 
     public static ResolveInfo newInfo(boolean systemApp, String category) {
@@ -506,4 +562,16 @@
         }
     }
 
+    @Implements(RemoteViews.class)
+    public static class TileUtilsShadowRemoteViews {
+
+        private Integer overrideViewId;
+        private CharSequence overrideText;
+
+        @Implementation
+        public void setTextViewText(int viewId, CharSequence text) {
+            overrideViewId = viewId;
+            overrideText = text;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 8de1d31..2bc0e45c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -15,6 +15,8 @@
  */
 package com.android.keyguard;
 
+import static android.view.Display.INVALID_DISPLAY;
+
 import android.app.Presentation;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -28,16 +30,21 @@
 import android.view.View;
 import android.view.WindowManager;
 
+// TODO(multi-display): Support multiple external displays
 public class KeyguardDisplayManager {
     protected static final String TAG = "KeyguardDisplayManager";
     private static boolean DEBUG = KeyguardConstants.DEBUG;
+
+    private final ViewMediatorCallback mCallback;
+    private final MediaRouter mMediaRouter;
+    private final Context mContext;
+
     Presentation mPresentation;
-    private MediaRouter mMediaRouter;
-    private Context mContext;
     private boolean mShowing;
 
-    public KeyguardDisplayManager(Context context) {
+    public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) {
         mContext = context;
+        mCallback = callback;
         mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
     }
 
@@ -90,6 +97,7 @@
     };
 
     protected void updateDisplays(boolean showing) {
+        Presentation originalPresentation = mPresentation;
         if (showing) {
             MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
                     MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
@@ -121,6 +129,13 @@
                 mPresentation = null;
             }
         }
+
+        // mPresentation is only updated when the display changes
+        if (mPresentation != originalPresentation) {
+            final int displayId = mPresentation != null
+                    ? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY;
+            mCallback.onSecondaryDisplayShowingChanged(displayId);
+        }
     }
 
     private final static class KeyguardPresentation extends Presentation {
diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
index 327d218..b194de4 100644
--- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
@@ -88,4 +88,9 @@
      *         {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}.
      */
     int getBouncerPromptReason();
+
+    /**
+     * Invoked when the secondary display showing a keyguard window changes.
+     */
+    void onSecondaryDisplayShowingChanged(int displayId);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3eb68f5..28adca9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -17,6 +17,7 @@
 package com.android.systemui.keyguard;
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
@@ -239,6 +240,9 @@
     // answer whether the input should be restricted)
     private boolean mShowing;
 
+    // display id of the secondary display on which we have put a keyguard window
+    private int mSecondaryDisplayShowing = INVALID_DISPLAY;
+
     /** Cached value of #isInputRestricted */
     private boolean mInputRestricted;
 
@@ -646,6 +650,13 @@
             }
             return KeyguardSecurityView.PROMPT_REASON_NONE;
         }
+
+        @Override
+        public void onSecondaryDisplayShowingChanged(int displayId) {
+            synchronized (KeyguardViewMediator.this) {
+                setShowingLocked(mShowing, displayId, false);
+            }
+        }
     };
 
     public void userActivity() {
@@ -670,7 +681,7 @@
         filter.addAction(Intent.ACTION_SHUTDOWN);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
-        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);
+        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, mViewMediatorCallback);
 
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
@@ -685,7 +696,8 @@
                 com.android.keyguard.R.bool.config_enableKeyguardService)) {
             setShowingLocked(!shouldWaitForProvisioning()
                     && !mLockPatternUtils.isLockScreenDisabled(
-                            KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
+                            KeyguardUpdateMonitor.getCurrentUser()),
+                    mSecondaryDisplayShowing, true /* forceCallbacks */);
         }
 
         mStatusBarKeyguardViewManager =
@@ -1694,10 +1706,10 @@
         playSound(mTrustedSoundId);
     }
 
-    private void updateActivityLockScreenState(boolean showing) {
+    private void updateActivityLockScreenState(boolean showing, int secondaryDisplayShowing) {
         mUiOffloadThread.submit(() -> {
             try {
-                ActivityManager.getService().setLockScreenShown(showing);
+                ActivityManager.getService().setLockScreenShown(showing, secondaryDisplayShowing);
             } catch (RemoteException e) {
             }
         });
@@ -2060,30 +2072,39 @@
     }
 
     private void setShowingLocked(boolean showing) {
-        setShowingLocked(showing, false /* forceCallbacks */);
+        setShowingLocked(showing, mSecondaryDisplayShowing, false /* forceCallbacks */);
     }
 
-    private void setShowingLocked(boolean showing, boolean forceCallbacks) {
-        if (showing != mShowing || forceCallbacks) {
+    private void setShowingLocked(
+            boolean showing, int secondaryDisplayShowing, boolean forceCallbacks) {
+        final boolean notifyDefaultDisplayCallbacks = showing != mShowing || forceCallbacks;
+        if (notifyDefaultDisplayCallbacks || secondaryDisplayShowing != mSecondaryDisplayShowing) {
             mShowing = showing;
-            int size = mKeyguardStateCallbacks.size();
-            for (int i = size - 1; i >= 0; i--) {
-                IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
-                try {
-                    callback.onShowingStateChanged(showing);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failed to call onShowingStateChanged", e);
-                    if (e instanceof DeadObjectException) {
-                        mKeyguardStateCallbacks.remove(callback);
-                    }
+            mSecondaryDisplayShowing = secondaryDisplayShowing;
+            if (notifyDefaultDisplayCallbacks) {
+                notifyDefaultDisplayCallbacks(showing);
+            }
+            updateActivityLockScreenState(showing, secondaryDisplayShowing);
+        }
+    }
+
+    private void notifyDefaultDisplayCallbacks(boolean showing) {
+        int size = mKeyguardStateCallbacks.size();
+        for (int i = size - 1; i >= 0; i--) {
+            IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
+            try {
+                callback.onShowingStateChanged(showing);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to call onShowingStateChanged", e);
+                if (e instanceof DeadObjectException) {
+                    mKeyguardStateCallbacks.remove(callback);
                 }
             }
-            updateInputRestrictedLocked();
-            mUiOffloadThread.submit(() -> {
-                mTrustManager.reportKeyguardShowingChanged();
-            });
-            updateActivityLockScreenState(showing);
         }
+        updateInputRestrictedLocked();
+        mUiOffloadThread.submit(() -> {
+            mTrustManager.reportKeyguardShowingChanged();
+        });
     }
 
     private void notifyTrustedChangedLocked(boolean trusted) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 84628e7..e28e1c9 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -633,7 +633,7 @@
 
     void destroySessionsLocked() {
         if (mSessions.size() == 0) {
-            mUi.destroyAll(null, null);
+            mUi.destroyAll(null, null, false);
             return;
         }
         while (mSessions.size() > 0) {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index f315148..af55807 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -578,9 +578,8 @@
         public void run() {
             synchronized (mLock) {
                 if (isCancelledLocked()) {
-                    // TODO(b/653742740): we should probably return here, but for now we're justing
-                    // logging to confirm this is the problem if it happens again.
-                    Slog.e(LOG_TAG, "run() called after canceled: " + mRequest);
+                    if (sDebug) Slog.d(LOG_TAG, "run() called after canceled: " + mRequest);
+                    return;
                 }
             }
             final RemoteFillService remoteService = getService();
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index db0f392..ff6e94b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -465,7 +465,7 @@
         if ((response.getDatasets() == null || response.getDatasets().isEmpty())
                         && response.getAuthentication() == null) {
             // Response is "empty" from an UI point of view, need to notify client.
-            notifyUnavailableToClient();
+            notifyUnavailableToClient(false);
         }
         synchronized (mLock) {
             processResponseLocked(response, requestFlags);
@@ -566,6 +566,10 @@
     // FillServiceCallbacks
     @Override
     public void authenticate(int requestId, int datasetIndex, IntentSender intent, Bundle extras) {
+        if (sDebug) {
+            Slog.d(TAG, "authenticate(): requestId=" + requestId + "; datasetIdx=" + datasetIndex
+                    + "; intentSender=" + intent);
+        }
         final Intent fillInIntent;
         synchronized (mLock) {
             if (mDestroyed) {
@@ -574,6 +578,10 @@
                 return;
             }
             fillInIntent = createAuthFillInIntentLocked(requestId, extras);
+            if (fillInIntent == null) {
+                forceRemoveSelfLocked();
+                return;
+            }
         }
         mService.setAuthenticationSelected(id);
 
@@ -1353,11 +1361,15 @@
         }
     }
 
-    private void notifyUnavailableToClient() {
+    private void notifyUnavailableToClient(boolean sessionFinished) {
         synchronized (mLock) {
-            if (!mHasCallback || mCurrentViewId == null) return;
+            if (mCurrentViewId == null) return;
             try {
-                mClient.notifyNoFillUi(id, mCurrentViewId);
+                if (mHasCallback) {
+                    mClient.notifyNoFillUi(id, mCurrentViewId, sessionFinished);
+                } else if (sessionFinished) {
+                    mClient.setSessionFinished();
+                }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e);
             }
@@ -1445,7 +1457,7 @@
         }
         mService.resetLastResponse();
         // Nothing to be done, but need to notify client.
-        notifyUnavailableToClient();
+        notifyUnavailableToClient(true);
         removeSelf();
     }
 
@@ -1564,6 +1576,10 @@
     }
 
     void autoFill(int requestId, int datasetIndex, Dataset dataset, boolean generateEvent) {
+        if (sDebug) {
+            Slog.d(TAG, "autoFill(): requestId=" + requestId  + "; datasetIdx=" + datasetIndex
+                    + "; dataset=" + dataset);
+        }
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#autoFill() rejected - session: "
@@ -1584,10 +1600,14 @@
             mService.logDatasetAuthenticationSelected(dataset.getId(), id);
             setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
             final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState);
-
+            if (fillInIntent == null) {
+                forceRemoveSelfLocked();
+                return;
+            }
             final int authenticationId = AutofillManager.makeAuthenticationId(requestId,
                     datasetIndex);
             startAuthentication(authenticationId, dataset.getAuthentication(), fillInIntent);
+
         }
     }
 
@@ -1597,14 +1617,16 @@
         }
     }
 
+    // TODO: this should never be null, but we got at least one occurrence, probably due to a race.
+    @Nullable
     private Intent createAuthFillInIntentLocked(int requestId, Bundle extras) {
         final Intent fillInIntent = new Intent();
 
         final FillContext context = getFillContextByRequestIdLocked(requestId);
         if (context == null) {
-            // TODO(b/653742740): this will crash system_server. We need to handle it, but we're
-            // keeping it crashing for now so we can diagnose when it happens again
-            Slog.wtf(TAG, "no FillContext for requestId" + requestId + "; mContexts= " + mContexts);
+            Slog.wtf(TAG, "createAuthFillInIntentLocked(): no FillContext. requestId=" + requestId
+                    + "; mContexts= " + mContexts);
+            return null;
         }
         fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure());
         fillInIntent.putExtra(AutofillManager.EXTRA_CLIENT_STATE, extras);
@@ -1744,7 +1766,7 @@
         if (mDestroyed) {
             return null;
         }
-        mUi.destroyAll(mPendingSaveUi, this);
+        mUi.destroyAll(mPendingSaveUi, this, true);
         mUi.clearCallback(this);
         mDestroyed = true;
         writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED);
@@ -1760,7 +1782,16 @@
 
         mPendingSaveUi = null;
         removeSelfLocked();
-        mUi.destroyAll(mPendingSaveUi, this);
+
+        mHandlerCaller.getHandler().post(() -> {
+            try {
+                mClient.setState(mService.isEnabled(), true, false);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "error updating client state: " + e);
+            }
+        });
+
+        mUi.destroyAll(mPendingSaveUi, this, false);
     }
 
     /**
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 434b590..36b95fc 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -275,7 +275,7 @@
                     if (mCallback != null) {
                         mCallback.save();
                     }
-                    destroySaveUiUiThread(pendingSaveUi);
+                    destroySaveUiUiThread(pendingSaveUi, true);
                 }
 
                 @Override
@@ -293,7 +293,7 @@
                     if (mCallback != null) {
                         mCallback.cancelSave();
                     }
-                    destroySaveUiUiThread(pendingSaveUi);
+                    destroySaveUiUiThread(pendingSaveUi, true);
                 }
 
                 @Override
@@ -335,8 +335,8 @@
      * Destroy all UI affordances.
      */
     public void destroyAll(@Nullable PendingUi pendingSaveUi,
-            @Nullable AutoFillUiCallback callback) {
-        mHandler.post(() -> destroyAllUiThread(pendingSaveUi, callback));
+            @Nullable AutoFillUiCallback callback, boolean notifyClient) {
+        mHandler.post(() -> destroyAllUiThread(pendingSaveUi, callback, notifyClient));
     }
 
     public void dump(PrintWriter pw) {
@@ -379,7 +379,7 @@
     }
 
     @android.annotation.UiThread
-    private void destroySaveUiUiThread(@Nullable PendingUi pendingSaveUi) {
+    private void destroySaveUiUiThread(@Nullable PendingUi pendingSaveUi, boolean notifyClient) {
         if (mSaveUi == null) {
             // Calling destroySaveUiUiThread() twice is normal - it usually happens when the
             // first call is made after the SaveUI is hidden and the second when the session is
@@ -391,7 +391,7 @@
         if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): " + pendingSaveUi);
         mSaveUi.destroy();
         mSaveUi = null;
-        if (pendingSaveUi != null) {
+        if (pendingSaveUi != null && notifyClient) {
             try {
                 if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): notifying client");
                 pendingSaveUi.client.setSaveUiState(pendingSaveUi.id, false);
@@ -403,9 +403,9 @@
 
     @android.annotation.UiThread
     private void destroyAllUiThread(@Nullable PendingUi pendingSaveUi,
-            @Nullable AutoFillUiCallback callback) {
+            @Nullable AutoFillUiCallback callback, boolean notifyClient) {
         hideFillUiUiThread(callback);
-        destroySaveUiUiThread(pendingSaveUi);
+        destroySaveUiUiThread(pendingSaveUi, notifyClient);
     }
 
     @android.annotation.UiThread
@@ -417,7 +417,7 @@
                 Slog.d(TAG, "hideAllUiThread(): "
                         + "destroying Save UI because pending restoration is finished");
             }
-            destroySaveUiUiThread(pendingSaveUi);
+            destroySaveUiUiThread(pendingSaveUi, true);
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index e0cde72..90ad8a5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2162,6 +2162,15 @@
             }
         }
 
+        if (r.fgRequired) {
+            if (DEBUG_FOREGROUND_SERVICE) {
+                Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
+                        + " for fg-service launch");
+            }
+            mAm.tempWhitelistUidLocked(r.appInfo.uid,
+                    SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
+        }
+
         if (!mPendingServices.contains(r)) {
             mPendingServices.add(r);
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 69285a48..1f8b83e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -713,7 +713,7 @@
 
     public boolean canShowErrorDialogs() {
         return mShowDialogs && !mSleeping && !mShuttingDown
-                && !mKeyguardController.isKeyguardShowing()
+                && !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)
                 && !(UserManager.isDeviceInDemoMode(mContext)
                         && mUserController.getCurrentUser().isDemo());
     }
@@ -12614,7 +12614,7 @@
     }
 
     @Override
-    public void setLockScreenShown(boolean showing) {
+    public void setLockScreenShown(boolean showing, int secondaryDisplayShowing) {
         if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
@@ -12624,7 +12624,7 @@
         synchronized(this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                mKeyguardController.setKeyguardShown(showing);
+                mKeyguardController.setKeyguardShown(showing, secondaryDisplayShowing);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -24087,7 +24087,7 @@
         @Override
         public void notifyKeyguardTrustedChanged() {
             synchronized (ActivityManagerService.this) {
-                if (mKeyguardController.isKeyguardShowing()) {
+                if (mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 5b27c9c..b2bbf19 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1176,8 +1176,15 @@
      *         can be put a secondary screen.
      */
     boolean canBeLaunchedOnDisplay(int displayId) {
+        final TaskRecord task = getTask();
+
+        // The resizeability of an Activity's parent task takes precendence over the ActivityInfo.
+        // This allows for a non resizable activity to be launched into a resizeable task.
+        final boolean resizeable =
+                task != null ? task.isResizeable() : supportsResizeableMultiWindow();
+
         return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
-                supportsResizeableMultiWindow(), launchedFromPid, launchedFromUid, info);
+                resizeable, launchedFromPid, launchedFromUid, info);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 791b2c0..a0817c4 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1980,7 +1980,8 @@
     boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible,
             boolean isTop) {
         final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID;
-        final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing();
+        final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing(
+                mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
         final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked();
         final boolean showWhenLocked = r.canShowWhenLocked() && !isInPinnedStack;
         final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
@@ -5205,8 +5206,8 @@
                 voiceInteractor, type);
         // add the task to stack first, mTaskPositioner might need the stack association
         addTask(task, toTop, "createTaskRecord");
-        final boolean isLockscreenShown =
-                mService.mStackSupervisor.mKeyguardController.isKeyguardShowing();
+        final boolean isLockscreenShown = mService.mStackSupervisor.mKeyguardController
+                .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
         if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable()
                 && !isLockscreenShown) {
             task.updateOverrideConfiguration(mBounds);
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index cea80c8..8596113 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
 import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -66,6 +67,7 @@
     private int mBeforeUnoccludeTransit;
     private int mVisibilityTransactionDepth;
     private SleepToken mSleepToken;
+    private int mSecondaryDisplayShowing = INVALID_DISPLAY;
 
     KeyguardController(ActivityManagerService service,
             ActivityStackSupervisor stackSupervisor) {
@@ -78,10 +80,12 @@
     }
 
     /**
-     * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
+     * @return true if Keyguard is showing, not going away, and not being occluded on the given
+     *         display, false otherwise
      */
-    boolean isKeyguardShowing() {
-        return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
+    boolean isKeyguardShowing(int displayId) {
+        return mKeyguardShowing && !mKeyguardGoingAway &&
+                (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
     }
 
     /**
@@ -94,15 +98,19 @@
     /**
      * Update the Keyguard showing state.
      */
-    void setKeyguardShown(boolean showing) {
-        if (showing == mKeyguardShowing) {
+    void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
+        boolean showingChanged = showing != mKeyguardShowing;
+        if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
             return;
         }
         mKeyguardShowing = showing;
-        dismissDockedStackIfNeeded();
-        if (showing) {
-            setKeyguardGoingAway(false);
-            mDismissalRequested = false;
+        mSecondaryDisplayShowing = secondaryDisplayShowing;
+        if (showingChanged) {
+            dismissDockedStackIfNeeded();
+            if (showing) {
+                setKeyguardGoingAway(false);
+                mDismissalRequested = false;
+            }
         }
         mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         updateKeyguardSleepToken();
@@ -337,9 +345,9 @@
     }
 
     private void updateKeyguardSleepToken() {
-        if (mSleepToken == null && isKeyguardShowing()) {
+        if (mSleepToken == null && isKeyguardShowing(DEFAULT_DISPLAY)) {
             mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
-        } else if (mSleepToken != null && !isKeyguardShowing()) {
+        } else if (mSleepToken != null && !isKeyguardShowing(DEFAULT_DISPLAY)) {
             mSleepToken.release();
             mSleepToken = null;
         }
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index c4911b8..eec2c99 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -48,8 +48,10 @@
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
 
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.Calendar;
 import java.util.TimeZone;
 
 import com.android.internal.R;
@@ -308,7 +310,7 @@
     }
 
     @Override
-    public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+    public void onCustomStartTimeChanged(LocalTime startTime) {
         Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);
 
         if (mAutoMode != null) {
@@ -317,7 +319,7 @@
     }
 
     @Override
-    public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+    public void onCustomEndTimeChanged(LocalTime endTime) {
         Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);
 
         if (mAutoMode != null) {
@@ -416,6 +418,36 @@
         outTemp[10] = blue;
     }
 
+    /**
+     * Returns the first date time corresponding to the local time that occurs before the
+     * provided date time.
+     *
+     * @param compareTime the LocalDateTime to compare against
+     * @return the prior LocalDateTime corresponding to this local time
+     */
+    public static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) {
+        final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
+                compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
+
+        // Check if the local time has passed, if so return the same time yesterday.
+        return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt;
+    }
+
+    /**
+     * Returns the first date time corresponding to this local time that occurs after the
+     * provided date time.
+     *
+     * @param compareTime the LocalDateTime to compare against
+     * @return the next LocalDateTime corresponding to this local time
+     */
+    public static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) {
+        final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
+                compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
+
+        // Check if the local time has passed, if so return the same time tomorrow.
+        return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
+    }
+
     private abstract class AutoMode implements NightDisplayController.Callback {
         public abstract void onStart();
 
@@ -427,10 +459,10 @@
         private final AlarmManager mAlarmManager;
         private final BroadcastReceiver mTimeChangedReceiver;
 
-        private NightDisplayController.LocalTime mStartTime;
-        private NightDisplayController.LocalTime mEndTime;
+        private LocalTime mStartTime;
+        private LocalTime mEndTime;
 
-        private Calendar mLastActivatedTime;
+        private LocalDateTime mLastActivatedTime;
 
         CustomAutoMode() {
             mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
@@ -443,31 +475,15 @@
         }
 
         private void updateActivated() {
-            final Calendar now = Calendar.getInstance();
-            final Calendar startTime = mStartTime.getDateTimeBefore(now);
-            final Calendar endTime = mEndTime.getDateTimeAfter(startTime);
+            final LocalDateTime now = LocalDateTime.now();
+            final LocalDateTime start = getDateTimeBefore(mStartTime, now);
+            final LocalDateTime end = getDateTimeAfter(mEndTime, start);
+            boolean activate = now.isBefore(end);
 
-            boolean activate = now.before(endTime);
             if (mLastActivatedTime != null) {
-                // Convert mLastActivatedTime to the current timezone if needed.
-                final TimeZone currentTimeZone = now.getTimeZone();
-                if (!currentTimeZone.equals(mLastActivatedTime.getTimeZone())) {
-                    final int year = mLastActivatedTime.get(Calendar.YEAR);
-                    final int dayOfYear = mLastActivatedTime.get(Calendar.DAY_OF_YEAR);
-                    final int hourOfDay = mLastActivatedTime.get(Calendar.HOUR_OF_DAY);
-                    final int minute = mLastActivatedTime.get(Calendar.MINUTE);
-
-                    mLastActivatedTime.setTimeZone(currentTimeZone);
-                    mLastActivatedTime.set(Calendar.YEAR, year);
-                    mLastActivatedTime.set(Calendar.DAY_OF_YEAR, dayOfYear);
-                    mLastActivatedTime.set(Calendar.HOUR_OF_DAY, hourOfDay);
-                    mLastActivatedTime.set(Calendar.MINUTE, minute);
-                }
-
                 // Maintain the existing activated state if within the current period.
-                if (mLastActivatedTime.before(now)
-                        && mLastActivatedTime.after(startTime)
-                        && (mLastActivatedTime.after(endTime) || now.before(endTime))) {
+                if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
+                        && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
                     activate = mController.isActivated();
                 }
             }
@@ -475,14 +491,16 @@
             if (mIsActivated == null || mIsActivated != activate) {
                 mController.setActivated(activate);
             }
+
             updateNextAlarm(mIsActivated, now);
         }
 
-        private void updateNextAlarm(@Nullable Boolean activated, @NonNull Calendar now) {
+        private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
             if (activated != null) {
-                final Calendar next = activated ? mEndTime.getDateTimeAfter(now)
-                        : mStartTime.getDateTimeAfter(now);
-                mAlarmManager.setExact(AlarmManager.RTC, next.getTimeInMillis(), TAG, this, null);
+                final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now)
+                        : getDateTimeAfter(mStartTime, now);
+                final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+                mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null);
             }
         }
 
@@ -512,18 +530,18 @@
         @Override
         public void onActivated(boolean activated) {
             mLastActivatedTime = mController.getLastActivatedTime();
-            updateNextAlarm(activated, Calendar.getInstance());
+            updateNextAlarm(activated, LocalDateTime.now());
         }
 
         @Override
-        public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+        public void onCustomStartTimeChanged(LocalTime startTime) {
             mStartTime = startTime;
             mLastActivatedTime = null;
             updateActivated();
         }
 
         @Override
-        public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+        public void onCustomEndTimeChanged(LocalTime endTime) {
             mEndTime = endTime;
             mLastActivatedTime = null;
             updateActivated();
@@ -552,15 +570,14 @@
             }
 
             boolean activate = state.isNight();
-            final Calendar lastActivatedTime = mController.getLastActivatedTime();
+            final LocalDateTime lastActivatedTime = mController.getLastActivatedTime();
             if (lastActivatedTime != null) {
-                final Calendar now = Calendar.getInstance();
-                final Calendar sunrise = state.sunrise();
-                final Calendar sunset = state.sunset();
-
+                final LocalDateTime now = LocalDateTime.now();
+                final LocalDateTime sunrise = state.sunrise();
+                final LocalDateTime sunset = state.sunset();
                 // Maintain the existing activated state if within the current period.
-                if (lastActivatedTime.before(now)
-                        && (lastActivatedTime.after(sunrise) ^ lastActivatedTime.after(sunset))) {
+                if (lastActivatedTime.isBefore(now) && (lastActivatedTime.isBefore(sunrise)
+                        ^ lastActivatedTime.isBefore(sunset))) {
                     activate = mController.isActivated();
                 }
             }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 0f580d8..4fafe34 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -438,16 +438,7 @@
                     PackageDexUsage.DexUseInfo dexUseInfo = e.getValue();
                     pw.println(dex);
                     pw.increaseIndent();
-                    for (String isa : dexUseInfo.getLoaderIsas()) {
-                        String status = null;
-                        try {
-                            status = DexFile.getDexFileStatus(path, isa);
-                        } catch (IOException ioe) {
-                             status = "[Exception]: " + ioe.getMessage();
-                        }
-                        pw.println(isa + ": " + status);
-                    }
-
+                    // TODO(calin): get the status of the oat file (needs installd call)
                     pw.println("class loader context: " + dexUseInfo.getClassLoaderContext());
                     if (dexUseInfo.isUsedByOtherApps()) {
                         pw.println("used be other apps: " + dexUseInfo.getLoadingPackages());
@@ -474,8 +465,9 @@
         }
 
         if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
-            // If the dex files is used by other apps, we cannot use profile-guided compilation.
-            return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+            // If the dex files is used by other apps, apply the shared filter.
+            return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+                    PackageManagerService.REASON_SHARED);
         }
 
         return targetCompilerFilter;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f594b38..b2e0a08 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -577,8 +577,9 @@
     public static final int REASON_BACKGROUND_DEXOPT = 3;
     public static final int REASON_AB_OTA = 4;
     public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 5;
+    public static final int REASON_SHARED = 6;
 
-    public static final int REASON_LAST = REASON_INACTIVE_PACKAGE_DOWNGRADE;
+    public static final int REASON_LAST = REASON_SHARED;
 
     /** All dangerous permission names in the same order as the events in MetricsEvent */
     private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
@@ -9803,19 +9804,6 @@
                     compilerFilter,
                     dexoptFlags));
 
-            if (pkg.isSystemApp()) {
-                // Only dexopt shared secondary dex files belonging to system apps to not slow down
-                // too much boot after an OTA.
-                int secondaryDexoptFlags = dexoptFlags |
-                        DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX |
-                        DexoptOptions.DEXOPT_ONLY_SHARED_DEX;
-                mDexManager.dexoptSecondaryDex(new DexoptOptions(
-                        pkg.packageName,
-                        compilerFilter,
-                        secondaryDexoptFlags));
-            }
-
-            // TODO(shubhamajmera): Record secondary dexopt stats.
             switch (primaryDexOptStaus) {
                 case PackageDexOptimizer.DEX_OPT_PERFORMED:
                     numberOfPackagesOptimized++;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 1a97a72..19b0d9b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -26,14 +26,19 @@
 public class PackageManagerServiceCompilerMapping {
     // Names for compilation reasons.
     static final String REASON_STRINGS[] = {
-            "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive"
+            "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive", "shared"
     };
 
+    static final int REASON_SHARED_INDEX = 6;
+
     // Static block to ensure the strings array is of the right length.
     static {
         if (PackageManagerService.REASON_LAST + 1 != REASON_STRINGS.length) {
             throw new IllegalStateException("REASON_STRINGS not correct");
         }
+        if (!"shared".equals(REASON_STRINGS[REASON_SHARED_INDEX])) {
+            throw new IllegalStateException("REASON_STRINGS not correct because of shared index");
+        }
     }
 
     private static String getSystemPropertyName(int reason) {
@@ -52,11 +57,18 @@
                 !DexFile.isValidCompilerFilter(sysPropValue)) {
             throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
                     + "(reason " + REASON_STRINGS[reason] + ")");
+        } else if (!isFilterAllowedForReason(reason, sysPropValue)) {
+            throw new IllegalStateException("Value \"" + sysPropValue +"\" not allowed "
+                    + "(reason " + REASON_STRINGS[reason] + ")");
         }
 
         return sysPropValue;
     }
 
+    private static boolean isFilterAllowedForReason(int reason, String filter) {
+        return reason != REASON_SHARED_INDEX || !DexFile.isProfileGuidedCompilerFilter(filter);
+    }
+
     // Check that the properties are set and valid.
     // Note: this is done in a separate method so this class can be statically initialized.
     static void checkProperties() {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 50e5e7b..5a5471b 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,5 +1,7 @@
 package com.android.server.policy.keyguard;
 
+import static android.view.Display.INVALID_DISPLAY;
+
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -201,7 +203,10 @@
             mKeyguardState.reset();
             mHandler.post(() -> {
                 try {
-                    ActivityManager.getService().setLockScreenShown(true);
+                    // There are no longer any keyguard windows on secondary displays, so pass
+                    // INVALID_DISPLAY. All that means is that showWhenLocked activities on
+                    // secondary displays now get to show.
+                    ActivityManager.getService().setLockScreenShown(true, INVALID_DISPLAY);
                 } catch (RemoteException e) {
                     // Local call.
                 }
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
index 30a8ccc..71304a7 100644
--- a/services/core/java/com/android/server/twilight/TwilightState.java
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -18,7 +18,10 @@
 
 import android.text.format.DateFormat;
 
-import java.util.Calendar;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.TimeZone;
 
 /**
  * The twilight state, consisting of the sunrise and sunset times (in millis) for the current
@@ -45,12 +48,11 @@
     }
 
     /**
-     * Returns a new {@link Calendar} instance initialized to {@link #sunriseTimeMillis()}.
+     * Returns a new {@link LocalDateTime} instance initialized to {@link #sunriseTimeMillis()}.
      */
-    public Calendar sunrise() {
-        final Calendar sunrise = Calendar.getInstance();
-        sunrise.setTimeInMillis(mSunriseTimeMillis);
-        return sunrise;
+    public LocalDateTime sunrise() {
+        final ZoneId zoneId = TimeZone.getDefault().toZoneId();
+        return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunriseTimeMillis), zoneId);
     }
 
     /**
@@ -62,12 +64,11 @@
     }
 
     /**
-     * Returns a new {@link Calendar} instance initialized to {@link #sunsetTimeMillis()}.
+     * Returns a new {@link LocalDateTime} instance initialized to {@link #sunsetTimeMillis()}.
      */
-    public Calendar sunset() {
-        final Calendar sunset = Calendar.getInstance();
-        sunset.setTimeInMillis(mSunsetTimeMillis);
-        return sunset;
+    public LocalDateTime sunset() {
+        final ZoneId zoneId = TimeZone.getDefault().toZoneId();
+        return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunsetTimeMillis), zoneId);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
index 58a4456..3a92d63 100644
--- a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
@@ -30,13 +30,14 @@
 import android.test.mock.MockContentResolver;
 
 import com.android.internal.app.NightDisplayController;
-import com.android.internal.app.NightDisplayController.LocalTime;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.display.DisplayTransformManager;
 import com.android.server.display.NightDisplayService;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -45,6 +46,7 @@
 
 import java.util.Calendar;
 import java.util.HashMap;
+import java.time.LocalTime;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -926,11 +928,10 @@
      */
     private void setActivated(boolean activated, int lastActivatedTimeOffset) {
         mNightDisplayController.setActivated(activated);
-
-        final Calendar c = Calendar.getInstance();
-        c.add(Calendar.MINUTE, lastActivatedTimeOffset);
-        Secure.putLongForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, c.getTimeInMillis(), mUserId);
+        Secure.putStringForUser(mContext.getContentResolver(),
+                Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                LocalDateTime.now().plusMinutes(lastActivatedTimeOffset).toString(),
+                mUserId);
     }
 
     /**
@@ -969,7 +970,7 @@
     private static LocalTime getLocalTimeRelativeToNow(int offsetMinutes) {
         final Calendar c = Calendar.getInstance();
         c.add(Calendar.MINUTE, offsetMinutes);
-        return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
+        return LocalTime.of(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
     }
 
     /**
@@ -984,13 +985,27 @@
         final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset);
         final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset);
 
-        final Calendar now = Calendar.getInstance();
-        long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis();
-        long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis();
+        final LocalDateTime now = LocalDateTime.now();
+        final ZoneId zoneId = ZoneId.systemDefault();
+
+        long sunsetMillis = NightDisplayService.getDateTimeBefore(sunset, now)
+                .atZone(zoneId)
+                .toInstant()
+                .toEpochMilli();
+        long sunriseMillis = NightDisplayService.getDateTimeBefore(sunrise, now)
+                .atZone(zoneId)
+                .toInstant()
+                .toEpochMilli();
         if (sunsetMillis < sunriseMillis) {
-            sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
+            sunsetMillis = NightDisplayService.getDateTimeAfter(sunset, now)
+                    .atZone(zoneId)
+                    .toInstant()
+                    .toEpochMilli();
         } else {
-            sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
+            sunriseMillis = NightDisplayService.getDateTimeAfter(sunrise, now)
+                    .atZone(zoneId)
+                    .toInstant()
+                    .toEpochMilli();
         }
 
         return new TwilightState(sunriseMillis, sunsetMillis);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 2252c85..e51f7a9 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -20,15 +20,19 @@
 import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
 import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import android.view.Display;
 import org.junit.runner.RunWith;
 import org.junit.Test;
 
@@ -46,6 +50,8 @@
 
     private final ComponentName testActivityComponent =
             ComponentName.unflattenFromString("com.foo/.BarActivity");
+    private final ComponentName secondaryActivityComponent =
+            ComponentName.unflattenFromString("com.foo/.BarActivity2");
     @Test
     public void testStackCleanupOnClearingTask() throws Exception {
         final ActivityManagerService service = createActivityManagerService();
@@ -131,4 +137,45 @@
         record.ensureActivityConfigurationLocked(0 /* globalChanges */, false /* preserveWindow */);
         assertEquals(expectedActivityBounds, record.getBounds());
     }
+
+
+    @Test
+    public void testCanBeLaunchedOnDisplay() throws Exception {
+        testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
+                true /*activityResizeable*/, true /*expected*/);
+
+        testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
+                false /*activityResizeable*/, false /*expected*/);
+
+        testSupportsLaunchingResizeable(true /*taskPresent*/, false /*taskResizeable*/,
+                true /*activityResizeable*/, false /*expected*/);
+
+        testSupportsLaunchingResizeable(true /*taskPresent*/, true /*taskResizeable*/,
+                false /*activityResizeable*/, true /*expected*/);
+    }
+
+    private void testSupportsLaunchingResizeable(boolean taskPresent, boolean taskResizeable,
+            boolean activityResizeable, boolean expected) {
+        final ActivityManagerService service = createActivityManagerService();
+        service.mSupportsMultiWindow = true;
+
+
+        final TaskRecord task = taskPresent
+                ? createTask(service, testActivityComponent, TEST_STACK_ID) : null;
+
+        if (task != null) {
+            task.setResizeMode(taskResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+                    : ActivityInfo.RESIZE_MODE_UNRESIZEABLE);
+        }
+
+        final ActivityRecord record = createActivity(service, secondaryActivityComponent,
+                task);
+        record.info.resizeMode = activityResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+                : ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
+        record.canBeLaunchedOnDisplay(Display.DEFAULT_DISPLAY);
+
+        assertEquals(((TestActivityStackSupervisor) service.mStackSupervisor)
+                .getLastResizeableFromCanPlaceEntityOnDisplay(), expected);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index a6c0cf1..04ddae9 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -163,6 +163,7 @@
      */
     protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
         private final ActivityDisplay mDisplay;
+        private boolean mLastResizeable;
 
         public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
             super(service, looper);
@@ -170,6 +171,22 @@
             mDisplay = new ActivityDisplay();
         }
 
+        // TODO: Use Mockito spy instead. Currently not possible due to TestActivityStackSupervisor
+        // access to ActivityDisplay
+        @Override
+        boolean canPlaceEntityOnDisplay(int displayId, boolean resizeable, int callingPid,
+                int callingUid, ActivityInfo activityInfo) {
+            mLastResizeable = resizeable;
+            return super.canPlaceEntityOnDisplay(displayId, resizeable, callingPid, callingUid,
+                    activityInfo);
+        }
+
+        // TODO: remove and use Mockito verify once {@link #canPlaceEntityOnDisplay} override is
+        // removed.
+        public boolean getLastResizeableFromCanPlaceEntityOnDisplay() {
+            return mLastResizeable;
+        }
+
         // No home stack is set.
         @Override
         void moveHomeStackToFront(String reason) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 629173d..7a53ef6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -161,7 +161,7 @@
 
             // Second byte is the MSG_LEN, length of the message
             // See 3GPP2 C.S0023 3.4.27
-            int size = data[1];
+            int size = data[1] & 0xFF;
 
             // Note: Data may include trailing FF's.  That's OK; message
             // should still parse correctly.