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
This commit is contained in:
Jason Monk
2016-01-07 16:25:34 -05:00
parent c24d360328
commit d4f03ec86f
14 changed files with 340 additions and 56 deletions

View File

@@ -17,13 +17,12 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/category" android:id="@+id/category"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="@dimen/dashboard_category_height"
android:paddingStart="@dimen/dashboard_category_padding_start" android:paddingStart="@dimen/dashboard_category_padding_start"
android:paddingEnd="@dimen/dashboard_category_padding_end" android:paddingEnd="@dimen/dashboard_category_padding_end"
android:orientation="vertical" android:orientation="vertical"
android:paddingBottom="8dip" android:paddingBottom="8dip"
android:background="@color/card_background" android:background="@color/card_background" >
android:elevation="@dimen/dashboard_category_elevation" >
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -32,7 +31,7 @@
<TextView android:id="@android:id/title" <TextView android:id="@android:id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/dashboard_category_title_height" android:layout_height="match_parent"
android:paddingStart="@dimen/dashboard_category_title_margin_start" android:paddingStart="@dimen/dashboard_category_title_margin_start"
android:singleLine="true" android:singleLine="true"
android:ellipsize="marquee" android:ellipsize="marquee"

View File

@@ -21,8 +21,7 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:minHeight="@dimen/dashboard_tile_minimum_height" android:minHeight="@dimen/dashboard_tile_minimum_height"
android:clickable="true" android:clickable="true"
android:background="@drawable/selectable_card" android:background="@drawable/selectable_card" >
android:elevation="@dimen/dashboard_category_elevation" >
<ImageView <ImageView
android:id="@android:id/icon" android:id="@android:id/icon"

View File

@@ -16,7 +16,7 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android" <TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/dashboard_category_title_height" android:layout_height="@dimen/dashboard_category_height"
android:paddingStart="@dimen/search_title_padding_start" android:paddingStart="@dimen/search_title_padding_start"
android:singleLine="true" android:singleLine="true"
android:ellipsize="marquee" android:ellipsize="marquee"

View File

@@ -16,7 +16,7 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android" <TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/dashboard_category_title_height" android:layout_height="@dimen/dashboard_category_height"
android:paddingStart="@dimen/search_title_padding_start" android:paddingStart="@dimen/search_title_padding_start"
android:singleLine="true" android:singleLine="true"
android:ellipsize="marquee" android:ellipsize="marquee"

View File

