Progressive disclosure on selected UIs: app, display

Bug: 32255863
Test: RunSettingsRoboTests
Change-Id: I1651433ba30a2b5f880095e07b5e2ed9c4e308b9
diff --git a/res/drawable/ic_arrow_down_24dp.xml b/res/drawable/ic_arrow_down_24dp.xml
new file mode 100644
index 0000000..7c5866d
--- /dev/null
+++ b/res/drawable/ic_arrow_down_24dp.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M7.41,7.84L12,12.42l4.59,-4.58L18,9.25l-6,6 -6,-6z"/>
+</vector>
diff --git a/res/layout/expand_preference.xml b/res/layout/expand_preference.xml
index 640cda7..1392d65 100644
--- a/res/layout/expand_preference.xml
+++ b/res/layout/expand_preference.xml
@@ -15,18 +15,63 @@
   limitations under the License.
   -->
 
+<!-- Based off frameworks/base/core/res/res/layout/preference_material.xml -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@drawable/selectable_card_grey"
-    android:gravity="center_vertical"
     android:minHeight="?android:attr/listPreferredItemHeight"
-    android:orientation="vertical"
-    android:paddingEnd="?android:attr/scrollbarSize">
-    <TextView
-        android:id="@android:id/title"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:background="?android:attr/selectableItemBackground"
+    android:clipToPadding="false">
+
+    <LinearLayout
+        android:id="@+id/icon_container"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"/>
-</LinearLayout>
\ No newline at end of file
+        android:minWidth="60dp"
+        android:gravity="start|center_vertical"
+        android:orientation="horizontal"
+        android:paddingEnd="12dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp">
+        <com.android.internal.widget.PreferenceImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxWidth="48dp"
+            android:maxHeight="48dp"/>
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp">
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:textColor="?android:attr/colorAccent"
+            android:ellipsize="marquee"/>
+
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:ellipsize="marquee"
+            android:maxLines="1"/>
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 353864e..0f8f762 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6629,7 +6629,7 @@
     <string name="experimental_preference">(Experimental)</string>
 
     <!-- [CHAR LIMIT=45] Auto-rotate setting title -->
-    <string name="display_auto_rotate_title">When device is rotated</string>
+    <string name="display_auto_rotate_title">Device rotation</string>
     <!-- [CHAR LIMIT=70] Rotate when screen is turned option -->
     <string name="display_auto_rotate_rotate">Rotate the contents of the screen</string>
     <!-- [CHAR LIMIT=70] Keep the screen in portrait when rotated -->
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index 356d5c5..91b193d 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -62,6 +62,12 @@
     }
 
     @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        mProgressiveDisclosureMixin.setTileLimit(4);
+    }
+
+    @Override
     protected String getCategoryKey() {
         return CategoryKey.CATEGORY_DISPLAY;
     }
diff --git a/src/com/android/settings/applications/AdvancedAppSettings.java b/src/com/android/settings/applications/AdvancedAppSettings.java
index 1a15d6f..5bce24d 100644
--- a/src/com/android/settings/applications/AdvancedAppSettings.java
+++ b/src/com/android/settings/applications/AdvancedAppSettings.java
@@ -16,7 +16,6 @@
 package com.android.settings.applications;
 
 import android.content.Context;
-import android.os.Bundle;
 import android.provider.SearchIndexableResource;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -37,11 +36,6 @@
     static final String TAG = "AdvancedAppSettings";
 
     @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-    }
-
-    @Override
     protected String getCategoryKey() {
         return CategoryKey.CATEGORY_APPS_DEFAULT;
     }
diff --git a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
index 5942897..be70f86 100644
--- a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
+++ b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
@@ -40,6 +40,12 @@
     }
 
     @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        mProgressiveDisclosureMixin.setTileLimit(3);
