Merge "Support autoclick secondary action (7/n)"
diff --git a/protos/contextual_card_list.proto b/protos/contextual_card_list.proto
index 69c3741..54e5654 100644
--- a/protos/contextual_card_list.proto
+++ b/protos/contextual_card_list.proto
@@ -19,6 +19,7 @@
     POSSIBLE = 2;
     IMPORTANT = 3;
     DEFERRED_SETUP = 5;
+    STICKY = 6;
   }
 
   /** Slice uri of the contextual card */
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index eb6515e..54af16f 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -43,6 +43,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageItemInfo;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.IBinder;
@@ -143,7 +144,7 @@
         implements View.OnClickListener, OnItemSelectedListener, SearchView.OnQueryTextListener {
 
     static final String TAG = "ManageApplications";
-    static final boolean DEBUG = false;
+    static final boolean DEBUG = Build.IS_DEBUGGABLE;
 
     // Intent extras.
     public static final String EXTRA_CLASSNAME = "classname";
@@ -178,8 +179,6 @@
     public static final int STORAGE_TYPE_LEGACY = 2; // Show apps even if they can be categorized.
     public static final int STORAGE_TYPE_PHOTOS_VIDEOS = 3;
 
-    private static final int NO_USER_SPECIFIED = -1;
-
     /**
      * Intents with action {@code android.settings.MANAGE_APP_OVERLAY_PERMISSION}
      * and data URI scheme {@code package} don't go to the app-specific screen for managing the
@@ -461,19 +460,8 @@
         pinnedHeader.addView(mSpinnerHeader, 0);
 
         final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance();
-        mFilterAdapter.enableFilter(appFilterRegistry.getDefaultFilterType(mListType));
-
-        AppFilter compositeFilter = getCompositeFilter(mListType, mStorageType, mVolumeUuid);
-        if (mIsWorkOnly) {
-            compositeFilter = new CompoundFilter(compositeFilter, ApplicationsState.FILTER_WORK);
-        }
-        if (mIsPersonalOnly) {
-            compositeFilter = new CompoundFilter(compositeFilter,
-                    ApplicationsState.FILTER_PERSONAL);
-        }
-        if (compositeFilter != null) {
-            mApplications.setCompositeFilter(compositeFilter);
-        }
+        final int filterType = appFilterRegistry.getDefaultFilterType(mListType);
+        mFilterAdapter.enableFilter(filterType);
 
         if (mListType == LIST_TYPE_MAIN) {
             if (UserManager.get(getActivity()).getUserProfiles().size() > 1 && !mIsWorkOnly
@@ -491,6 +479,8 @@
         if (mListType == LIST_TYPE_HIGH_POWER) {
             mFilterAdapter.enableFilter(FILTER_APPS_POWER_WHITELIST_ALL);
         }
+
+        setCompositeFilter();
     }
 
     @VisibleForTesting
@@ -511,11 +501,8 @@
             return new CompoundFilter(ApplicationsState.FILTER_MOVIES, filter);
         } else if (listType == LIST_TYPE_PHOTOGRAPHY) {
             return new CompoundFilter(ApplicationsState.FILTER_PHOTOS, filter);
-        } else {
-            final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance();
-            return appFilterRegistry.get(
-                    appFilterRegistry.getDefaultFilterType(listType)).getFilter();
         }
+        return null;
     }
 
     @Override
@@ -615,6 +602,21 @@
         }
     }
 
+    private void setCompositeFilter() {
+        AppFilter compositeFilter = getCompositeFilter(mListType, mStorageType, mVolumeUuid);
+        if (compositeFilter == null) {
+            compositeFilter = mFilter.getFilter();
+        }
+        if (mIsWorkOnly) {
+            compositeFilter = new CompoundFilter(compositeFilter, ApplicationsState.FILTER_WORK);
+        }
+        if (mIsPersonalOnly) {
+            compositeFilter = new CompoundFilter(compositeFilter,
+                    ApplicationsState.FILTER_PERSONAL);
+        }
+        mApplications.setCompositeFilter(compositeFilter);
+    }
+
     // utility method used to start sub activity
     private void startApplicationDetailsActivity() {
         switch (mListType) {
@@ -823,6 +825,7 @@
     @Override
     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
         mFilter = mFilterAdapter.getFilter(position);
+        setCompositeFilter();
         mApplications.setFilter(mFilter);
 
         if (DEBUG) {
@@ -1227,14 +1230,10 @@
                 comparatorObj = ApplicationsState.ALPHA_COMPARATOR;
             }
 
-            filterObj = new CompoundFilter(filterObj, ApplicationsState.FILTER_NOT_HIDE);
-            AppFilter finalFilterObj = filterObj;
+            final AppFilter finalFilterObj = new CompoundFilter(filterObj,
+                    ApplicationsState.FILTER_NOT_HIDE);
             ThreadUtils.postOnBackgroundThread(() -> {
-                final ArrayList<AppEntry> entries = mSession.rebuild(finalFilterObj,
-                        comparatorObj, false);
-                if (entries != null) {
-                    ThreadUtils.postOnMainThread(() -> onRebuildComplete(entries));
-                }
+                mSession.rebuild(finalFilterObj, comparatorObj, false);
             });
         }
 
@@ -1284,7 +1283,7 @@
         @Override
         public void onRebuildComplete(ArrayList<AppEntry> entries) {
             if (DEBUG) {
-                Log.d(TAG, "onRebuildComplete");
+                Log.d(TAG, "onRebuildComplete size=" + entries.size());
             }
             final int filterType = mAppFilter.getFilterType();
             if (filterType == FILTER_APPS_POWER_WHITELIST ||
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index 3a744a9..a2233fc 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -258,7 +258,7 @@
             preference.setSummary(summary);
         } else if (tile.getMetaData() != null
                 && tile.getMetaData().containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
-            // Set a placeholder summary before  starting to fetch real summary, this is necessary
+            // Set a placeholder summary before starting to fetch real summary, this is necessary
             // to avoid preference height change.
             preference.setSummary(R.string.summary_placeholder);
 
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 40df224..1c83a10 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.homepage.contextualcards;
 
+import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.STICKY_VALUE;
 import static com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
 import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI;
 import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI;
@@ -127,18 +128,34 @@
     @VisibleForTesting
     List<ContextualCard> getDisplayableCards(List<ContextualCard> candidates) {
         final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
+        final List<ContextualCard> stickyCards = new ArrayList<>();
         final List<ContextualCard> visibleCards = new ArrayList<>();
         final List<ContextualCard> hiddenCards = new ArrayList<>();
 
-        final int size = eligibleCards.size();
-        final int cardCount = getCardCount();
-        for (int i = 0; i < size; i++) {
-            if (i < cardCount) {
-                visibleCards.add(eligibleCards.get(i));
-            } else {
-                hiddenCards.add(eligibleCards.get(i));
+        final int maxCardCount = getCardCount();
+        eligibleCards.forEach(card -> {
+            if (card.getCategory() != STICKY_VALUE) {
+                return;
             }
-        }
+            if (stickyCards.size() < maxCardCount) {
+                stickyCards.add(card);
+            } else {
+                hiddenCards.add(card);
+            }
+        });
+
+        final int nonStickyCardCount = maxCardCount - stickyCards.size();
+        eligibleCards.forEach(card -> {
+            if (card.getCategory() == STICKY_VALUE) {
+                return;
+            }
+            if (visibleCards.size() < nonStickyCardCount) {
+                visibleCards.add(card);
+            } else {
+                hiddenCards.add(card);
+            }
+        });
+        visibleCards.addAll(stickyCards);
 
         if (!CardContentProvider.DELETE_CARD_URI.equals(mNotifyUri)) {
             final MetricsFeatureProvider metricsFeatureProvider =
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 9e9069f..9beb624 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -17,6 +17,7 @@
 package com.android.settings.homepage.contextualcards;
 
 import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
+import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.STICKY_VALUE;
 import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE;
 import static com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
 import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI;
@@ -346,16 +347,23 @@
         return result;
     }
 
-    // TODO(b/143055685):use category to determine whether they are sticky.
     private List<ContextualCard> getCardsWithStickyViewType(List<ContextualCard> cards) {
         final List<ContextualCard> result = new ArrayList<>(cards);
         int replaceCount = 0;
         for (int index = 0; index < result.size(); index++) {
+            final ContextualCard card = cards.get(index);
+            if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2)) {
+                if (card.getCategory() == STICKY_VALUE) {
+                    result.set(index, card.mutate().setViewType(
+                            SliceContextualCardRenderer.VIEW_TYPE_STICKY).build());
+                }
+                continue;
+            }
+
             if (replaceCount > STICKY_CARDS.size() - 1) {
                 break;
             }
 
-            final ContextualCard card = cards.get(index);
             if (card.getCardType() != ContextualCard.CardType.SLICE) {
                 continue;
             }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index 00993f6..fceb79d 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -17,6 +17,7 @@
 package com.android.settings.homepage.contextualcards;
 
 import static com.android.settings.homepage.contextualcards.ContextualCardLoader.DEFAULT_CARD_COUNT;
+import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.STICKY_VALUE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -82,16 +83,41 @@
 
     @Test
     public void getDisplayableCards_fourEligibleCards_shouldShowDefaultCardCount() {
-        final List<ContextualCard> fourCards = getContextualCardList();
-        doReturn(fourCards).when(mContextualCardLoader).filterEligibleCards(anyList());
+        final List<ContextualCard> cards = getContextualCardList().stream().limit(4)
+                .collect(Collectors.toList());
+        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
 
-        final List<ContextualCard> result = mContextualCardLoader
-                .getDisplayableCards(fourCards);
+        final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
 
         assertThat(result).hasSize(DEFAULT_CARD_COUNT);
     }
 
     @Test
+    public void getDisplayableCards_oneStickyCard_shouldShowOneStickyCardAtTheTail() {
+        final List<ContextualCard> cards = getContextualCardList().stream().limit(5)
+                .collect(Collectors.toList());
+        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
+
+        final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
+
+        assertThat(result).hasSize(DEFAULT_CARD_COUNT);
+        assertThat(result.get(DEFAULT_CARD_COUNT - 1).getCategory()).isEqualTo(STICKY_VALUE);
+    }
+
+    @Test
+    public void getDisplayableCards_threeStickyCards_shouldShowThreeStickyCardAtTheTail() {
+        final List<ContextualCard> cards = getContextualCardList();
+        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
+
+        final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
+
+        assertThat(result).hasSize(DEFAULT_CARD_COUNT);
+        for (int i = 1; i <= Math.min(3, DEFAULT_CARD_COUNT); i++) {
+            assertThat(result.get(DEFAULT_CARD_COUNT - i).getCategory()).isEqualTo(STICKY_VALUE);
+        }
+    }
+
+    @Test
     public void getDisplayableCards_refreshCardUri_shouldLogContextualCard() {
         mContextualCardLoader.mNotifyUri = CardContentProvider.REFRESH_CARD_URI;
 
@@ -128,20 +154,20 @@
     private List<ContextualCard> getContextualCardList() {
         final List<ContextualCard> cards = new ArrayList<>();
         cards.add(new ContextualCard.Builder()
-                .setName("test_wifi")
+                .setName("test_low_storage")
                 .setCardType(ContextualCard.CardType.SLICE)
-                .setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI)
+                .setSliceUri(CustomSliceRegistry.LOW_STORAGE_SLICE_URI)
                 .build());
         cards.add(new ContextualCard.Builder()
                 .setName("test_flashlight")
                 .setCardType(ContextualCard.CardType.SLICE)
-                .setSliceUri(
-                        Uri.parse("content://com.android.settings.test.slices/action/flashlight"))
+                .setSliceUri(Uri.parse(
+                        "content://com.android.settings.test.slices/action/flashlight"))
                 .build());
         cards.add(new ContextualCard.Builder()
-                .setName("test_connected")
+                .setName("test_dark_theme")
                 .setCardType(ContextualCard.CardType.SLICE)
-                .setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI)
+                .setSliceUri(CustomSliceRegistry.DARK_THEME_SLICE_URI)
                 .build());
         cards.add(new ContextualCard.Builder()
                 .setName("test_gesture")
@@ -149,6 +175,24 @@
                 .setSliceUri(Uri.parse(
                         "content://com.android.settings.test.slices/action/gesture_pick_up"))
                 .build());
+        cards.add(new ContextualCard.Builder()
+                .setName("test_wifi")
+                .setCardType(ContextualCard.CardType.SLICE)
+                .setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI)
+                .setCategory(STICKY_VALUE)
+                .build());
+        cards.add(new ContextualCard.Builder()
+                .setName("test_connected")
+                .setCardType(ContextualCard.CardType.SLICE)
+                .setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI)
+                .setCategory(STICKY_VALUE)
+                .build());
+        cards.add(new ContextualCard.Builder()
+                .setName("test_sticky")
+                .setCardType(ContextualCard.CardType.SLICE)
+                .setSliceUri(Uri.parse("content://com.android.settings.test.slices/action/sticky"))
+                .setCategory(STICKY_VALUE)
+                .build());
         return cards;
     }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
index d179cae..8958d6e 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -565,7 +565,27 @@
     }
 
     @Test
+    public void getCardsWithViewType_hasOneStickySlice_shouldHaveOneStickyCard() {
+        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, true);
+        final List<ContextualCard> cards = new ArrayList<>();
+        cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
+        cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
+        final List<Integer> categories = Arrays.asList(
+                ContextualCardProto.ContextualCard.Category.STICKY_VALUE,
+                ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+        );
+        final List<ContextualCard> cardListWithWifi = buildCategoriedCards(cards, categories);
+
+        final List<ContextualCard> result = mManager.getCardsWithViewType(cardListWithWifi);
+
+        assertThat(result).hasSize(cards.size());
+        assertThat(result.get(0).getViewType()).isEqualTo(VIEW_TYPE_STICKY);
+        assertThat(result.get(1).getViewType()).isEqualTo(VIEW_TYPE_FULL_WIDTH);
+    }
+
+    @Test
     public void getCardsWithViewType_hasWifiSlice_shouldHaveOneStickyCard() {
+        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
         final List<ContextualCard> cards = new ArrayList<>();
         cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
         cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
@@ -584,6 +604,7 @@
 
     @Test
     public void getCardsWithViewType_hasBluetoothDeviceSlice_shouldHaveOneStickyCard() {
+        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
         final List<ContextualCard> cards = new ArrayList<>();
         cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
         cards.add(buildContextualCard(CustomSliceRegistry.LOW_STORAGE_SLICE_URI.toString()));
@@ -602,6 +623,7 @@
 
     @Test
     public void getCardsWithViewType_hasWifiAndBtDeviceSlice_shouldHaveTwoStickyCards() {
+        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
         final List<ContextualCard> cards = new ArrayList<>();
         cards.add(buildContextualCard(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()));
         cards.add(buildContextualCard(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString()));
@@ -624,6 +646,7 @@
 
     @Test
     public void getCardsWithViewType_noWifiOrBtDeviceSlice_shouldNotHaveStickyCard() {
+        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.CONTEXTUAL_HOME2, false);
         final List<Integer> categories = Arrays.asList(
                 ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
                 ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
@@ -683,8 +706,8 @@
         cards.add(new ContextualCard.Builder()
                 .setName("test_flashlight")
                 .setCardType(ContextualCard.CardType.SLICE)
-                .setSliceUri(
-                        Uri.parse("content://com.android.settings.test.slices/action/flashlight"))
+                .setSliceUri(Uri.parse(
+                        "content://com.android.settings.test.slices/action/flashlight"))
                 .setViewType(VIEW_TYPE_FULL_WIDTH)
                 .build());
         cards.add(new ContextualCard.Builder()