@@ -21,8 +21,7 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:minHeight="@dimen/dashboard_tile_minimum_height" android:minHeight="@dimen/dashboard_tile_minimum_height"
android:clickable="true" android:clickable="true"
android:background="@drawable/selectable_card" android:background="@drawable/selectable_card">
android:elevation="@dimen/dashboard_category_elevation">
<View <View
android:layout_width="@dimen/dashboard_tile_image_size" android:layout_width="@dimen/dashboard_tile_image_size"

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/dashboard_category_height"
android:clickable="true"
android:background="@drawable/selectable_card"
android:elevation="@dimen/dashboard_category_elevation"
android:gravity="center_vertical" >
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="@dimen/suggestion_arrow_margin"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.TileTitle"
android:textColor="?android:attr/colorAccent"
android:alpha=".87"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<ImageView android:id="@android:id/icon"
android:layout_width="@dimen/dashboard_tile_image_size"
android:layout_height="@dimen/dashboard_tile_image_size"
android:layout_marginStart="@dimen/suggestion_arrow_margin"
android:layout_marginEnd="@dimen/suggestion_arrow_margin"
android:src="@drawable/ic_expand_more" />
</LinearLayout>

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:background="@drawable/selectable_card"
android:elevation="@dimen/dashboard_category_elevation"
android:orientation="vertical" >
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="@dimen/dashboard_tile_minimum_height">
<ImageView
android:id="@android:id/icon"
android:layout_width="@dimen/dashboard_tile_image_size"
android:layout_height="@dimen/dashboard_tile_image_size"
android:scaleType="centerInside"
android:layout_marginStart="@dimen/dashboard_tile_image_margin_start"
android:layout_marginEnd="@dimen/dashboard_tile_image_margin_end" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.TileTitle"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<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="@style/TextAppearance.Small"
android:textColor="?android:attr/textColorSecondary" />
</RelativeLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent">
<ImageView android:id="@+id/overflow"
android:layout_width="44dp"
android:layout_height="44dp"
android:paddingStart="16dp"
android:paddingBottom="16dp"
android:paddingTop="12dp"
android:paddingEnd="12dp"
android:gravity="top"
style="?android:attr/actionOverflowButtonStyle" />
</FrameLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -103,8 +103,8 @@
<!-- Dashboard category panel elevation --> <!-- Dashboard category panel elevation -->
<dimen name="dashboard_category_elevation">2dp</dimen> <dimen name="dashboard_category_elevation">2dp</dimen>
<!-- Dashboard category title layout height --> <!-- Dashboard category layout height -->
<dimen name="dashboard_category_title_height">48dp</dimen> <dimen name="dashboard_category_height">48dp</dimen>
<!-- Dashboard category title margin start --> <!-- Dashboard category title margin start -->
<dimen name="dashboard_category_title_margin_start">16dp</dimen> <dimen name="dashboard_category_title_margin_start">16dp</dimen>
@@ -119,6 +119,8 @@
<dimen name="dashboard_tile_image_margin_start">16dp</dimen> <dimen name="dashboard_tile_image_margin_start">16dp</dimen>
<dimen name="dashboard_tile_image_margin_end">32dp</dimen> <dimen name="dashboard_tile_image_margin_end">32dp</dimen>
<dimen name="suggestion_arrow_margin">16dp</dimen>
<!-- SwitchBar margin start / end --> <!-- SwitchBar margin start / end -->
<dimen name="switchbar_margin_start">16dp</dimen> <dimen name="switchbar_margin_start">16dp</dimen>
<dimen name="switchbar_margin_end">16dp</dimen> <dimen name="switchbar_margin_end">16dp</dimen>

View File

@@ -6767,4 +6767,10 @@
<!-- Summary of condition that background data is off [CHAR LIMIT=NONE] --> <!-- Summary of condition that background data is off [CHAR LIMIT=NONE] -->
<string name="condition_bg_data_summary">Background data is only available via Wi-Fi. This may affect some apps or services when Wi-Fi is not available.</string> <string name="condition_bg_data_summary">Background data is only available via Wi-Fi. This may affect some apps or services when Wi-Fi is not available.</string>
<!-- Title for the suggestions section on the dashboard [CHAR LIMIT=30] -->
<string name="suggestions_title">Suggestions (<xliff:g name="count" example="3">%1$d</xliff:g>)</string>
<!-- Name of option to remove a suggestion from the list [CHAR LIMIT=30] -->
<string name="suggestion_remove">Remove</string>
</resources> </resources>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 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.
-->
<optional-steps>
<step category="com.android.settings.suggested.category.LOCK_SCREEN" />
<step category="com.android.settings.suggested.category.EMAIL" />
<step category="com.android.settings.suggested.category.PAYMENT" />
<step category="com.android.settings.suggested.category.PARTNER_ACCOUNT"
multiple="true" />
<step category="com.android.settings.suggested.category.DEFAULT"
multiple="true" />
</optional-steps>

View File

