Merge "Add a null a check in fingerprint service" into pi-dev
diff --git a/api/test-current.txt b/api/test-current.txt
index f7bfeae..5cffd0e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -917,6 +917,7 @@
 
   public class TelephonyManager {
     method public int getCarrierIdListVersion();
+    method public void refreshUiccProfile();
     method public void setCarrierTestOverride(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff
   }
diff --git a/core/java/android/app/usage/EventList.java b/core/java/android/app/usage/EventList.java
new file mode 100644
index 0000000..aaae57e5
--- /dev/null
+++ b/core/java/android/app/usage/EventList.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.usage;
+
+import java.util.ArrayList;
+
+/**
+ * A container to keep {@link UsageEvents.Event usage events} in non-descending order of their
+ * {@link UsageEvents.Event#mTimeStamp timestamps}.
+ *
+ * @hide
+ */
+public class EventList {
+
+    private final ArrayList<UsageEvents.Event> mEvents;
+
+    /**
+     * Create a new event list with default capacity
+     */
+    public EventList() {
+        mEvents = new ArrayList<>();
+    }
+
+    /**
+     * Returns the size of the list
+     * @return the number of events in the list
+     */
+    public int size() {
+        return mEvents.size();
+    }
+
+    /**
+     * Removes all events from the list
+     */
+    public void clear() {
+        mEvents.clear();
+    }
+
+    /**
+     * Returns the {@link UsageEvents.Event event} at the specified position in this list.
+     * @param index the index of the event to return, such that {@code 0 <= index < size()}
+     * @return The {@link UsageEvents.Event event} at position {@code index}
+     */
+    public UsageEvents.Event get(int index) {
+        return mEvents.get(index);
+    }
+
+    /**
+     * Inserts the given {@link UsageEvents.Event event} into the list while keeping the list sorted
+     * based on the event {@link UsageEvents.Event#mTimeStamp timestamps}.
+     *
+     * @param event The event to insert
+     */
+    public void insert(UsageEvents.Event event) {
+        final int size = mEvents.size();
+        // fast case: just append if this is the latest event
+        if (size == 0 || event.mTimeStamp >= mEvents.get(size - 1).mTimeStamp) {
+            mEvents.add(event);
+            return;
+        }
+        // To minimize number of elements being shifted, insert at the first occurrence of the next
+        // greatest timestamp in the list.
+        final int insertIndex = firstIndexOnOrAfter(event.mTimeStamp + 1);
+        mEvents.add(insertIndex, event);
+    }
+
+    /**
+     * Finds the index of the first event whose timestamp is greater than or equal to the given
+     * timestamp.
+     *
+     * @param timeStamp The timestamp for which to search the list.
+     * @return The smallest {@code index} for which {@code (get(index).mTimeStamp >= timeStamp)} is
+     * {@code true}, or {@link #size() size} if no such {@code index} exists.
+     */
+    public int firstIndexOnOrAfter(long timeStamp) {
+        final int size = mEvents.size();
+        int result = size;
+        int lo = 0;
+        int hi = size - 1;
+        while (lo <= hi) {
+            final int mid = (lo + hi) >>> 1;
+            final long midTimeStamp = mEvents.get(mid).mTimeStamp;
+            if (midTimeStamp >= timeStamp) {
+                hi = mid - 1;
+                result = mid;
+            } else {
+                lo = mid + 1;
+            }
+        }
+        return result;
+    }
+}
diff --git a/core/java/android/app/usage/TimeSparseArray.java b/core/java/android/app/usage/TimeSparseArray.java
index 4ec0e9e..2bd6b24 100644
--- a/core/java/android/app/usage/TimeSparseArray.java
+++ b/core/java/android/app/usage/TimeSparseArray.java
@@ -27,14 +27,12 @@
 public class TimeSparseArray<E> extends LongSparseArray<E> {
     private static final String TAG = TimeSparseArray.class.getSimpleName();
 
+    private boolean mWtfReported;
+
     public TimeSparseArray() {
         super();
     }
 
-    public TimeSparseArray(int initialCapacity) {
-        super(initialCapacity);
-    }
-
     /**
      * Finds the index of the first element whose timestamp is greater or equal to
      * the given time.
@@ -75,22 +73,16 @@
     /**
      * {@inheritDoc}
      *
-     * Overridden to ensure no collisions. The key (time in milliseconds) is incremented till an
-     * empty place is found.
+     * <p> As this container is being used only to keep {@link android.util.AtomicFile files},
+     * there should not be any collisions. Reporting a {@link Slog#wtf(String, String)} in case that
+     * happens, as that will lead to one whole file being dropped.
      */
     @Override
     public void put(long key, E value) {
-        final long origKey = key;
-        int keyIndex = indexOfKey(key);
-        if (keyIndex >= 0) {
-            final long sz = size();
-            while (keyIndex < sz && keyAt(keyIndex) == key) {
-                key++;
-                keyIndex++;
-            }
-            if (key >= origKey + 100) {
-                Slog.w(TAG, "Value " + value + " supposed to be inserted at " + origKey
-                        + " displaced to " + key);
+        if (indexOfKey(key) >= 0) {
+            if (!mWtfReported) {
+                Slog.wtf(TAG, "Overwriting value " + get(key) + " by " + value);
+                mWtfReported = true;
             }
         }
         super.put(key, value);
diff --git a/core/tests/coretests/src/android/app/usage/EventListTest.java b/core/tests/coretests/src/android/app/usage/EventListTest.java
new file mode 100644
index 0000000..9dc0d43
--- /dev/null
+++ b/core/tests/coretests/src/android/app/usage/EventListTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.usage;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class EventListTest {
+    private static final String TAG = EventListTest.class.getSimpleName();
+
+    private UsageEvents.Event getUsageEvent(long timeStamp) {
+        final UsageEvents.Event event = new UsageEvents.Event();
+        event.mTimeStamp = timeStamp;
+        return event;
+    }
+
+    private static String getListTimeStamps(EventList list) {
+        final StringBuilder builder = new StringBuilder("[");
+        for (int i = 0; i < list.size() - 1; i++) {
+            builder.append(list.get(i).mTimeStamp);
+            builder.append(", ");
+        }
+        builder.append(list.get(list.size() - 1).mTimeStamp);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    private static void assertSorted(EventList eventList) {
+        for (int i = 1; i < eventList.size(); i++) {
+            final long lastTimeStamp = eventList.get(i - 1).mTimeStamp;
+            if (eventList.get(i).mTimeStamp < lastTimeStamp) {
+                Log.e(TAG, "Unsorted timestamps in list: " + getListTimeStamps(eventList));
+                fail("Timestamp " + eventList.get(i).mTimeStamp + " at " + i
+                        + " follows larger timestamp " + lastTimeStamp);
+            }
+        }
+    }
+
+    @Test
+    public void testInsertsSortedRandom() {
+        final Random random = new Random(128);
+        final EventList listUnderTest = new EventList();
+        for (int i = 0; i < 100; i++) {
+            listUnderTest.insert(getUsageEvent(random.nextLong()));
+        }
+        assertSorted(listUnderTest);
+    }
+
+    @Test
+    public void testInsertsSortedWithDuplicates() {
+        final Random random = new Random(256);
+        final EventList listUnderTest = new EventList();
+        for (int i = 0; i < 10; i++) {
+            final long randomTimeStamp = random.nextLong();
+            for (int j = 0; j < 10; j++) {
+                listUnderTest.insert(getUsageEvent(randomTimeStamp));
+            }
+        }
+        assertSorted(listUnderTest);
+    }
+
+    @Test
+    public void testFirstIndexOnOrAfter() {
+        final EventList listUnderTest = new EventList();
+        listUnderTest.insert(getUsageEvent(2));
+        listUnderTest.insert(getUsageEvent(5));
+        listUnderTest.insert(getUsageEvent(5));
+        listUnderTest.insert(getUsageEvent(5));
+        listUnderTest.insert(getUsageEvent(8));
+        assertTrue(listUnderTest.firstIndexOnOrAfter(1) == 0);
+        assertTrue(listUnderTest.firstIndexOnOrAfter(2) == 0);
+        assertTrue(listUnderTest.firstIndexOnOrAfter(3) == 1);
+        assertTrue(listUnderTest.firstIndexOnOrAfter(4) == 1);
+        assertTrue(listUnderTest.firstIndexOnOrAfter(5) == 1);
+        assertTrue(listUnderTest.firstIndexOnOrAfter(6) == 4);
+        assertTrue(listUnderTest.firstIndexOnOrAfter(7) == 4);
+        assertTrue(listUnderTest.firstIndexOnOrAfter(8) == 4);
+        assertTrue(listUnderTest.firstIndexOnOrAfter(9) == listUnderTest.size());
+        assertTrue(listUnderTest.firstIndexOnOrAfter(100) == listUnderTest.size());
+
+        listUnderTest.clear();
+        assertTrue(listUnderTest.firstIndexOnOrAfter(5) == 0);
+        assertTrue(listUnderTest.firstIndexOnOrAfter(100) == 0);
+    }
+
+    @Test
+    public void testClear() {
+        final EventList listUnderTest = new EventList();
+        for (int i = 1; i <= 100; i++) {
+            listUnderTest.insert(getUsageEvent(i));
+        }
+        listUnderTest.clear();
+        assertEquals(0, listUnderTest.size());
+    }
+
+    @Test
+    public void testSize() {
+        final EventList listUnderTest = new EventList();
+        for (int i = 1; i <= 100; i++) {
+            listUnderTest.insert(getUsageEvent(i));
+        }
+        assertEquals(100, listUnderTest.size());
+    }
+}
diff --git a/core/tests/coretests/src/android/app/usage/TimeSparseArrayTest.java b/core/tests/coretests/src/android/app/usage/TimeSparseArrayTest.java
deleted file mode 100644
index db46740..0000000
--- a/core/tests/coretests/src/android/app/usage/TimeSparseArrayTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.app.usage;
-
-import static org.junit.Assert.assertTrue;
-
-import android.os.SystemClock;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class TimeSparseArrayTest {
-    @Test
-    public void testDuplicateKeysNotDropped() {
-        final TimeSparseArray<Integer> testTimeSparseArray = new TimeSparseArray<>();
-        final long key = SystemClock.elapsedRealtime();
-        for (int i = 0; i < 5; i++) {
-            testTimeSparseArray.put(key, i);
-        }
-        for (int i = 0; i < 5; i++) {
-            final int valueIndex = testTimeSparseArray.indexOfValue(i);
-            assertTrue("Value " + i + " not found; intended key: " + key , valueIndex >= 0);
-            final long keyForValue = testTimeSparseArray.keyAt(valueIndex);
-            assertTrue("Value " + i + " stored too far (at " + keyForValue + ") from intended key "
-                    + key, Math.abs(keyForValue - key) < 100);
-        }
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index 8d451c1..5a0dddc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -33,10 +33,21 @@
      * touch slop is when the respected operation will occur when exceeded. Touch slop must be
      * larger than the drag slop.
      */
-    public static final int QUICK_STEP_DRAG_SLOP_PX = convertDpToPixel(10);
-    public static final int QUICK_SCRUB_DRAG_SLOP_PX = convertDpToPixel(20);
-    public static final int QUICK_STEP_TOUCH_SLOP_PX = convertDpToPixel(24);
-    public static final int QUICK_SCRUB_TOUCH_SLOP_PX = convertDpToPixel(35);
+    public static int getQuickStepDragSlopPx() {
+        return convertDpToPixel(10);
+    }
+
+    public static int getQuickScrubDragSlopPx() {
+        return convertDpToPixel(20);
+    }
+
+    public static int getQuickStepTouchSlopPx() {
+        return convertDpToPixel(24);
+    }
+
+    public static int getQuickScrubTouchSlopPx() {
+        return convertDpToPixel(35);
+    }
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME, HIT_TARGET_OVERVIEW})
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 5597ffd..2ddae74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -281,6 +281,7 @@
 
         IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
         filter.addAction(Intent.ACTION_SCREEN_ON);
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
         getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
         notifyNavigationBarScreenOn();
         mOverviewProxyService.addCallback(mOverviewProxyListener);
@@ -1084,6 +1085,10 @@
                     || Intent.ACTION_SCREEN_ON.equals(action)) {
                 notifyNavigationBarScreenOn();
             }
+            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                // The accessibility settings may be different for the new user
+                updateAccessibilityServicesState(mAccessibilityManager);
+            };
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index ff5d0e3..6b0ac94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -34,7 +34,6 @@
 import android.util.Slog;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.WindowManagerGlobal;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -45,16 +44,13 @@
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.system.NavigationBarCompat;
 
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
 import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
 import static com.android.systemui.OverviewProxyService.TAG_OPS;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
-import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_SCRUB_DRAG_SLOP_PX;
-import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_SCRUB_TOUCH_SLOP_PX;
-import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_STEP_DRAG_SLOP_PX;
-import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_STEP_TOUCH_SLOP_PX;
 
 /**
  * Class to detect gestures on the navigation bar and implement quick scrub.
@@ -215,17 +211,23 @@
                 int pos, touchDown, offset, trackSize;
 
                 if (mIsVertical) {
-                    exceededScrubTouchSlop = yDiff > QUICK_SCRUB_TOUCH_SLOP_PX && yDiff > xDiff;
-                    exceededSwipeUpTouchSlop = xDiff > QUICK_STEP_TOUCH_SLOP_PX && xDiff > yDiff;
-                    exceededScrubDragSlop = yDiff > QUICK_SCRUB_DRAG_SLOP_PX && yDiff > xDiff;
+                    exceededScrubTouchSlop =
+                            yDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && yDiff > xDiff;
+                    exceededSwipeUpTouchSlop =
+                            xDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && xDiff > yDiff;
+                    exceededScrubDragSlop =
+                            yDiff > NavigationBarCompat.getQuickScrubDragSlopPx() && yDiff > xDiff;
                     pos = y;
                     touchDown = mTouchDownY;
                     offset = pos - mTrackRect.top;
                     trackSize = mTrackRect.height();
                 } else {
-                    exceededScrubTouchSlop = xDiff > QUICK_SCRUB_TOUCH_SLOP_PX && xDiff > yDiff;
-                    exceededSwipeUpTouchSlop = yDiff > QUICK_STEP_TOUCH_SLOP_PX && yDiff > xDiff;
-                    exceededScrubDragSlop = xDiff > QUICK_SCRUB_DRAG_SLOP_PX && xDiff > yDiff;
+                    exceededScrubTouchSlop =
+                            xDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && xDiff > yDiff;
+                    exceededSwipeUpTouchSlop =
+                            yDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && yDiff > xDiff;
+                    exceededScrubDragSlop =
+                            xDiff > NavigationBarCompat.getQuickScrubDragSlopPx() && xDiff > yDiff;
                     pos = x;
                     touchDown = mTouchDownX;
                     offset = pos - mTrackRect.left;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 22a48f0..85cfde8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -49,12 +49,11 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.NavigationBarCompat;
 
 import static android.view.KeyEvent.KEYCODE_HOME;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
-import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_SCRUB_TOUCH_SLOP_PX;
-import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_STEP_TOUCH_SLOP_PX;
 
 public class KeyButtonView extends ImageView implements ButtonInterface {
     private static final String TAG = KeyButtonView.class.getSimpleName();
@@ -234,10 +233,12 @@
                 x = (int)ev.getRawX();
                 y = (int)ev.getRawY();
 
-                boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) >
-                        (mIsVertical ? QUICK_SCRUB_TOUCH_SLOP_PX : QUICK_STEP_TOUCH_SLOP_PX);
-                boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) >
-                        (mIsVertical ? QUICK_STEP_TOUCH_SLOP_PX : QUICK_SCRUB_TOUCH_SLOP_PX);
+                boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > (mIsVertical
+                        ? NavigationBarCompat.getQuickScrubTouchSlopPx()
+                        : NavigationBarCompat.getQuickStepTouchSlopPx());
+                boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > (mIsVertical
+                        ? NavigationBarCompat.getQuickStepTouchSlopPx()
+                        : NavigationBarCompat.getQuickScrubTouchSlopPx());
                 if (exceededTouchSlopX || exceededTouchSlopY) {
                     // When quick step is enabled, prevent animating the ripple triggered by
                     // setPressed and decide to run it on touch up
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 83fe976..59bf2a2 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -351,7 +351,7 @@
             mCallForwarding[i] =  false;
             mCellLocation[i] = new Bundle();
             mCellInfo.add(i, null);
-            mPhysicalChannelConfigs.add(i, null);
+            mPhysicalChannelConfigs.add(i, new ArrayList<PhysicalChannelConfig>());
         }
 
         // Note that location can be null for non-phone builds like
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 228171f..f413639 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -422,13 +422,9 @@
         }
 
         // If we're starting indirectly (e.g. from PendingIntent), figure out whether
-        // we're launching into an app in a background state.
-        final int uidState = mAm.getUidStateLocked(r.appInfo.uid);
-        if (DEBUG_SERVICE) {
-            Slog.v(TAG_SERVICE, "Uid state " + uidState + " indirect starting " + r.shortName);
-        }
-        final boolean bgLaunch = (uidState >
-                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+        // we're launching into an app in a background state.  This keys off of the same
+        // idleness state tracking as e.g. O+ background service start policy.
+        final boolean bgLaunch = !mAm.isUidActiveLocked(r.appInfo.uid);
 
         // If the app has strict background restrictions, we treat any bg service
         // start analogously to the legacy-app forced-restrictions case, regardless
@@ -1197,10 +1193,13 @@
 
                 if (!ignoreForeground &&
                         appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
-                    ignoreForeground = true;
                     Slog.w(TAG,
                             "Service.startForeground() not allowed due to bg restriction: service "
                             + r.shortName);
+                    // Back off of any foreground expectations around this service, since we've
+                    // just turned down its fg request.
+                    updateServiceForegroundLocked(r.app, false);
+                    ignoreForeground = true;
                 }
 
                 // Apps under strict background restrictions simply don't get to have foreground
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7170119..ac06ddd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26626,8 +26626,7 @@
         @Override
         public boolean isUidActive(int uid) {
             synchronized (ActivityManagerService.this) {
-                final UidRecord uidRec = mActiveUids.get(uid);
-                return (uidRec != null) && !uidRec.idle;
+                return isUidActiveLocked(uid);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 674414f..86aed47 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3865,9 +3865,13 @@
         windowInfo.title = mAttrs.accessibilityTitle;
         // Panel windows have no public way to set the a11y title directly. Use the
         // regular title as a fallback.
-        if (TextUtils.isEmpty(windowInfo.title)
-                && (mAttrs.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW)
-                && (mAttrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW)) {
+        final boolean isPanelWindow = (mAttrs.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW)
+                && (mAttrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW);
+        // Accessibility overlays should have titles that work for accessibility, and can't set
+        // the a11y title themselves.
+        final boolean isAccessibilityOverlay =
+                windowInfo.type == WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+        if (TextUtils.isEmpty(windowInfo.title) && (isPanelWindow || isAccessibilityOverlay)) {
             windowInfo.title = mAttrs.getTitle();
         }
         windowInfo.accessibilityIdOfAnchor = mAttrs.accessibilityIdOfAnchor;
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index c914689..0dce738 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -16,6 +16,7 @@
 package com.android.server.usage;
 
 import android.app.usage.ConfigurationStats;
+import android.app.usage.EventList;
 import android.app.usage.EventStats;
 import android.app.usage.TimeSparseArray;
 import android.app.usage.UsageEvents;
@@ -37,7 +38,7 @@
     public final ArrayMap<String, UsageStats> packageStats = new ArrayMap<>();
     public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>();
     public Configuration activeConfiguration;
-    public TimeSparseArray<UsageEvents.Event> events;
+    public EventList events;
 
     // A string cache. This is important as when we're parsing XML files, we don't want to
     // keep hundreds of strings that have the same contents. We will read the string
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index fe3a884..aa832ad 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -22,12 +22,11 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import android.app.usage.ConfigurationStats;
-import android.app.usage.TimeSparseArray;
+import android.app.usage.EventList;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStats;
 import android.content.res.Configuration;
 import android.util.ArrayMap;
-import android.util.Pair;
 
 import java.io.IOException;
 import java.net.ProtocolException;
@@ -193,9 +192,9 @@
         }
 
         if (statsOut.events == null) {
-            statsOut.events = new TimeSparseArray<>();
+            statsOut.events = new EventList();
         }
-        statsOut.events.put(event.mTimeStamp, event);
+        statsOut.events.insert(event);
     }
 
     private static void writeUsageStats(XmlSerializer xml, final IntervalStats stats,
@@ -411,7 +410,7 @@
         xml.startTag(null, EVENT_LOG_TAG);
         final int eventCount = stats.events != null ? stats.events.size() : 0;
         for (int i = 0; i < eventCount; i++) {
-            writeEvent(xml, stats, stats.events.valueAt(i));
+            writeEvent(xml, stats, stats.events.get(i));
         }
         xml.endTag(null, EVENT_LOG_TAG);
     }
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index d9fc066..9cb98f3 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -17,15 +17,14 @@
 package com.android.server.usage;
 
 import android.app.usage.ConfigurationStats;
+import android.app.usage.EventList;
 import android.app.usage.EventStats;
-import android.app.usage.TimeSparseArray;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.content.res.Configuration;
 import android.os.SystemClock;
 import android.content.Context;
-import android.text.format.DateFormat;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -174,10 +173,10 @@
 
         // Add the event to the daily list.
         if (currentDailyStats.events == null) {
-            currentDailyStats.events = new TimeSparseArray<>();
+            currentDailyStats.events = new EventList();
         }
         if (event.mEventType != UsageEvents.Event.SYSTEM_INTERACTION) {
-            currentDailyStats.events.put(event.mTimeStamp, event);
+            currentDailyStats.events.insert(event);
         }
 
         boolean incrementAppLaunch = false;
@@ -367,18 +366,14 @@
                             return;
                         }
 
-                        final int startIndex = stats.events.closestIndexOnOrAfter(beginTime);
-                        if (startIndex < 0) {
-                            return;
-                        }
-
+                        final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
                         final int size = stats.events.size();
                         for (int i = startIndex; i < size; i++) {
-                            if (stats.events.keyAt(i) >= endTime) {
+                            if (stats.events.get(i).mTimeStamp >= endTime) {
                                 return;
                             }
 
-                            UsageEvents.Event event = stats.events.valueAt(i);
+                            UsageEvents.Event event = stats.events.get(i);
                             if (obfuscateInstantApps) {
                                 event = event.getObfuscatedIfInstantApp();
                             }
@@ -410,18 +405,14 @@
                         return;
                     }
 
-                    final int startIndex = stats.events.closestIndexOnOrAfter(beginTime);
-                    if (startIndex < 0) {
-                        return;
-                    }
-
+                    final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
                     final int size = stats.events.size();
                     for (int i = startIndex; i < size; i++) {
-                        if (stats.events.keyAt(i) >= endTime) {
+                        if (stats.events.get(i).mTimeStamp >= endTime) {
                             return;
                         }
 
-                        final UsageEvents.Event event = stats.events.valueAt(i);
+                        final UsageEvents.Event event = stats.events.get(i);
                         if (!packageName.equals(event.mPackage)) {
                             continue;
                         }
@@ -633,18 +624,14 @@
                             return;
                         }
 
-                        final int startIndex = stats.events.closestIndexOnOrAfter(beginTime);
-                        if (startIndex < 0) {
-                            return;
-                        }
-
+                        final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
                         final int size = stats.events.size();
                         for (int i = startIndex; i < size; i++) {
-                            if (stats.events.keyAt(i) >= endTime) {
+                            if (stats.events.get(i).mTimeStamp >= endTime) {
                                 return;
                             }
 
-                            UsageEvents.Event event = stats.events.valueAt(i);
+                            UsageEvents.Event event = stats.events.get(i);
                             if (pkg != null && !pkg.equals(event.mPackage)) {
                                 continue;
                             }
@@ -779,10 +766,10 @@
         if (!skipEvents) {
             pw.println("events");
             pw.increaseIndent();
-            final TimeSparseArray<UsageEvents.Event> events = stats.events;
+            final EventList events = stats.events;
             final int eventCount = events != null ? events.size() : 0;
             for (int i = 0; i < eventCount; i++) {
-                final UsageEvents.Event event = events.valueAt(i);
+                final UsageEvents.Event event = events.get(i);
                 if (pkg != null && !pkg.equals(event.mPackage)) {
                     continue;
                 }
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 0ff2982..1524c6d 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -578,7 +579,8 @@
      * @param configs List of the current {@link PhysicalChannelConfig}s
      * @hide
      */
-    public void onPhysicalChannelConfigurationChanged(List<PhysicalChannelConfig> configs) {
+    public void onPhysicalChannelConfigurationChanged(
+            @NonNull List<PhysicalChannelConfig> configs) {
         // default implementation empty
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3880f2f..917cfb4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2786,6 +2786,22 @@
     }
 
     /**
+     * Test method to reload the UICC profile.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public void refreshUiccProfile() {
+        try {
+            ITelephony telephony = getITelephony();
+            telephony.refreshUiccProfile(mSubId);
+        } catch (RemoteException ex) {
+            Rlog.w(TAG, "RemoteException", ex);
+        }
+    }
+
+    /**
      * Map logicalSlot to physicalSlot, and activate the physicalSlot if it is inactive. For
      * example, passing the physicalSlots array [1, 0] means mapping the first item 1, which is
      * physical slot index 1, to the logical slot 0; and mapping the second item 0, which is
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7e8b2de..27facef 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1509,4 +1509,10 @@
      * A test API to return installed carrier id list version.
      */
     int getCarrierIdListVersion(int subId);
+
+    /**
+     * A test API to reload the UICC profile.
+     * @hide
+     */
+    void refreshUiccProfile(int subId);
 }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index a7fffca..b333126 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -85,7 +85,7 @@
 
     boolean disableNetwork(int netId, String packageName);
 
-    boolean startScan(String packageName);
+    void startScan(String packageName);
 
     List<ScanResult> getScanResults(String callingPackage);
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a19965d..9c6c8a9 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1635,7 +1635,8 @@
     public boolean startScan(WorkSource workSource) {
         try {
             String packageName = mContext.getOpPackageName();
-            return mService.startScan(packageName);
+            mService.startScan(packageName);
+            return true;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 20e49cd..f3ffcad 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1070,16 +1070,4 @@
             fail("setWifiApConfiguration should rethrow Exceptions from WifiService");
         } catch (SecurityException e) { }
     }
-
-    /**
-     * Check the call to startScan calls WifiService.
-     */
-    @Test
-    public void testStartScan() throws Exception {
-        when(mWifiService.startScan(TEST_PACKAGE_NAME)).thenReturn(true);
-        assertTrue(mWifiManager.startScan());
-
-        when(mWifiService.startScan(TEST_PACKAGE_NAME)).thenReturn(false);
-        assertFalse(mWifiManager.startScan());
-    }
 }