From d4f03ec86f9e8b7b108fc63684e23f5c0fb2a864 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Thu, 7 Jan 2016 16:25:34 -0500 Subject: [PATCH] Add suggestions to settings Use an XML to define the categories that Settings will look for, and surface enabled activities under those categories as suggestions. When clicked on the activity will be started for result. If the result is not cancelled, then the operation is assumed successful and the suggestion is disabled. Users can also use an overflow -> remove flow to get rid of unwanted suggestions. Change-Id: I767abf8efe103af0509bc6b6b55888ae82643512 --- res/layout/dashboard_category.xml | 35 +++-- res/layout/dashboard_tile.xml | 3 +- res/layout/search_panel_results_header.xml | 2 +- .../search_panel_suggestions_header.xml | 2 +- res/layout/see_all.xml | 3 +- res/layout/suggestion_header.xml | 45 ++++++ res/layout/suggestion_tile.xml | 86 +++++++++++ res/values/dimens.xml | 6 +- res/values/strings.xml | 6 + res/xml/suggestion_ordering.xml | 25 ++++ .../android/settings/SettingsActivity.java | 26 +++- .../settings/dashboard/DashboardAdapter.java | 135 +++++++++++++++--- .../settings/dashboard/DashboardSummary.java | 4 + .../settings/dashboard/SummaryLoader.java | 18 +-- 14 files changed, 340 insertions(+), 56 deletions(-) create mode 100644 res/layout/suggestion_header.xml create mode 100644 res/layout/suggestion_tile.xml create mode 100644 res/xml/suggestion_ordering.xml diff --git a/res/layout/dashboard_category.xml b/res/layout/dashboard_category.xml index 9109440431e..e79f8d512e0 100644 --- a/res/layout/dashboard_category.xml +++ b/res/layout/dashboard_category.xml @@ -15,15 +15,14 @@ --> + android:id="@+id/category" + android:layout_width="match_parent" + android:layout_height="@dimen/dashboard_category_height" + android:paddingStart="@dimen/dashboard_category_padding_start" + android:paddingEnd="@dimen/dashboard_category_padding_end" + android:orientation="vertical" + android:paddingBottom="8dip" + android:background="@color/card_background" > + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingStart="@dimen/dashboard_category_title_margin_start" + android:singleLine="true" + android:ellipsize="marquee" + android:gravity="center_vertical" + android:textAppearance="@style/TextAppearance.CategoryTitle" + android:textAlignment="viewStart" + /> diff --git a/res/layout/dashboard_tile.xml b/res/layout/dashboard_tile.xml index cc237eebdf9..cd7c8ee08b0 100644 --- a/res/layout/dashboard_tile.xml +++ b/res/layout/dashboard_tile.xml @@ -21,8 +21,7 @@ android:gravity="center_vertical" android:minHeight="@dimen/dashboard_tile_minimum_height" android:clickable="true" - android:background="@drawable/selectable_card" - android:elevation="@dimen/dashboard_category_elevation" > + android:background="@drawable/selectable_card" > + android:background="@drawable/selectable_card"> + + + + + + + + + diff --git a/res/layout/suggestion_tile.xml b/res/layout/suggestion_tile.xml new file mode 100644 index 00000000000..0b5e65244d4 --- /dev/null +++ b/res/layout/suggestion_tile.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 539dc058eba..79655e4f06d 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -103,8 +103,8 @@ 2dp - - 48dp + + 48dp 16dp @@ -119,6 +119,8 @@ 16dp 32dp + 16dp + 16dp 16dp diff --git a/res/values/strings.xml b/res/values/strings.xml index e7442ed5d90..cf8acead719 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6767,4 +6767,10 @@ Background data is only available via Wi-Fi. This may affect some apps or services when Wi-Fi is not available. + + Suggestions (%1$d) + + + Remove + diff --git a/res/xml/suggestion_ordering.xml b/res/xml/suggestion_ordering.xml new file mode 100644 index 00000000000..339b195bc1f --- /dev/null +++ b/res/xml/suggestion_ordering.xml @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 4d9e2f0ae70..ba975a2c2e7 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -50,7 +50,6 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.SearchView; -import com.android.internal.logging.MetricsLogger; import com.android.internal.util.ArrayUtils; import com.android.settings.Settings.WifiSettingsActivity; import com.android.settings.accessibility.AccessibilitySettings; @@ -111,7 +110,7 @@ import com.android.settings.wifi.SavedAccessPointsWifiSettings; import com.android.settings.wifi.WifiSettings; import com.android.settings.wifi.p2p.WifiP2pSettings; import com.android.settingslib.drawer.DashboardCategory; -import com.android.settingslib.drawer.DashboardTile; +import com.android.settingslib.drawer.Tile; import com.android.settingslib.drawer.SettingsDrawerActivity; import java.util.ArrayList; @@ -199,6 +198,8 @@ public class SettingsActivity extends SettingsDrawerActivity private static final String EMPTY_QUERY = ""; + private static final int REQUEST_SUGGESTION = 42; + private String mFragmentClass; private CharSequence mInitialTitle; @@ -365,6 +366,7 @@ public class SettingsActivity extends SettingsDrawerActivity private int mHomeActivitiesCount = 1; private Intent mResultIntentData; + private ComponentName mCurrentSuggestion; public SwitchBar getSwitchBar() { return mSwitchBar; @@ -1031,7 +1033,7 @@ public class SettingsActivity extends SettingsDrawerActivity // When on restricted users, disable all extra categories (but only the settings ones). List categories = getDashboardCategories(); for (DashboardCategory category : categories) { - for (DashboardTile tile : category.tiles) { + for (Tile tile : category.tiles) { ComponentName component = tile.intent.getComponent(); if (packageName.equals(component)&& !ArrayUtils.contains( SETTINGS_FOR_RESTRICTED, component.getClassName())) { @@ -1146,7 +1148,7 @@ public class SettingsActivity extends SettingsDrawerActivity } @Override - protected void onTileClicked(DashboardTile tile) { + protected void onTileClicked(Tile tile) { if (mIsShowingDashboard) { // If on dashboard, don't finish so the back comes back to here. openTile(tile); @@ -1200,4 +1202,20 @@ public class SettingsActivity extends SettingsDrawerActivity public void setResultIntentData(Intent resultIntentData) { mResultIntentData = resultIntentData; } + + public void startSuggestion(Intent intent) { + mCurrentSuggestion = intent.getComponent(); + startActivityForResult(intent, REQUEST_SUGGESTION); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_SUGGESTION && mCurrentSuggestion != null + && resultCode != RESULT_CANCELED) { + getPackageManager().setComponentEnabledSetting(mCurrentSuggestion, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); + } + super.onActivityResult(requestCode, resultCode, data); + } + } diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java index a53d8b615ae..b564a277534 100644 --- a/src/com/android/settings/dashboard/DashboardAdapter.java +++ b/src/com/android/settings/dashboard/DashboardAdapter.java @@ -16,10 +16,14 @@ package com.android.settings.dashboard; import android.content.Context; +import android.content.pm.PackageManager; +import android.support.v7.widget.PopupMenu; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.TypedValue; +import android.view.ContextThemeWrapper; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -30,14 +34,21 @@ import com.android.settings.SettingsActivity; import com.android.settings.dashboard.conditional.Condition; import com.android.settings.dashboard.conditional.ConditionAdapterUtils; import com.android.settingslib.drawer.DashboardCategory; -import com.android.settingslib.drawer.DashboardTile; +import com.android.settingslib.drawer.Tile; import java.util.ArrayList; import java.util.List; -public class DashboardAdapter extends RecyclerView.Adapter implements View.OnClickListener { +public class DashboardAdapter extends RecyclerView.Adapter + implements View.OnClickListener { public static final String TAG = "DashboardAdapter"; + private static int SUGGESTION_MODE_DEFAULT = 0; + private static int SUGGESTION_MODE_COLLAPSED = 1; + private static int SUGGESTION_MODE_EXPANDED = 2; + + private static final int DEFAULT_SUGGESTION_COUNT = 2; + private final List mItems = new ArrayList<>(); private final List mTypes = new ArrayList<>(); private final List mIds = new ArrayList<>(); @@ -46,11 +57,14 @@ public class DashboardAdapter extends RecyclerView.Adapter mCategories; private List mConditions; + private List mSuggestions; private boolean mIsShowingAll; // Used for counting items; private int mId; + private int mSuggestionMode = SUGGESTION_MODE_DEFAULT; + private Condition mExpandedCondition = null; public DashboardAdapter(Context context) { @@ -59,6 +73,11 @@ public class DashboardAdapter extends RecyclerView.Adapter suggestions) { + mSuggestions = suggestions; + recountItems(); + } + public void setCategories(List categories) { mCategories = categories; @@ -68,7 +87,7 @@ public class DashboardAdapter extends RecyclerView.Adapter conditions) { mConditions = conditions; - setShowingAll(mIsShowingAll); + recountItems(); } public boolean isShowingAll() { return mIsShowingAll; } - public void notifyChanged(DashboardTile tile) { + public void notifyChanged(Tile tile) { notifyDataSetChanged(); } public void setShowingAll(boolean showingAll) { mIsShowingAll = showingAll; + recountItems(); + } + + private void recountItems() { reset(); + boolean hasConditions = false; for (int i = 0; mConditions != null && i < mConditions.size(); i++) { - countItem(mConditions.get(i), R.layout.condition_card, mConditions.get(i).shouldShow()); + boolean shouldShow = mConditions.get(i).shouldShow(); + hasConditions |= shouldShow; + countItem(mConditions.get(i), R.layout.condition_card, shouldShow); + } + boolean hasSuggestions = mSuggestions != null && mSuggestions.size() != 0; + countItem(null, R.layout.dashboard_spacer, hasConditions && hasSuggestions); + countItem(null, R.layout.suggestion_header, hasSuggestions); + if (mSuggestions != null) { + int maxSuggestions = mSuggestionMode == SUGGESTION_MODE_DEFAULT + ? Math.min(DEFAULT_SUGGESTION_COUNT, mSuggestions.size()) + : mSuggestionMode == SUGGESTION_MODE_EXPANDED ? mSuggestions.size() + : 0; + for (int i = 0; i < mSuggestions.size(); i++) { + countItem(mSuggestions.get(i), R.layout.suggestion_tile, i < maxSuggestions); + } } countItem(null, R.layout.dashboard_spacer, true); for (int i = 0; mCategories != null && i < mCategories.size(); i++) { DashboardCategory category = mCategories.get(i); countItem(category, R.layout.dashboard_category, mIsShowingAll); for (int j = 0; j < category.tiles.size(); j++) { - DashboardTile tile = category.tiles.get(j); + Tile tile = category.tiles.get(j); countItem(tile, R.layout.dashboard_tile, mIsShowingAll || ArrayUtils.contains(DashboardSummary.INITIAL_ITEMS, tile.intent.getComponent().getClassName())); @@ -126,6 +164,7 @@ public class DashboardAdapter extends RecyclerView.Adapter DEFAULT_SUGGESTION_COUNT); + } + + private void onBindTile(DashboardItemHolder holder, Tile tile) { + holder.icon.setImageIcon(tile.icon); + holder.title.setText(tile.title); + if (!TextUtils.isEmpty(tile.summary)) { + holder.summary.setText(tile.summary); holder.summary.setVisibility(View.VISIBLE); } else { holder.summary.setVisibility(View.GONE); @@ -193,6 +288,12 @@ public class DashboardAdapter extends RecyclerView.Adapter mSummaryMap = new ArrayMap<>(); - private final List mTiles = new ArrayList<>(); + private final ArrayMap mSummaryMap = new ArrayMap<>(); + private final List mTiles = new ArrayList<>(); private final Worker mWorker; private final Handler mHandler; @@ -54,9 +54,9 @@ public class SummaryLoader { mWorker = new Worker(mWorkerThread.getLooper()); mActivity = activity; for (int i = 0; i < categories.size(); i++) { - List tiles = categories.get(i).tiles; + List tiles = categories.get(i).tiles; for (int j = 0; j < tiles.size(); j++) { - DashboardTile tile = tiles.get(j); + Tile tile = tiles.get(j); mWorker.obtainMessage(Worker.MSG_GET_PROVIDER, tile).sendToTarget(); } } @@ -71,7 +71,7 @@ public class SummaryLoader { } public void setSummary(SummaryProvider provider, final CharSequence summary) { - final DashboardTile tile = mSummaryMap.get(provider); + final Tile tile = mSummaryMap.get(provider); mHandler.post(new Runnable() { @Override public void run() { @@ -85,7 +85,7 @@ public class SummaryLoader { mWorker.obtainMessage(Worker.MSG_SET_LISTENING, listening ? 1 : 0, 0).sendToTarget(); } - private SummaryProvider getSummaryProvider(DashboardTile tile) { + private SummaryProvider getSummaryProvider(Tile tile) { if (!mActivity.getPackageName().equals(tile.intent.getComponent().getPackageName())) { // Not within Settings, can't load Summary directly. // TODO: Load summary indirectly. @@ -118,7 +118,7 @@ public class SummaryLoader { return null; } - private Bundle getMetaData(DashboardTile tile) { + private Bundle getMetaData(Tile tile) { return tile.metaData; } @@ -142,7 +142,7 @@ public class SummaryLoader { public void handleMessage(Message msg) { switch (msg.what) { case MSG_GET_PROVIDER: - DashboardTile tile = (DashboardTile) msg.obj; + Tile tile = (Tile) msg.obj; SummaryProvider provider = getSummaryProvider(tile); if (provider != null) { if (DEBUG) Log.d(TAG, "Creating " + tile);