@@ -50,7 +50,6 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.SearchView; import android.widget.SearchView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils;
import com.android.settings.Settings.WifiSettingsActivity; import com.android.settings.Settings.WifiSettingsActivity;
import com.android.settings.accessibility.AccessibilitySettings; 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.WifiSettings;
import com.android.settings.wifi.p2p.WifiP2pSettings; import com.android.settings.wifi.p2p.WifiP2pSettings;
import com.android.settingslib.drawer.DashboardCategory; 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 com.android.settingslib.drawer.SettingsDrawerActivity;
import java.util.ArrayList; import java.util.ArrayList;
@@ -199,6 +198,8 @@ public class SettingsActivity extends SettingsDrawerActivity
private static final String EMPTY_QUERY = ""; private static final String EMPTY_QUERY = "";
private static final int REQUEST_SUGGESTION = 42;
private String mFragmentClass; private String mFragmentClass;
private CharSequence mInitialTitle; private CharSequence mInitialTitle;
@@ -365,6 +366,7 @@ public class SettingsActivity extends SettingsDrawerActivity
private int mHomeActivitiesCount = 1; private int mHomeActivitiesCount = 1;
private Intent mResultIntentData; private Intent mResultIntentData;
private ComponentName mCurrentSuggestion;
public SwitchBar getSwitchBar() { public SwitchBar getSwitchBar() {
return mSwitchBar; return mSwitchBar;
@@ -1031,7 +1033,7 @@ public class SettingsActivity extends SettingsDrawerActivity
// When on restricted users, disable all extra categories (but only the settings ones). // When on restricted users, disable all extra categories (but only the settings ones).
List<DashboardCategory> categories = getDashboardCategories(); List<DashboardCategory> categories = getDashboardCategories();
for (DashboardCategory category : categories) { for (DashboardCategory category : categories) {
for (DashboardTile tile : category.tiles) { for (Tile tile : category.tiles) {
ComponentName component = tile.intent.getComponent(); ComponentName component = tile.intent.getComponent();
if (packageName.equals(component)&& !ArrayUtils.contains( if (packageName.equals(component)&& !ArrayUtils.contains(
SETTINGS_FOR_RESTRICTED, component.getClassName())) { SETTINGS_FOR_RESTRICTED, component.getClassName())) {
@@ -1146,7 +1148,7 @@ public class SettingsActivity extends SettingsDrawerActivity
} }
@Override @Override
protected void onTileClicked(DashboardTile tile) { protected void onTileClicked(Tile tile) {
if (mIsShowingDashboard) { if (mIsShowingDashboard) {
// If on dashboard, don't finish so the back comes back to here. // If on dashboard, don't finish so the back comes back to here.
openTile(tile); openTile(tile);
@@ -1200,4 +1202,20 @@ public class SettingsActivity extends SettingsDrawerActivity
public void setResultIntentData(Intent resultIntentData) { public void setResultIntentData(Intent resultIntentData) {
mResultIntentData = 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);
}
} }

View File

@@ -16,10 +16,14 @@
package com.android.settings.dashboard; package com.android.settings.dashboard;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; 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.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapterUtils; import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
import com.android.settingslib.drawer.DashboardCategory; 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.ArrayList;
import java.util.List; import java.util.List;
public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.DashboardItemHolder> implements View.OnClickListener { public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.DashboardItemHolder>
implements View.OnClickListener {
public static final String TAG = "DashboardAdapter"; 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<Object> mItems = new ArrayList<>(); private final List<Object> mItems = new ArrayList<>();
private final List<Integer> mTypes = new ArrayList<>(); private final List<Integer> mTypes = new ArrayList<>();
private final List<Integer> mIds = new ArrayList<>(); private final List<Integer> mIds = new ArrayList<>();
@@ -46,11 +57,14 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
private List<DashboardCategory> mCategories; private List<DashboardCategory> mCategories;
private List<Condition> mConditions; private List<Condition> mConditions;
private List<Tile> mSuggestions;
private boolean mIsShowingAll; private boolean mIsShowingAll;
// Used for counting items; // Used for counting items;
private int mId; private int mId;
private int mSuggestionMode = SUGGESTION_MODE_DEFAULT;
private Condition mExpandedCondition = null; private Condition mExpandedCondition = null;
public DashboardAdapter(Context context) { public DashboardAdapter(Context context) {
@@ -59,6 +73,11 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
setHasStableIds(true); setHasStableIds(true);
} }
public void setSuggestions(List<Tile> suggestions) {
mSuggestions = suggestions;
recountItems();
}
public void setCategories(List<DashboardCategory> categories) { public void setCategories(List<DashboardCategory> categories) {
mCategories = categories; mCategories = categories;
@@ -68,7 +87,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
tintColor, true); tintColor, true);
for (int i = 0; i < categories.size(); i++) { for (int i = 0; i < categories.size(); i++) {
for (int j = 0; j < categories.get(i).tiles.size(); j++) { for (int j = 0; j < categories.get(i).tiles.size(); j++) {
DashboardTile tile = categories.get(i).tiles.get(j); Tile tile = categories.get(i).tiles.get(j);
if (!mContext.getPackageName().equals( if (!mContext.getPackageName().equals(
tile.intent.getComponent().getPackageName())) { tile.intent.getComponent().getPackageName())) {
@@ -78,34 +97,53 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
} }
} }
} }
setShowingAll(mIsShowingAll); recountItems();
} }
public void setConditions(List<Condition> conditions) { public void setConditions(List<Condition> conditions) {
mConditions = conditions; mConditions = conditions;
setShowingAll(mIsShowingAll); recountItems();
} }
public boolean isShowingAll() { public boolean isShowingAll() {
return mIsShowingAll; return mIsShowingAll;
} }
public void notifyChanged(DashboardTile tile) { public void notifyChanged(Tile tile) {
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void setShowingAll(boolean showingAll) { public void setShowingAll(boolean showingAll) {
mIsShowingAll = showingAll; mIsShowingAll = showingAll;
recountItems();
}
private void recountItems() {
reset(); reset();
boolean hasConditions = false;
for (int i = 0; mConditions != null && i < mConditions.size(); i++) { 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); countItem(null, R.layout.dashboard_spacer, true);
for (int i = 0; mCategories != null && i < mCategories.size(); i++) { for (int i = 0; mCategories != null && i < mCategories.size(); i++) {
DashboardCategory category = mCategories.get(i); DashboardCategory category = mCategories.get(i);
countItem(category, R.layout.dashboard_category, mIsShowingAll); countItem(category, R.layout.dashboard_category, mIsShowingAll);
for (int j = 0; j < category.tiles.size(); j++) { 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 countItem(tile, R.layout.dashboard_tile, mIsShowingAll
|| ArrayUtils.contains(DashboardSummary.INITIAL_ITEMS, || ArrayUtils.contains(DashboardSummary.INITIAL_ITEMS,
tile.intent.getComponent().getClassName())); tile.intent.getComponent().getClassName()));
@@ -126,6 +164,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
if (add) { if (add) {
mItems.add(object); mItems.add(object);
mTypes.add(type); mTypes.add(type);
// TODO: Counting namespaces for handling of suggestions/conds appearing/disappearing.
mIds.add(mId); mIds.add(mId);
} }
mId++; mId++;
@@ -144,7 +183,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
onBindCategory(holder, (DashboardCategory) mItems.get(position)); onBindCategory(holder, (DashboardCategory) mItems.get(position));
break; break;
case R.layout.dashboard_tile: case R.layout.dashboard_tile:
final DashboardTile tile = (DashboardTile) mItems.get(position); final Tile tile = (Tile) mItems.get(position);
onBindTile(holder, tile); onBindTile(holder, tile);
holder.itemView.setOnClickListener(new View.OnClickListener() { holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override @Override
@@ -153,14 +192,28 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
} }
}); });
break; break;
case R.layout.see_all: case R.layout.suggestion_header:
onBindSeeAll(holder); onBindSuggestionHeader(holder);
break;
case R.layout.suggestion_tile:
final Tile suggestion = (Tile) mItems.get(position);
onBindTile(holder, suggestion);
holder.itemView.setOnClickListener(new View.OnClickListener() { holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
setShowingAll(!mIsShowingAll); ((SettingsActivity) mContext).startSuggestion(suggestion.intent);
} }
}); });
holder.itemView.findViewById(R.id.overflow).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
showRemoveOption(v, suggestion);
}
});
break;
case R.layout.see_all:
onBindSeeAll(holder);
break; break;
case R.layout.condition_card: case R.layout.condition_card:
ConditionAdapterUtils.bindViews((Condition) mItems.get(position), holder, ConditionAdapterUtils.bindViews((Condition) mItems.get(position), holder,
@@ -175,11 +228,53 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
} }
} }
private void onBindTile(DashboardItemHolder holder, DashboardTile dashboardTile) { private void showRemoveOption(View v, final Tile suggestion) {
holder.icon.setImageIcon(dashboardTile.icon); PopupMenu popup = new PopupMenu(
holder.title.setText(dashboardTile.title); new ContextThemeWrapper(mContext, R.style.Theme_AppCompat_DayNight), v);
if (!TextUtils.isEmpty(dashboardTile.summary)) { popup.getMenu().add(R.string.suggestion_remove).setOnMenuItemClickListener(
holder.summary.setText(dashboardTile.summary); new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
mContext.getPackageManager().setComponentEnabledSetting(
suggestion.intent.getComponent(),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
mSuggestions.remove(suggestion);
recountItems();
return true;
}
});
popup.show();
}
private void onBindSuggestionHeader(final DashboardItemHolder holder) {
holder.icon.setImageResource(hasMoreSuggestions() ? R.drawable.ic_expand_more
: R.drawable.ic_expand_less);
holder.title.setText(mContext.getString(R.string.suggestions_title, mSuggestions.size()));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (hasMoreSuggestions()) {
mSuggestionMode = SUGGESTION_MODE_EXPANDED;
} else {
mSuggestionMode = SUGGESTION_MODE_COLLAPSED;
}
recountItems();
}
});
}
private boolean hasMoreSuggestions() {
return mSuggestionMode == SUGGESTION_MODE_COLLAPSED
|| (mSuggestionMode == SUGGESTION_MODE_DEFAULT
&& mSuggestions.size() > 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); holder.summary.setVisibility(View.VISIBLE);
} else { } else {
holder.summary.setVisibility(View.GONE); holder.summary.setVisibility(View.GONE);
@@ -193,6 +288,12 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
private void onBindSeeAll(DashboardItemHolder holder) { private void onBindSeeAll(DashboardItemHolder holder) {
holder.title.setText(mIsShowingAll ? R.string.see_less holder.title.setText(mIsShowingAll ? R.string.see_less
: R.string.see_all); : R.string.see_all);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setShowingAll(!mIsShowingAll);
}
});
} }
@Override @Override

