Merge "Use binary resource support in robolectric"
diff --git a/res/anim/layout_animation_fall_down.xml b/res/anim/item_animation_fade_in.xml
similarity index 69%
copy from res/anim/layout_animation_fall_down.xml
copy to res/anim/item_animation_fade_in.xml
index f39735c..68a2713 100644
--- a/res/anim/layout_animation_fall_down.xml
+++ b/res/anim/item_animation_fade_in.xml
@@ -15,8 +15,13 @@
   limitations under the License.
   -->
 
-<layoutAnimation
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:animation="@anim/item_animation_fall_down"
-    android:delay="15%"
-    android:animationOrder="normal"/>
\ No newline at end of file
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:duration="500">
+
+    <!-- Fade in: alpha from 0 to 100% -->
+    <alpha
+        android:fromAlpha="0"
+        android:toAlpha="1"
+        android:interpolator="@android:anim/decelerate_interpolator"/>
+
+</set>
\ No newline at end of file
diff --git a/res/anim/item_animation_fall_down.xml b/res/anim/item_animation_fall_down.xml
deleted file mode 100644
index df2451c..0000000
--- a/res/anim/item_animation_fall_down.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:duration="500">
-
-    <!-- Move up the view by 20% of it’s own height, and let it fall down to its final position -->
-    <translate
-        android:fromYDelta="-20%"
-        android:toYDelta="0"
-        android:interpolator="@android:anim/decelerate_interpolator"/>
-
-    <!-- Fade in: alpha from 0 to 100% -->
-    <alpha
-        android:fromAlpha="0"
-        android:toAlpha="1"
-        android:interpolator="@android:anim/decelerate_interpolator"/>
-
-    <!-- Shrink from 105% to 100% -->
-    <scale
-        android:fromXScale="105%"
-        android:fromYScale="105%"
-        android:toXScale="100%"
-        android:toYScale="100%"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:interpolator="@android:anim/decelerate_interpolator"/>
-</set>
\ No newline at end of file
diff --git a/res/anim/layout_animation_fall_down.xml b/res/anim/layout_animation_fade_in.xml
similarity index 93%
rename from res/anim/layout_animation_fall_down.xml
rename to res/anim/layout_animation_fade_in.xml
index f39735c..fcdb874 100644
--- a/res/anim/layout_animation_fall_down.xml
+++ b/res/anim/layout_animation_fade_in.xml
@@ -17,6 +17,6 @@
 
 <layoutAnimation
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:animation="@anim/item_animation_fall_down"
+    android:animation="@anim/item_animation_fade_in"
     android:delay="15%"
     android:animationOrder="normal"/>
\ No newline at end of file
diff --git a/res/layout/settings_homepage.xml b/res/layout/settings_homepage.xml
index f027d65..e04b372 100644
--- a/res/layout/settings_homepage.xml
+++ b/res/layout/settings_homepage.xml
@@ -25,6 +25,6 @@
         android:id="@+id/card_container"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layoutAnimation="@anim/layout_animation_fall_down"/>
+        android:layoutAnimation="@anim/layout_animation_fade_in"/>
 
 </LinearLayout>
diff --git a/src/com/android/settings/development/MobileDataAlwaysOnPreferenceController.java b/src/com/android/settings/development/MobileDataAlwaysOnPreferenceController.java
index 78054ae..b2fa693 100644
--- a/src/com/android/settings/development/MobileDataAlwaysOnPreferenceController.java
+++ b/src/com/android/settings/development/MobileDataAlwaysOnPreferenceController.java
@@ -66,7 +66,7 @@
     protected void onDeveloperOptionsSwitchDisabled() {
         super.onDeveloperOptionsSwitchDisabled();
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON,
-                SETTING_VALUE_OFF);
-        ((SwitchPreference) mPreference).setChecked(false);
+                SETTING_VALUE_ON);
+        ((SwitchPreference) mPreference).setChecked(true);
     }
 }
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCard.java b/src/com/android/settings/homepage/contextualcards/ContextualCard.java
index ca5555b..4673ad1 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCard.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCard.java
@@ -64,6 +64,7 @@
     private final int mCardAction;
     private final long mExpireTimeMS;
     private final boolean mIsHalfWidth;
+    private final boolean mIsLargeCard;
     private final Drawable mIconDrawable;
 
     public String getName() {
@@ -142,6 +143,10 @@
         return mIsHalfWidth;
     }
 
