Merge "Fix history task stack" into rvc-dev
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 37f683e..33bacf0 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1083,7 +1083,7 @@
      * @hide
      */
     public static final int OP_ACTIVATE_PLATFORM_VPN = AppProtoEnums.APP_OP_ACTIVATE_PLATFORM_VPN;
-    /** @hide */
+    /** @hide Controls whether or not read logs are available for incremental installations. */
     public static final int OP_LOADER_USAGE_STATS = AppProtoEnums.APP_OP_LOADER_USAGE_STATS;
 
     // App op deprecated/removed.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6a5e6ca..2a11fff 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5951,9 +5951,9 @@
     /**
      * Return the label to use for this application.
      *
-     * @return Returns the label associated with this application, or null if
-     * it could not be found for any reason.
-     * @param info The application to get the label of.
+     * @return Returns a {@link CharSequence} containing the label associated with
+     * this application, or its name the  item does not have a label.
+     * @param info The {@link ApplicationInfo} of the application to get the label of.
      */
     @NonNull
     public abstract CharSequence getApplicationLabel(@NonNull ApplicationInfo info);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index da2a56d..5239a37 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -170,7 +170,7 @@
     private INotificationManager mINotificationManager;
 
     // Callback that updates BubbleOverflowActivity on data change.
-    @Nullable private Runnable mOverflowCallback = null;
+    @Nullable private BubbleData.Listener mOverflowListener = null;
 
     private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
     private IStatusBarService mBarService;
@@ -577,8 +577,8 @@
         mInflateSynchronously = inflateSynchronously;
     }
 