View File

@@ -33,6 +33,7 @@ import com.android.settings.SettingsActivity;
import com.android.settings.dashboard.conditional.ConditionAdapterUtils; import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
import com.android.settings.dashboard.conditional.ConditionManager; import com.android.settings.dashboard.conditional.ConditionManager;
import com.android.settings.dashboard.conditional.FocusRecyclerView; import com.android.settings.dashboard.conditional.FocusRecyclerView;
import com.android.settingslib.SuggestionParser;
import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.SettingsDrawerActivity; import com.android.settingslib.drawer.SettingsDrawerActivity;
@@ -58,6 +59,7 @@ public class DashboardSummary extends InstrumentedFragment
private DashboardAdapter mAdapter; private DashboardAdapter mAdapter;
private SummaryLoader mSummaryLoader; private SummaryLoader mSummaryLoader;
private ConditionManager mConditionManager; private ConditionManager mConditionManager;
private SuggestionParser mSuggestionParser;
@Override @Override
protected int getMetricsCategory() { protected int getMetricsCategory() {
@@ -76,6 +78,7 @@ public class DashboardSummary extends InstrumentedFragment
if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
+ " ms"); + " ms");
mConditionManager = ConditionManager.get(getContext()); mConditionManager = ConditionManager.get(getContext());
mSuggestionParser = new SuggestionParser(getContext(), R.xml.suggestion_ordering);
} }
@Override @Override
@@ -135,6 +138,7 @@ public class DashboardSummary extends InstrumentedFragment
mDashboard.setListener(this); mDashboard.setListener(this);
mAdapter = new DashboardAdapter(getContext()); mAdapter = new DashboardAdapter(getContext());
mAdapter.setConditions(mConditionManager.getConditions()); mAdapter.setConditions(mConditionManager.getConditions());
mAdapter.setSuggestions(mSuggestionParser.getSuggestions());
mSummaryLoader.setAdapter(mAdapter); mSummaryLoader.setAdapter(mAdapter);
ConditionAdapterUtils.addDismiss(mDashboard); ConditionAdapterUtils.addDismiss(mDashboard);