+    }
+
+    @Override
     protected String getCategoryKey() {
         return CategoryKey.CATEGORY_APPS;
     }
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 9afe4b2..14d1bdd 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -268,6 +268,7 @@
 
         // Add resource based tiles.
         displayResourceTiles();
+        mProgressiveDisclosureMixin.collapse(getPreferenceScreen());
 
         refreshDashboardTiles(TAG);
     }
diff --git a/src/com/android/settings/dashboard/ExpandPreference.java b/src/com/android/settings/dashboard/ExpandPreference.java
index 215bfc5..cfa1836 100644
--- a/src/com/android/settings/dashboard/ExpandPreference.java
+++ b/src/com/android/settings/dashboard/ExpandPreference.java
@@ -47,6 +47,7 @@
 
     private void init() {
         setLayoutResource(R.layout.expand_preference);
+        setIcon(R.drawable.ic_arrow_down_24dp);
         setTitle(R.string.wifi_more);
         setOrder(999);
     }
diff --git a/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java b/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
index 8110f32..2907028 100644
--- a/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
+++ b/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
@@ -25,6 +25,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.settings.R;
 import com.android.settings.core.lifecycle.LifecycleObserver;
 import com.android.settings.core.lifecycle.events.OnCreate;
 import com.android.settings.core.lifecycle.events.OnSaveInstanceState;
@@ -40,18 +41,19 @@
     private static final String STATE_USER_EXPANDED = "state_user_expanded";
     private static final int DEFAULT_TILE_LIMIT = 300;
 
-    private int mTileLimit = DEFAULT_TILE_LIMIT;
-
+    private final Context mContext;
     private final DashboardFeatureProvider mDashboardFeatureProvider;
     // Collapsed preference sorted by order.
     private final List<Preference> mCollapsedPrefs = new ArrayList<>();
-    private final ExpandPreference mExpandButton;
+    private /* final */ ExpandPreference mExpandButton;
     private final PreferenceFragment mFragment;
 
+    private int mTileLimit = DEFAULT_TILE_LIMIT;
     private boolean mUserExpanded;
 
     public ProgressiveDisclosureMixin(Context context,
             DashboardFeatureProvider dashboardFeatureProvider, PreferenceFragment fragment) {
+        mContext = context;
         mFragment = fragment;
         mExpandButton = new ExpandPreference(context);
         mExpandButton.setOnPreferenceClickListener(this);
@@ -181,6 +183,8 @@
                 if (mCollapsedPrefs.isEmpty()) {
                     // Removed last element, remove expand button too.
                     screen.removePreference(mExpandButton);
+                } else {
+                    updateExpandButtonSummary();
                 }
                 return;
             }
@@ -216,10 +220,28 @@
             insertionIndex = insertionIndex * -1 - 1;
         }
         mCollapsedPrefs.add(insertionIndex, preference);
+        updateExpandButtonSummary();
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     List<Preference> getCollapsedPrefs() {
         return mCollapsedPrefs;
     }