-    void setOverflowCallback(Runnable updateOverflow) {
-        mOverflowCallback = updateOverflow;
+    void setOverflowListener(BubbleData.Listener listener) {
+        mOverflowListener = listener;
     }
 
     /**
@@ -948,8 +948,8 @@
         @Override
         public void applyUpdate(BubbleData.Update update) {
             // Update bubbles in overflow.
-            if (mOverflowCallback != null) {
-                mOverflowCallback.run();
+            if (mOverflowListener != null) {
+                mOverflowListener.applyUpdate(update);
             }
 
             // Collapsing? Do this first before remaining steps.
@@ -973,7 +973,8 @@
                     if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
                         && (!bubble.showInShade()
                             || reason == DISMISS_NOTIF_CANCEL
-                            || reason == DISMISS_GROUP_CANCELLED)) {
+                            || reason == DISMISS_GROUP_CANCELLED
+                            || reason == DISMISS_OVERFLOW_MAX_REACHED)) {
                         // The bubble is now gone & the notification is hidden from the shade, so
                         // time to actually remove it
                         for (NotifCallback cb : mCallbacks) {
@@ -1040,9 +1041,6 @@
                     Log.d(TAG, BubbleDebugConfig.formatBubblesString(mStackView.getBubblesOnScreen(),
                             mStackView.getExpandedBubble()));
                 }
-                Log.d(TAG, "\n[BubbleData] overflow:");
-                Log.d(TAG, BubbleDebugConfig.formatBubblesString(mBubbleData.getOverflowBubbles(),
-                        null) + "\n");
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index b773bdb..2ac60f2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -74,6 +74,8 @@
         @Nullable Bubble selectedBubble;
         @Nullable Bubble addedBubble;
         @Nullable Bubble updatedBubble;
+        @Nullable Bubble addedOverflowBubble;
+        @Nullable Bubble removedOverflowBubble;
         // Pair with Bubble and @DismissReason Integer
         final List<Pair<Bubble, Integer>> removedBubbles = new ArrayList<>();
 
@@ -92,10 +94,12 @@
                     || addedBubble != null
                     || updatedBubble != null
                     || !removedBubbles.isEmpty()
+                    || addedOverflowBubble != null
+                    || removedOverflowBubble != null
                     || orderChanged;
         }
 
-        void bubbleRemoved(Bubble bubbleToRemove, @DismissReason  int reason) {
+        void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) {
             removedBubbles.add(new Pair<>(bubbleToRemove, reason));
         }
     }
@@ -233,6 +237,7 @@
 
     private void moveOverflowBubbleToPending(Bubble b) {
         mOverflowBubbles.remove(b);
+        mStateChange.removedOverflowBubble = b;
         mPendingBubbles.add(b);
     }
 
@@ -440,8 +445,9 @@
                 if (DEBUG_BUBBLE_DATA) {
                     Log.d(TAG, "Cancel overflow bubble: " + b);
                 }
-                mStateChange.bubbleRemoved(b, reason);
                 mOverflowBubbles.remove(b);
+                mStateChange.bubbleRemoved(b, reason);
+                mStateChange.removedOverflowBubble = b;
             }
             return;
         }
@@ -482,6 +488,7 @@
             Log.d(TAG, "Overflowing: " + bubble);
         }
         mOverflowBubbles.add(0, bubble);
+        mStateChange.addedOverflowBubble = bubble;
         bubble.stopInflation();
         if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
             // Remove oldest bubble.
@@ -489,8 +496,9 @@
             if (DEBUG_BUBBLE_DATA) {
                 Log.d(TAG, "Overflow full. Remove: " + oldest);
             }
-            mStateChange.bubbleRemoved(oldest, BubbleController.DISMISS_OVERFLOW_MAX_REACHED);
             mOverflowBubbles.remove(oldest);
+            mStateChange.removedOverflowBubble = oldest;
+            mStateChange.bubbleRemoved(oldest, BubbleController.DISMISS_OVERFLOW_MAX_REACHED);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index 13bc55c..de54c35 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -106,11 +106,12 @@
         mAdapter = new BubbleOverflowAdapter(mOverflowBubbles,
                 mBubbleController::promoteBubbleFromOverflow, viewWidth, viewHeight);
         mRecyclerView.setAdapter(mAdapter);
-        onDataChanged(mBubbleController.getOverflowBubbles());
-        mBubbleController.setOverflowCallback(() -> {
-            onDataChanged(mBubbleController.getOverflowBubbles());
-        });
-        onThemeChanged();
+
+        mOverflowBubbles.addAll(mBubbleController.getOverflowBubbles());
+        mAdapter.notifyDataSetChanged();
+        setEmptyStateVisibility();
+
+        mBubbleController.setOverflowListener(mDataListener);
     }
 
     /**
@@ -137,6 +138,14 @@
         }
     }
 
+    void setEmptyStateVisibility() {
+        if (mOverflowBubbles.isEmpty()) {
+            mEmptyState.setVisibility(View.VISIBLE);
+        } else {
+            mEmptyState.setVisibility(View.GONE);
+        }
+    }
+
     void setBackgroundColor() {
         final TypedArray ta = getApplicationContext().obtainStyledAttributes(
                 new int[]{android.R.attr.colorBackgroundFloating});
@@ -145,22 +154,40 @@
         findViewById(android.R.id.content).setBackgroundColor(bgColor);
     }
 
-    void onDataChanged(List<Bubble> bubbles) {
-        mOverflowBubbles.clear();
-        mOverflowBubbles.addAll(bubbles);
-        mAdapter.notifyDataSetChanged();
+    private final BubbleData.Listener mDataListener = new BubbleData.Listener() {
 
-        if (mOverflowBubbles.isEmpty()) {
-            mEmptyState.setVisibility(View.VISIBLE);
-        } else {
-            mEmptyState.setVisibility(View.GONE);
-        }
+        @Override
+        public void applyUpdate(BubbleData.Update update) {
 
-        if (DEBUG_OVERFLOW) {
-            Log.d(TAG, "Updated overflow bubbles:\n" + BubbleDebugConfig.formatBubblesString(
-                    mOverflowBubbles, /*selected*/ null));
+            Bubble toRemove = update.removedOverflowBubble;
+            if (toRemove != null) {
+                if (DEBUG_OVERFLOW) {
+                    Log.d(TAG, "remove: " + toRemove);
+                }
+                toRemove.cleanupViews();
+                int i = mOverflowBubbles.indexOf(toRemove);
+                mOverflowBubbles.remove(toRemove);
+                mAdapter.notifyItemRemoved(i);
+            }
+
+            Bubble toAdd = update.addedOverflowBubble;
+            if (toAdd != null) {
+                if (DEBUG_OVERFLOW) {
+                    Log.d(TAG, "add: " + toAdd);
+                }
+                mOverflowBubbles.add(0, toAdd);
+                mAdapter.notifyItemInserted(0);
+            }
+
+            setEmptyStateVisibility();
+
+            if (DEBUG_OVERFLOW) {
+                Log.d(TAG, BubbleDebugConfig.formatBubblesString(
+                        mBubbleController.getOverflowBubbles(),
+                        null));
+            }
         }