View File

@@ -25,7 +25,7 @@ import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.DashboardTile; import com.android.settingslib.drawer.Tile;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
@@ -38,8 +38,8 @@ public class SummaryLoader {
public static final String SUMMARY_PROVIDER_FACTORY = "SUMMARY_PROVIDER_FACTORY"; public static final String SUMMARY_PROVIDER_FACTORY = "SUMMARY_PROVIDER_FACTORY";
private final Activity mActivity; private final Activity mActivity;
private final ArrayMap<SummaryProvider, DashboardTile> mSummaryMap = new ArrayMap<>(); private final ArrayMap<SummaryProvider, Tile> mSummaryMap = new ArrayMap<>();
private final List<DashboardTile> mTiles = new ArrayList<>(); private final List<Tile> mTiles = new ArrayList<>();
private final Worker mWorker; private final Worker mWorker;
private final Handler mHandler; private final Handler mHandler;
@@ -54,9 +54,9 @@ public class SummaryLoader {
mWorker = new Worker(mWorkerThread.getLooper()); mWorker = new Worker(mWorkerThread.getLooper());
mActivity = activity; mActivity = activity;
for (int i = 0; i < categories.size(); i++) { for (int i = 0; i < categories.size(); i++) {
List<DashboardTile> tiles = categories.get(i).tiles; List<Tile> tiles = categories.get(i).tiles;
for (int j = 0; j < tiles.size(); j++) { 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(); mWorker.obtainMessage(Worker.MSG_GET_PROVIDER, tile).sendToTarget();
} }
} }
@@ -71,7 +71,7 @@ public class SummaryLoader {
} }
public void setSummary(SummaryProvider provider, final CharSequence summary) { public void setSummary(SummaryProvider provider, final CharSequence summary) {
final DashboardTile tile = mSummaryMap.get(provider); final Tile tile = mSummaryMap.get(provider);
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -85,7 +85,7 @@ public class SummaryLoader {
mWorker.obtainMessage(Worker.MSG_SET_LISTENING, listening ? 1 : 0, 0).sendToTarget(); 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())) { if (!mActivity.getPackageName().equals(tile.intent.getComponent().getPackageName())) {
// Not within Settings, can't load Summary directly. // Not within Settings, can't load Summary directly.
// TODO: Load summary indirectly. // TODO: Load summary indirectly.
@@ -118,7 +118,7 @@ public class SummaryLoader {
return null; return null;
} }
private Bundle getMetaData(DashboardTile tile) { private Bundle getMetaData(Tile tile) {
return tile.metaData; return tile.metaData;
} }
@@ -142,7 +142,7 @@ public class SummaryLoader {
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
case MSG_GET_PROVIDER: case MSG_GET_PROVIDER:
DashboardTile tile = (DashboardTile) msg.obj; Tile tile = (Tile) msg.obj;
SummaryProvider provider = getSummaryProvider(tile); SummaryProvider provider = getSummaryProvider(tile);
if (provider != null) { if (provider != null) {
if (DEBUG) Log.d(TAG, "Creating " + tile); if (DEBUG) Log.d(TAG, "Creating " + tile);