+    public boolean isLargeCard() {
+        return mIsLargeCard;
+    }
+
     boolean isCustomCard() {
         return TextUtils.isEmpty(mSliceUri);
     }
@@ -170,6 +175,7 @@
         mExpireTimeMS = builder.mExpireTimeMS;
         mIconDrawable = builder.mIconDrawable;
         mIsHalfWidth = builder.mIsHalfWidth;
+        mIsLargeCard = builder.mIsLargeCard;
     }
 
     ContextualCard(Cursor c) {
@@ -212,6 +218,8 @@
         mIsHalfWidth = (c.getInt(
                 c.getColumnIndex(CardDatabaseHelper.CardColumns.SUPPORT_HALF_WIDTH)) == 1);
         mBuilder.setIsHalfWidth(mIsHalfWidth);
+        mIsLargeCard = false;
+        mBuilder.setIsLargeCard(mIsLargeCard);
         mIconDrawable = null;
         mBuilder.setIconDrawable(mIconDrawable);
     }
@@ -256,6 +264,7 @@
         private long mExpireTimeMS;
         private Drawable mIconDrawable;
         private boolean mIsHalfWidth;
+        private boolean mIsLargeCard;
 
         public Builder setName(String name) {
             mName = name;
@@ -347,6 +356,11 @@
             return this;
         }
 