-    }
+    };
 
     @Override
     public void onStart() {
@@ -226,6 +253,7 @@
         Bubble b = mBubbles.get(index);
 
         vh.iconView.setRenderedBubble(b);
+        vh.iconView.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
         vh.iconView.setOnClickListener(view -> {
             mBubbles.remove(b);
             notifyDataSetChanged();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 90ca83e..1e247f2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4420,6 +4420,11 @@
         if (getInstantAppPackageName(callingUid) != null) {
             throw new SecurityException("Instant applications don't have access to this method");
         }
+        if (!mUserManager.exists(userId)) {
+            throw new SecurityException("User doesn't exist");
+        }
+        mPermissionManager.enforceCrossUserPermission(
+                callingUid, userId, false, false, "checkPackageStartable");
         final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId);
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -5777,9 +5782,15 @@
 
     @Override
     public ChangedPackages getChangedPackages(int sequenceNumber, int userId) {
-        if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+        final int callingUid = Binder.getCallingUid();
+        if (getInstantAppPackageName(callingUid) != null) {
             return null;
         }
+        if (!mUserManager.exists(userId)) {
+            return null;
+        }
+        mPermissionManager.enforceCrossUserPermission(
+                callingUid, userId, false, false, "getChangedPackages");
         synchronized (mLock) {
             if (sequenceNumber >= mChangedPackagesSequenceNumber) {
                 return null;
@@ -8772,8 +8783,10 @@
 
     private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
         if (!mUserManager.exists(userId)) return null;
-        flags = updateFlagsForComponent(flags, userId);
         final int callingUid = Binder.getCallingUid();
+        mPermissionManager.enforceCrossUserPermission(
+                callingUid, userId, false, false, "resolveContentProvider");
+        flags = updateFlagsForComponent(flags, userId);
         final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
         if (providerInfo == null) {
             return null;
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index edb6d65..05879ec 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -21,7 +21,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.SharedLibraryInfo;
 
 import com.android.internal.util.DataClass;
@@ -64,6 +63,12 @@
     }
 
     public PackageStateUnserialized setLastPackageUsageTimeInMills(int reason, long time) {
+        if (reason < 0) {
+            return this;
+        }
+        if (reason >= PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT) {
+            return this;
+        }
         getLastPackageUsageTimeInMills()[reason] = time;
         return this;
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 7c3efeb..1cfbad9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -20,6 +20,7 @@
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 
 import android.content.pm.PackageManager;
@@ -32,6 +33,8 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.pm.pkg.PackageStateUnserialized;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -300,4 +303,55 @@
         // Everything is different
         assertThat(params1.equals(params2), is(false));
     }
+
+    /**
+     * Test fix for b/149772100.
+     */
+    private static void assertLastPackageUsageUnset(
+            PackageStateUnserialized state) throws Exception {
+        for (int i = state.getLastPackageUsageTimeInMills().length - 1; i >= 0; --i) {
+            assertEquals(0L, state.getLastPackageUsageTimeInMills()[i]);
+        }
+    }
+    private static void assertLastPackageUsageSet(
+            PackageStateUnserialized state, int reason, long value) throws Exception {
+        for (int i = state.getLastPackageUsageTimeInMills().length - 1; i >= 0; --i) {
+            if (i == reason) {
+                assertEquals(value, state.getLastPackageUsageTimeInMills()[i]);
+            } else {
+                assertEquals(0L, state.getLastPackageUsageTimeInMills()[i]);
+            }
+        }
+    }
+    @Test
+    public void testPackageUseReasons() throws Exception {
+        final PackageStateUnserialized testState1 = new PackageStateUnserialized();
+        testState1.setLastPackageUsageTimeInMills(-1, 10L);
+        assertLastPackageUsageUnset(testState1);
+
+        final PackageStateUnserialized testState2 = new PackageStateUnserialized();
+        testState2.setLastPackageUsageTimeInMills(
+                PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT, 20L);
+        assertLastPackageUsageUnset(testState2);
+
+        final PackageStateUnserialized testState3 = new PackageStateUnserialized();
+        testState3.setLastPackageUsageTimeInMills(Integer.MAX_VALUE, 30L);
+        assertLastPackageUsageUnset(testState3);
+
+        final PackageStateUnserialized testState4 = new PackageStateUnserialized();
+        testState4.setLastPackageUsageTimeInMills(0, 40L);
+        assertLastPackageUsageSet(testState4, 0, 40L);
+
+        final PackageStateUnserialized testState5 = new PackageStateUnserialized();
+        testState5.setLastPackageUsageTimeInMills(
+                PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER, 50L);
+        assertLastPackageUsageSet(
+                testState5, PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER, 50L);
+
+        final PackageStateUnserialized testState6 = new PackageStateUnserialized();
+        testState6.setLastPackageUsageTimeInMills(
+                PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT - 1, 60L);
+        assertLastPackageUsageSet(
+                testState6, PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT - 1, 60L);
+    }
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6b285d7..477bb1f 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3053,20 +3053,21 @@
      * This configuration allows the system UI to determine how long to continue to display 5G icons
      * when the device switches between different 5G scenarios.
      *
-     * There are six 5G scenarios:
+     * There are seven 5G scenarios:
      * 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using
      *    millimeter wave.
      * 2. connected: device currently connected to 5G cell as the secondary cell but not using
      *    millimeter wave.
-     * 3. not_restricted_rrc_idle: device camped on a network that has 5G capability(not necessary
+     * 3. not_restricted_rrc_idle: device camped on a network that has 5G capability (not necessary
      *    to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
      *    currently in IDLE state.
-     * 4. not_restricted_rrc_con: device camped on a network that has 5G capability(not necessary
+     * 4. not_restricted_rrc_con: device camped on a network that has 5G capability (not necessary
      *    to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
      *    currently in CONNECTED state.
-     * 5. restricted: device camped on a network that has 5G capability(not necessary to connect a
+     * 5. restricted: device camped on a network that has 5G capability (not necessary to connect a
      *    5G cell as a secondary cell) but the use of 5G is restricted.
-     * 6. any: any of the above scenarios, as well as none (not connected to 5G)
+     * 6. legacy: device is not camped on a network that has 5G capability
+     * 7. any: any of the above scenarios
      *
      * The configured string contains various timer rules separated by a semicolon.
      * Each rule will have three items: prior 5G scenario, current 5G scenario, and grace period
@@ -3098,20 +3099,21 @@
      * This configuration extends {@link #KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING} to allow the
      * system UI to continue displaying 5G icons after the initial timer expires.
      *
-     * There are six 5G scenarios:
+     * There are seven 5G scenarios:
      * 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using
      *    millimeter wave.
      * 2. connected: device currently connected to 5G cell as the secondary cell but not using
      *    millimeter wave.
-     * 3. not_restricted_rrc_idle: device camped on a network that has 5G capability(not necessary
+     * 3. not_restricted_rrc_idle: device camped on a network that has 5G capability (not necessary
      *    to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
      *    currently in IDLE state.
-     * 4. not_restricted_rrc_con: device camped on a network that has 5G capability(not necessary
+     * 4. not_restricted_rrc_con: device camped on a network that has 5G capability (not necessary
      *    to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC
      *    currently in CONNECTED state.
-     * 5. restricted: device camped on a network that has 5G capability(not necessary to connect a
+     * 5. restricted: device camped on a network that has 5G capability (not necessary to connect a
      *    5G cell as a secondary cell) but the use of 5G is restricted.
-     * 6. any: any of the above scenarios, as well as none (not connected to 5G)
+     * 6. legacy: device is not camped on a network that has 5G capability
+     * 7. any: any of the above scenarios
      *
      * The configured string contains various timer rules separated by a semicolon.
      * Each rule will have three items: primary 5G scenario, secondary 5G scenario, and
@@ -4203,7 +4205,7 @@
         sDefaults.putStringArray(KEY_BANDWIDTH_STRING_ARRAY, new String[]{
                 "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA-IS95A:14,14", "CDMA-IS95B:14,14",
                 "1xRTT:30,30", "EvDo-rev.0:750,48", "EvDo-rev.A:950,550", "HSDPA:4300,620",
-                "HSUPA:4300,1800", "HSPA:4300,1800", "EvDo-rev.B:1500,550:", "eHRPD:750,48",
+                "HSUPA:4300,1800", "HSPA:4300,1800", "EvDo-rev.B:1500,550", "eHRPD:750,48",
                 "HSPAP:13000,3400", "TD-SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,15000",
                 "NR_NSA_MMWAVE:145000,15000", "NR_SA:145000,15000"});
         sDefaults.putBoolean(KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPSTREAM_BOOL, false);