diff --git a/Android.mk b/Android.mk index 349b79ce046..eeaad0c936a 100644 --- a/Android.mk +++ b/Android.mk @@ -22,9 +22,10 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_ANDROID_LIBRARIES := \ android-support-v4 \ android-support-v13 \ - android-support-v7-recyclerview \ - android-support-v7-preference \ android-support-v7-appcompat \ + android-support-v7-cardview \ + android-support-v7-preference \ + android-support-v7-recyclerview \ android-support-v14-preference LOCAL_JAVA_LIBRARIES := \ diff --git a/res/layout/dashboard_header_spacer.xml b/res/layout/dashboard_header_spacer.xml new file mode 100644 index 00000000000..442ae48b54c --- /dev/null +++ b/res/layout/dashboard_header_spacer.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/res/layout/settings_main_dashboard.xml b/res/layout/settings_main_dashboard.xml index c10193cda90..1a3b1335dd8 100644 --- a/res/layout/settings_main_dashboard.xml +++ b/res/layout/settings_main_dashboard.xml @@ -18,7 +18,31 @@ --> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 6495ab01d52..2c7a2e8ec82 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -140,6 +140,12 @@ 32dp 32dp + + 8dp + -8dp + 16dp 16dp diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 4045fd2afdd..9956f719eff 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -50,6 +50,7 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; +import android.widget.Toolbar; import com.android.internal.util.ArrayUtils; import com.android.settings.Settings.WifiSettingsActivity; @@ -62,6 +63,7 @@ import com.android.settings.dashboard.DashboardSummary; import com.android.settings.development.DevelopmentSettings; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.DynamicIndexableContentMonitor; +import com.android.settings.search2.SearchActivity; import com.android.settings.search2.SearchFeatureProvider; import com.android.settings.wfd.WifiDisplaySettings; import com.android.settings.widget.SwitchBar; @@ -75,7 +77,7 @@ import java.util.Set; public class SettingsActivity extends SettingsDrawerActivity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback, - ButtonBarHandler, FragmentManager.OnBackStackChangedListener { + ButtonBarHandler, FragmentManager.OnBackStackChangedListener, OnClickListener { private static final String LOG_TAG = "Settings"; @@ -345,6 +347,14 @@ public class SettingsActivity extends SettingsDrawerActivity launchSettingFragment(initialFragmentName, isSubSettings, intent); } + if (mIsShowingDashboard) { + findViewById(R.id.search_bar).setVisibility(View.VISIBLE); + findViewById(R.id.action_bar).setVisibility(View.GONE); + Toolbar toolbar = findViewById(R.id.search_action_bar); + toolbar.setOnClickListener(this); + setActionBar(toolbar); + } + mActionBar = getActionBar(); if (mActionBar != null) { mActionBar.setDisplayHomeAsUpEnabled(mDisplayHomeAsUpEnabled); @@ -432,10 +442,10 @@ public class SettingsActivity extends SettingsDrawerActivity switchToFragment(initialFragmentName, initialArguments, true, false, mInitialTitleResId, mInitialTitle, false); } else { - // No UP affordance if we are displaying the main Dashboard - mDisplayHomeAsUpEnabled = false; - // Show Search affordance - mDisplaySearch = true; + // Show search icon as up affordance if we are displaying the main Dashboard + mDisplayHomeAsUpEnabled = true; + // toolbar is search affordance so don't show search + mDisplaySearch = false; mInitialTitleResId = R.string.dashboard_title; switchToFragment(DashboardSummary.class.getName(), null /* args */, false, false, @@ -939,4 +949,10 @@ public class SettingsActivity extends SettingsDrawerActivity return bitmap; } -} \ No newline at end of file + + @Override + public void onClick(View v) { + Intent intent = new Intent(this, SearchActivity.class); + startActivity(intent); + } +} diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java index e3e95be7f33..dc67888733b 100644 --- a/src/com/android/settings/dashboard/DashboardAdapter.java +++ b/src/com/android/settings/dashboard/DashboardAdapter.java @@ -15,6 +15,8 @@ */ package com.android.settings.dashboard; +import android.annotation.AttrRes; +import android.annotation.ColorInt; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; @@ -55,6 +57,7 @@ public class DashboardAdapter extends RecyclerView.Adapter (position + 1)) { + // The spacer that goes underneath the search bar needs to match the + // background of the first real view. That view is either a condition, + // a suggestion, or the dashboard item. + // + // If it's a dashboard item, set null background so it uses the parent's + // background like the other views. Otherwise, match the colors. + int nextType = mDashboardData.getItemTypeByPosition(position + 1); + int colorAttr = nextType == R.layout.suggestion_header + ? android.R.attr.colorSecondary + : nextType == R.layout.condition_card + ? android.R.attr.colorAccent + : DONT_SET_BACKGROUND_ATTR; + + if (colorAttr != DONT_SET_BACKGROUND_ATTR) { + TypedArray array = holder.itemView.getContext() + .obtainStyledAttributes(new int[]{colorAttr}); + @ColorInt int color = array.getColor(0, 0); + array.recycle(); + holder.itemView.setBackgroundColor(color); + } else { + holder.itemView.setBackground(null); + } + } + } + @VisibleForTesting void onBindSuggestionHeader(final DashboardItemHolder holder, DashboardData .SuggestionHeaderData data) { diff --git a/src/com/android/settings/dashboard/DashboardData.java b/src/com/android/settings/dashboard/DashboardData.java index 4e8c7a0e6c4..8625790f4ec 100644 --- a/src/com/android/settings/dashboard/DashboardData.java +++ b/src/com/android/settings/dashboard/DashboardData.java @@ -45,7 +45,8 @@ public class DashboardData { public static final int DEFAULT_SUGGESTION_COUNT = 2; // id namespace for different type of items. - private static final int NS_SPACER = 0; + private static final int NS_HEADER_SPACER = 0; + private static final int NS_SPACER = 1000; private static final int NS_ITEMS = 2000; private static final int NS_CONDITION = 3000; @@ -228,6 +229,9 @@ public class DashboardData { * and mIsShowingAll, mSuggestionMode flag. */ private void buildItemsData() { + // add the view that goes under the search bar + countItem(null, R.layout.dashboard_header_spacer, true, NS_HEADER_SPACER); + resetCount(); boolean hasConditions = false; for (int i = 0; mConditions != null && i < mConditions.size(); i++) { boolean shouldShow = mConditions.get(i).shouldShow(); diff --git a/src/com/android/settings/search2/SearchFeatureProviderImpl.java b/src/com/android/settings/search2/SearchFeatureProviderImpl.java index 4e47f9db57a..1179c516a4c 100644 --- a/src/com/android/settings/search2/SearchFeatureProviderImpl.java +++ b/src/com/android/settings/search2/SearchFeatureProviderImpl.java @@ -54,13 +54,10 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider { String menuTitle = activity.getString(R.string.search_menu); MenuItem menuItem = menu.add(Menu.NONE, Menu.NONE, Menu.NONE, menuTitle) .setIcon(R.drawable.ic_search_24dp) - .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - Intent intent = new Intent(activity, SearchActivity.class); - activity.startActivity(intent); - return true; - } + .setOnMenuItemClickListener(item -> { + Intent intent = new Intent(activity, SearchActivity.class); + activity.startActivity(intent); + return true; }); menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); diff --git a/tests/robotests/src/com/android/settings/SettingsActivityTest.java b/tests/robotests/src/com/android/settings/SettingsActivityTest.java index 65e97083957..eecd88aae0e 100644 --- a/tests/robotests/src/com/android/settings/SettingsActivityTest.java +++ b/tests/robotests/src/com/android/settings/SettingsActivityTest.java @@ -20,12 +20,15 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.FragmentManager; import android.app.FragmentTransaction; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.view.Menu; + +import com.android.settings.search2.SearchActivity; import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; import org.junit.Test; @@ -35,6 +38,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; import org.robolectric.util.ReflectionHelpers; import static com.google.common.truth.Truth.assertThat; @@ -138,4 +142,15 @@ public class SettingsActivityTest { assertThat(mActivity.mDisplaySearch).isTrue(); } + + @Test + public void testOnClick() { + doReturn("com.android.settings").when(mActivity).getPackageName(); + + mActivity.onClick(null); + + Intent intent = ShadowApplication.getInstance().getNextStartedActivity(); + assertThat(intent.getComponent()).isEqualTo( + new ComponentName("com.android.settings", SearchActivity.class.getName())); + } } diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java index d7daa03a1fa..3b27cf128a0 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java @@ -19,16 +19,23 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Icon; +import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; +import android.widget.LinearLayout; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.dashboard.conditional.Condition; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; +import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; import org.junit.Before; @@ -47,6 +54,7 @@ import java.util.List; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -99,6 +107,53 @@ public class DashboardAdapterTest { when(mView.getTag()).thenReturn(mCondition); } + @Test + public void testOnBindViewHolder_spacer_noSuggestions_noConditions() { + makeCategory(); + DashboardAdapter.DashboardItemHolder holder = setupSpacer(); + + mDashboardAdapter.onBindViewHolder(holder, 0); + + assertThat(holder.itemView.getBackground()).isNull(); + } + + @Test + public void testOnBindViewHolder_spacer_suggestion_noConditions() { + setupSuggestions(makeSuggestions("pkg1")); + makeCategory(); + DashboardAdapter.DashboardItemHolder holder = setupSpacer(); + + mDashboardAdapter.onBindViewHolder(holder, 0); + + assertThat(holder.itemView.getBackground()).isNotNull(); + assertThat(holder.itemView.getBackground()).isInstanceOf(ColorDrawable.class); + } + + @Test + public void testOnBindViewHolder_spacer_noSuggestion_condition() { + makeCondition(); + makeCategory(); + DashboardAdapter.DashboardItemHolder holder = setupSpacer(); + + mDashboardAdapter.onBindViewHolder(holder, 0); + + assertThat(holder.itemView.getBackground()).isNotNull(); + assertThat(holder.itemView.getBackground()).isInstanceOf(ColorDrawable.class); + } + + @Test + public void testOnBindViewHolder_spacer_suggestion_condition() { + setupSuggestions(makeSuggestions("pkg1")); + makeCondition(); + makeCategory(); + DashboardAdapter.DashboardItemHolder holder = setupSpacer(); + + mDashboardAdapter.onBindViewHolder(holder, 0); + + assertThat(holder.itemView.getBackground()).isNotNull(); + assertThat(holder.itemView.getBackground()).isInstanceOf(ColorDrawable.class); + } + @Test public void testSetConditions_AfterSetConditions_ExpandedConditionNull() { mDashboardAdapter.onExpandClick(mView); @@ -109,7 +164,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_NotExpanded() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); + setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); verify(mFactory.metricsFeatureProvider, times(2)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); @@ -124,7 +179,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_NotExpandedAndPaused() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); + setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); mDashboardAdapter.onPause(); verify(mFactory.metricsFeatureProvider, times(4)).action( any(Context.class), mActionCategoryCaptor.capture(), @@ -141,7 +196,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_Expanded() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); + setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); @@ -160,7 +215,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_ExpandedAndPaused() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); + setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); @@ -183,7 +238,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_ExpandedAfterPause() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); + setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); mDashboardAdapter.onPause(); mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); @@ -208,7 +263,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_ExpandedAfterPauseAndPausedAgain() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); + setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); mDashboardAdapter.onPause(); mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); @@ -237,7 +292,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_ExpandedWithLessThanDefaultShown() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1"})); + setupSuggestions(makeSuggestions("pkg1")); mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); @@ -254,7 +309,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_ExpandedWithLessThanDefaultShownAndPaused() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1"})); + setupSuggestions(makeSuggestions("pkg1")); mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); @@ -273,7 +328,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_ExpandedWithLessThanDefaultShownAfterPause() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1"})); + setupSuggestions(makeSuggestions("pkg1")); mDashboardAdapter.onPause(); mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); @@ -293,7 +348,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_ExpandedWithLessThanDefaultShownAfterPauseAndPausedAgain() { - setUpSuggestions(makeSuggestions(new String[]{"pkg1"})); + setupSuggestions(makeSuggestions("pkg1")); mDashboardAdapter.onPause(); mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); @@ -313,7 +368,7 @@ public class DashboardAdapterTest { assertThat(mActionCategoryCaptor.getAllValues().toArray()).isEqualTo(expectedActions); } - private List makeSuggestions(String[] pkgNames) { + private List makeSuggestions(String... pkgNames) { final List suggestions = new ArrayList<>(); for (String pkgName : pkgNames) { Tile suggestion = new Tile(); @@ -324,11 +379,31 @@ public class DashboardAdapterTest { return suggestions; } - private void setUpSuggestions(List suggestions) { + private void setupSuggestions(List suggestions) { mDashboardAdapter.setCategoriesAndSuggestions(new ArrayList<>(), suggestions); mSuggestionHolder = mDashboardAdapter.onCreateViewHolder( new FrameLayout(RuntimeEnvironment.application), - mDashboardAdapter.getItemViewType(0)); + mDashboardAdapter.getItemViewType(1)); } + private void makeCondition() { + final List conditions = new ArrayList<>(); + Condition condition = mock(Condition.class); + when(condition.shouldShow()).thenReturn(true); + conditions.add(condition); + mDashboardAdapter.setConditions(conditions); + } + + private void makeCategory() { + List categories = new ArrayList<>(); + categories.add(new DashboardCategory()); + mDashboardAdapter.setCategory(categories); + } + + private DashboardAdapter.DashboardItemHolder setupSpacer() { + Context context = RuntimeEnvironment.application; + final View view = LayoutInflater.from(context) + .inflate(R.layout.dashboard_header_spacer, new LinearLayout(context), false); + return new DashboardAdapter.DashboardItemHolder(view); + } } diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardDataTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardDataTest.java index abea5653482..8bbb15b3ba1 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardDataTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardDataTest.java @@ -112,7 +112,7 @@ public class DashboardDataTest { public void testBuildItemsData_containsAllData() { final DashboardData.SuggestionHeaderData data = new DashboardData.SuggestionHeaderData(false, 1, 0); - final Object[] expectedObjects = {mTestCondition, null, data, mTestSuggestion, + final Object[] expectedObjects = {null, mTestCondition, null, data, mTestSuggestion, mDashboardCategory, mTestCategoryTile}; final int expectedSize = expectedObjects.length; @@ -171,7 +171,7 @@ public class DashboardDataTest { @Test public void testDiffUtil_DataEqual_noResultData() { List testResultData = new ArrayList<>(); - testDiffUtil(mDashboardDataWithOneConditions, + testDiffUtil(mDashboardDataWithOneConditions, mDashboardDataWithOneConditions, testResultData); } @@ -180,7 +180,7 @@ public class DashboardDataTest { //Build testResultData final List testResultData = new ArrayList<>(); testResultData.add(new ListUpdateResult.ResultData( - ListUpdateResult.ResultData.TYPE_OPERATION_INSERT, 1, 1)); + ListUpdateResult.ResultData.TYPE_OPERATION_INSERT, 2, 1)); testDiffUtil(mDashboardDataWithOneConditions, mDashboardDataWithTwoConditions, testResultData); @@ -191,7 +191,7 @@ public class DashboardDataTest { //Build testResultData final List testResultData = new ArrayList<>(); testResultData.add(new ListUpdateResult.ResultData( - ListUpdateResult.ResultData.TYPE_OPERATION_REMOVE, 0, 6)); + ListUpdateResult.ResultData.TYPE_OPERATION_REMOVE, 1, 6)); testDiffUtil(mDashboardDataWithOneConditions, mDashboardDataWithNoItems, testResultData); } @@ -203,8 +203,8 @@ public class DashboardDataTest { mDashboardDataWithOneConditions.getItemList(), mDashboardDataWithOneConditions.getItemList()); - // Item in position 0 is condition card, which payload should not be null - assertThat(callback.getChangePayload(0, 0)).isNotEqualTo(null); + // Item in position 1 is condition card, which payload should not be null + assertThat(callback.getChangePayload(1, 1)).isNotNull(); } @Test @@ -214,9 +214,9 @@ public class DashboardDataTest { mDashboardDataWithOneConditions.getItemList(), mDashboardDataWithOneConditions.getItemList()); - // Only item in position 0 is condition card, so others' payload should be null - for (int i = 1; i < mDashboardDataWithOneConditions.getItemList().size(); i++) { - assertThat(callback.getChangePayload(i, i)).isEqualTo(null); + // Position 0 is spacer, 1 is condition card, so others' payload should be null + for (int i = 2; i < mDashboardDataWithOneConditions.getItemList().size(); i++) { + assertThat(callback.getChangePayload(i, i)).isNull(); } } @@ -356,6 +356,11 @@ public class DashboardDataTest { return arg2 - resultData.arg2; } + + @Override + public String toString() { + return "op:" + operation + ",arg1:" + arg1 + ",arg2:" + arg2; + } } } }