+
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    void updateExpandButtonSummary() {
+        final int size = mCollapsedPrefs.size();
+        if (size == 0) {
+            mExpandButton.setSummary(null);
+        } else if (size == 1) {
+            mExpandButton.setSummary(mCollapsedPrefs.get(0).getTitle());
+        } else {
+            CharSequence summary = mCollapsedPrefs.get(0).getTitle();
+            for (int i = 1; i < size; i++) {
+                summary = mContext.getString(R.string.join_many_items_middle, summary,
+                        mCollapsedPrefs.get(i).getTitle());
+            }
+            mExpandButton.setSummary(summary);
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java b/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
index ffc6874..bb00cb8 100644
--- a/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
@@ -21,6 +21,7 @@
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 
+import com.android.settings.R;
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 import com.android.settings.overlay.FeatureFactory;
@@ -34,6 +35,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
 
 import java.util.List;
 
@@ -41,6 +43,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -56,10 +59,11 @@
     private FakeFeatureFactory mFakeFeatureFactory;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private PreferenceFragment mPreferenceFragment;
+    @Mock
+    private ExpandPreference mExpandButton;
     private PreferenceScreen mScreen;
     private Context mAppContext;
     private Preference mPreference;
-
     private ProgressiveDisclosureMixin mMixin;
 
     @Before
@@ -71,6 +75,7 @@
         mFakeFeatureFactory = (FakeFeatureFactory) FeatureFactory.getFactory(mContext);
         mMixin = new ProgressiveDisclosureMixin(mAppContext,
                 mFakeFeatureFactory.dashboardFeatureProvider, mPreferenceFragment);
+        ReflectionHelpers.setField(mMixin, "mExpandButton", mExpandButton);
         mPreference = new Preference(mAppContext);
         mPreference.setKey("test");
         when(mFakeFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
@@ -166,6 +171,7 @@
 
         mMixin.collapse(screen);
         assertThat(mMixin.isCollapsed()).isFalse();
+        verify(mExpandButton, never()).setSummary(anyString());
         verify(screen, never()).addPreference(any(Preference.class));
         verify(screen, never()).removePreference(any(Preference.class));
     }
@@ -180,6 +186,7 @@
         mMixin.collapse(screen);
 
         assertThat(mMixin.isCollapsed()).isTrue();
+        verify(mExpandButton, atLeastOnce()).setSummary(anyString());
         verify(screen).addPreference(any(ExpandPreference.class));
         verify(screen, times(3)).removePreference(any(Preference.class));
     }
@@ -224,7 +231,9 @@
         lastPref.setOrder(100);
         // Add something to collapsed list so we are in collapsed state.
         mMixin.addToCollapsedList(new Preference(mAppContext));
+        verify(mExpandButton).setSummary(anyString());
         assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1);
+
         // 3 prefs on screen, 2 are real and the last one is more button.
         when(mScreen.getPreferenceCount()).thenReturn(3);
         when(mScreen.getPreference(1)).thenReturn(lastPref);
@@ -244,7 +253,9 @@
         lastPref.setOrder(100);
         // Add something to collapsed list so we are in collapsed state.
         mMixin.addToCollapsedList(new Preference(mAppContext));
+        verify(mExpandButton).setSummary(anyString());
         assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1);
+
         // 3 prefs on screen, 2 are real and the last one is more button.
         when(mScreen.getPreferenceCount()).thenReturn(3);
         when(mScreen.getPreference(1)).thenReturn(lastPref);
@@ -255,6 +266,40 @@
 
         verify(mScreen, never()).removePreference(any(Preference.class));
         verify(mScreen, never()).addPreference(any(Preference.class));
+        verify(mExpandButton, times(2)).setSummary(anyString());
         assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(toBeAdded);
     }
+
+    @Test
+    public void updateExpandSummary_noPref_noSummary() {
+        mMixin.updateExpandButtonSummary();
+
+        verify(mExpandButton).setSummary(null);
+    }
+
+    @Test
+    public void updateExapndSummary_singlePref_expandSummarySameAsPrefTitle() {
+        final String TEST = "test";
+        final Preference pref = new Preference(mAppContext);
+        pref.setTitle(TEST);
+
+        mMixin.addToCollapsedList(pref);
+        verify(mExpandButton).setSummary(TEST);
+    }
+
+    @Test
+    public void updateExapndSummary_multiPrefs_useCombinedPrefTitleAsSummary() {
+        final String TEST1 = "test1";
+        final String TEST2 = "test2";
+        final Preference pref1 = new Preference(mAppContext);
+        pref1.setTitle(TEST1);
+        final Preference pref2 = new Preference(mAppContext);
+        pref2.setTitle(TEST2);
+
+        mMixin.addToCollapsedList(pref1);
+        mMixin.addToCollapsedList(pref2);
+
+        verify(mExpandButton)
+                .setSummary(mAppContext.getString(R.string.join_many_items_middle, TEST1, TEST2));
+    }
 }