+        public Builder setIsLargeCard(boolean isLargeCard) {
+            mIsLargeCard = isLargeCard;
+            return this;
+        }
+
         public ContextualCard build() {
             return new ContextualCard(this);
         }
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
index 8583f38..5ebc924 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
@@ -24,16 +24,16 @@
 public interface ContextualCardFeatureProvider {
 
     /** Homepage displays. */
-    public void logHomepageDisplay(Context context, Long latency);
+    void logHomepageDisplay(Context context, long latency);
 
     /** When user clicks dismiss in contextual card */
-    public void logContextualCardDismiss(Context context, ContextualCard card);
+    void logContextualCardDismiss(Context context, ContextualCard card);
 
     /** After ContextualCardManager decides which cards will be displayed/hidden */
-    public void logContextualCardDisplay(Context context, List<ContextualCard> showedCards,
+    void logContextualCardDisplay(Context context, List<ContextualCard> showedCards,
             List<ContextualCard> hiddenCards);
 
     /** When user clicks toggle/title area of a contextual card. */
-    public void logContextualCardClick(Context context, ContextualCard card, int row,
+    void logContextualCardClick(Context context, ContextualCard card, int row,
             int tapTarget);
 }
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
index 32a86e8..dc295fc 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
@@ -85,11 +85,10 @@
     private static final int TARGET_SLIDER = 3;
 
     @Override
-    public void logHomepageDisplay(Context context, Long latency) {
-        final Intent intent = new Intent();
-        intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_HOME_SHOW);
-        intent.putExtra(EXTRA_LATENCY, latency);
-        sendBroadcast(context, intent);
+    public void logHomepageDisplay(Context context, long latency) {
+        sendBroadcast(context, new Intent()
+                .putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_HOME_SHOW)
+                .putExtra(EXTRA_LATENCY, latency));
     }
 
     @Override
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index e631d22..71b262d 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -31,6 +31,7 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
+import android.text.format.DateUtils;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -49,6 +50,7 @@
     @VisibleForTesting
     static final int DEFAULT_CARD_COUNT = 4;
     static final int CARD_CONTENT_LOADER_ID = 1;
+    static final long CARD_CONTENT_LOADER_TIMEOUT_MS = DateUtils.SECOND_IN_MILLIS;
 
     private static final String TAG = "ContextualCardLoader";
 
@@ -97,6 +99,8 @@
                     final ContextualCard card = new ContextualCard(cursor);
                     if (card.isCustomCard()) {
                         //TODO(b/114688391): Load and generate custom card,then add into list
+                    } else if (isLargeCard(card)) {
+                        result.add(card.mutate().setIsLargeCard(true).build());
                     } else {
                         result.add(card);
                     }
@@ -195,12 +199,16 @@
 
     private int getNumberOfLargeCard(List<ContextualCard> cards) {
         return (int) cards.stream()
-                .filter(card -> card.getSliceUri().equals(WIFI_SLICE_URI)
-                        || card.getSliceUri().equals(BLUETOOTH_DEVICES_SLICE_URI))
+                .filter(card -> isLargeCard(card))
                 .count();
     }
 
+    private boolean isLargeCard(ContextualCard card) {
+        return card.getSliceUri().equals(WIFI_SLICE_URI)
+                || card.getSliceUri().equals(BLUETOOTH_DEVICES_SLICE_URI);
+    }
+
     public interface CardContentLoaderListener {
         void onFinishCardLoading(List<ContextualCard> contextualCards);
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 28ad0d3..24266ee 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -59,12 +59,15 @@
         ContextualCardUpdateListener {
 
     private static final String TAG = "ContextualCardManager";
+
     //The list for Settings Custom Card
     private static final int[] SETTINGS_CARDS =
             {ContextualCard.CardType.CONDITIONAL, ContextualCard.CardType.LEGACY_SUGGESTION};
 
     @VisibleForTesting
     final List<ContextualCard> mContextualCards;
+    @VisibleForTesting
+    long mStartTime;
 
     private final Context mContext;
     private final ControllerRendererPool mControllerRendererPool;
@@ -72,7 +75,6 @@
     private final List<LifecycleObserver> mLifecycleObservers;
 
     private ContextualCardUpdateListener mListener;
-    private long mStartTime;
 
     public ContextualCardManager(Context context, Lifecycle lifecycle) {
         mContext = context;
@@ -169,11 +171,14 @@
 
     @Override
     public void onFinishCardLoading(List<ContextualCard> cards) {
-        onContextualCardUpdated(cards.stream().collect(groupingBy(ContextualCard::getCardType)));
-        final long elapsedTime = System.currentTimeMillis() - mStartTime;
-        final ContextualCardFeatureProvider contextualCardFeatureProvider =
-                FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
-        contextualCardFeatureProvider.logHomepageDisplay(mContext, elapsedTime);
+        final long loadTime = System.currentTimeMillis() - mStartTime;
+        if (loadTime <= ContextualCardLoader.CARD_CONTENT_LOADER_TIMEOUT_MS) {
+            onContextualCardUpdated(
+                    cards.stream().collect(groupingBy(ContextualCard::getCardType)));
+        }
+        final long totalTime = System.currentTimeMillis() - mStartTime;
+        FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider()
+                .logHomepageDisplay(mContext, totalTime);
     }
 
     public ControllerRendererPool getControllerRendererPool() {
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java b/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java
index 02854c2..834ebbc 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java
@@ -109,7 +109,6 @@
         final Map<Integer, List<ContextualCard>> conditionalCards =
                 buildConditionalCardsWithFooterOrHeader(conditionCards);
         mListener.onContextualCardUpdated(conditionalCards);
-
     }
 
     /**
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index be03c28..172c3b2 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -131,6 +131,12 @@
         // Set this listener so we can log the interaction users make on the slice
         cardHolder.sliceView.setOnSliceActionListener(this);
 
+        // Customize slice view for Settings
+        if (card.isLargeCard()) {
+            cardHolder.sliceView.showHeaderDivider(true);
+            cardHolder.sliceView.showActionDividers(true);
+        }
+
         initDismissalActions(cardHolder, card);
     }
 
diff --git a/src/com/android/settings/slices/SliceBackgroundWorker.java b/src/com/android/settings/slices/SliceBackgroundWorker.java
index a663ece..8b68f05 100644
--- a/src/com/android/settings/slices/SliceBackgroundWorker.java
+++ b/src/com/android/settings/slices/SliceBackgroundWorker.java
@@ -58,6 +58,10 @@
         mUri = uri;
     }
 
+    public Uri getUri() {
+        return mUri;
+    }
+
     /**
      * Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link
      * CustomSliceable}
diff --git a/src/com/android/settings/wifi/WifiSlice.java b/src/com/android/settings/wifi/WifiSlice.java
index 64e3fc3..9f05783 100644
--- a/src/com/android/settings/wifi/WifiSlice.java
+++ b/src/com/android/settings/wifi/WifiSlice.java
@@ -25,7 +25,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.net.Uri;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
@@ -76,14 +75,6 @@
     }
 
     @Override
-    public IntentFilter getIntentFilter() {
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        return filter;
-    }
-
-    @Override
     public Slice getSlice() {
         final boolean isWifiEnabled = isWifiEnabled();
         final IconCompat icon = IconCompat.createWithResource(mContext,
@@ -200,7 +191,7 @@
                 mWifiManager.isWifiEnabled());
         mWifiManager.setWifiEnabled(newState);
         // Do not notifyChange on Uri. The service takes longer to update the current value than it
-        // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay}
+        // does for the Slice to check the current value again. Let {@link WifiScanWorker}
         // handle it.
     }
 
@@ -292,6 +283,7 @@
 
         @Override
         public void onWifiStateChanged(int state) {
+            mContext.getContentResolver().notifyChange(getUri(), null);
         }
 
         @Override
diff --git a/tests/robotests/src/com/android/settings/development/MobileDataAlwaysOnPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/MobileDataAlwaysOnPreferenceControllerTest.java
index a5b7b8e..914f1a7 100644
--- a/tests/robotests/src/com/android/settings/development/MobileDataAlwaysOnPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/MobileDataAlwaysOnPreferenceControllerTest.java
@@ -95,13 +95,13 @@
     }
 
     @Test
-    public void onDeveloperOptionsSwitchDisabled_preferenceShouldBeDisabled() {
+    public void onDeveloperOptionsSwitchDisabled_shouldDisableMobileDataAlwaysOn() {
         mController.onDeveloperOptionsSwitchDisabled();
         final int mode = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.MOBILE_DATA_ALWAYS_ON, -1 /* default */);
 
-        assertThat(mode).isEqualTo(MobileDataAlwaysOnPreferenceController.SETTING_VALUE_OFF);
+        assertThat(mode).isEqualTo(MobileDataAlwaysOnPreferenceController.SETTING_VALUE_ON);
         verify(mPreference).setEnabled(false);
-        verify(mPreference).setChecked(false);
+        verify(mPreference).setChecked(true);
     }
 }
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 ced9a9e..2af84f9 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -18,6 +18,13 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyMap;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
 import android.content.Context;
 import android.net.Uri;
 import android.util.ArrayMap;
@@ -36,6 +43,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 @RunWith(RobolectricTestRunner.class)
 public class ContextualCardManagerTest {
@@ -107,6 +115,25 @@
                 .isEqualTo(ContextualCard.CardType.CONDITIONAL_FOOTER);
     }
 
+    @Test
+    public void onFinishCardLoading_fastLoad_shouldCallOnContextualCardUpdated() {
+        mManager.mStartTime = System.currentTimeMillis();
+        final ContextualCardManager manager = spy(mManager);
+        doNothing().when(manager).onContextualCardUpdated(anyMap());
+
+        manager.onFinishCardLoading(new ArrayList<>());
+        verify(manager).onContextualCardUpdated(nullable(Map.class));
+    }
+
+    @Test
+    public void onFinishCardLoading_slowLoad_shouldSkipOnContextualCardUpdated() {
+        mManager.mStartTime = 0;
+        final ContextualCardManager manager = spy(mManager);
+        doNothing().when(manager).onContextualCardUpdated(anyMap());
+
+        manager.onFinishCardLoading(new ArrayList<>());
+        verify(manager, never()).onContextualCardUpdated(anyMap());
+    }
 
     private ContextualCard buildContextualCard(String sliceUri) {
         return new ContextualCard.Builder()
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
index 752c389..2d4dd04 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
@@ -20,10 +20,18 @@
 import static android.app.slice.Slice.HINT_LIST_ITEM;
 import static android.app.slice.SliceItem.FORMAT_SLICE;
 
+import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI;
 import static com.android.settings.wifi.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.net.wifi.WifiManager;
@@ -52,13 +60,16 @@
 public class WifiSliceTest {
 
     private Context mContext;
-
+    private ContentResolver mResolver;
     private WifiManager mWifiManager;
     private WifiSlice mWifiSlice;
+    private WifiSlice.WifiScanWorker mWifiScanWorker;
 
     @Before
     public void setUp() {
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
+        mResolver = mock(ContentResolver.class);
+        doReturn(mResolver).when(mContext).getContentResolver();
         mWifiManager = mContext.getSystemService(WifiManager.class);
 
         // Set-up specs for SliceMetadata.
@@ -66,6 +77,7 @@
         mWifiManager.setWifiEnabled(true);
 
         mWifiSlice = new WifiSlice(mContext);
+        mWifiScanWorker = new WifiSlice.WifiScanWorker(mContext, WIFI_SLICE_URI);
     }
 
     @Test
@@ -122,4 +134,11 @@
 
         assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_ENABLED);
     }
+
+    @Test
+    public void onWifiStateChanged_shouldNotifyChange() {
+        mWifiScanWorker.onWifiStateChanged(WifiManager.WIFI_STATE_DISABLED);
+
+        verify(mResolver).notifyChange(WIFI_SLICE_URI, null);
+    }
 }