First pass at restyling dashboard

Still needs summaries, but the things are in the right place-ish.

Change-Id: I1cbc23da9f56589836b5ebd7e202114e8f323adc
This commit is contained in:
Jason Monk
2015-11-11 16:45:49 -05:00
parent 4309b9552c
commit 7c7eb70dc3
9 changed files with 345 additions and 141 deletions

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 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
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight" >
<item android:drawable="@color/card_background"/>
</ripple>

View File

@@ -14,24 +14,13 @@
limitations under the License.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dashboard"
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dashboard_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarStyle="outsideOverlay"
android:clipToPadding="false">
<LinearLayout
android:id="@+id/dashboard_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:paddingStart="@dimen/dashboard_padding_start"
android:paddingEnd="@dimen/dashboard_padding_end"
android:paddingTop="@dimen/dashboard_padding_top"
android:paddingBottom="@dimen/dashboard_padding_bottom"
android:clipToPadding="false"
android:orientation="vertical"
/>
</ScrollView>
android:paddingStart="@dimen/dashboard_padding_start"
android:paddingEnd="@dimen/dashboard_padding_end"
android:paddingTop="@dimen/dashboard_padding_top"
android:paddingBottom="@dimen/dashboard_padding_bottom"
android:clipToPadding="false" />

View File

@@ -21,11 +21,16 @@
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_marginBottom="8dip"
android:elevation="@dimen/dashboard_category_elevation">
android:elevation="@dimen/dashboard_category_elevation" >
<TextView android:id="@+id/category_title"
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<TextView android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="@dimen/dashboard_category_title_height"
android:paddingStart="@dimen/dashboard_category_title_margin_start"
@@ -36,10 +41,4 @@
android:textAlignment="viewStart"
/>
<com.android.settings.dashboard.DashboardContainerView
android:id="@+id/category_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 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.
-->
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="10dp" />

View File

@@ -19,10 +19,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="@dimen/dashboard_tile_minimum_height">
android:minHeight="@dimen/dashboard_tile_minimum_height"
android:clickable="true"
android:background="@drawable/selectable_card"
android:elevation="@dimen/dashboard_category_elevation" >
<ImageView
android:id="@+id/icon"
android:id="@android:id/icon"
android:layout_width="@dimen/dashboard_tile_image_size"
android:layout_height="@dimen/dashboard_tile_image_size"
android:scaleType="centerInside"
@@ -45,7 +48,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="@+id/title"
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -53,7 +56,7 @@
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView android:id="@+id/status"
<TextView android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
@@ -65,11 +68,6 @@
</LinearLayout>
<View android:id="@+id/tile_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/dividerVertical" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

65
res/layout/see_all.xml Normal file
View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 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:gravity="center_vertical"
android:minHeight="@dimen/dashboard_tile_minimum_height"
android:clickable="true"
android:background="@drawable/selectable_card"
android:elevation="@dimen/dashboard_category_elevation">
<View
android:layout_width="@dimen/dashboard_tile_image_size"
android:layout_height="@dimen/dashboard_tile_image_size"
android:layout_marginStart="@dimen/dashboard_tile_image_margin_start"
android:layout_marginEnd="@dimen/dashboard_tile_image_margin_end"
android:visibility="invisible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:orientation="vertical"
android:gravity="center_vertical"
android:layout_weight="1">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="@android:style/TextAppearance.Material.Widget.Button.Inverse"
android:textColor="?android:attr/colorAccent"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -6989,4 +6989,9 @@
<!-- Description for a custom display scale. This shows the requested display
density in raw pixels per inch rather than computing a scale amount. [CHAR LIMIT=24] -->
<string name="force_density_summary_custom">Custom (<xliff:g id="densityDpi" example="160">%d</xliff:g>)</string>
<!-- Button to show all top-level settings items [CHAR LIMIT=20] -->
<string name="see_all">See all</string>
<!-- Button to show less top-level settings items [CHAR LIMIT=20] -->
<string name="see_less">See less</string>
</resources>

View File

@@ -299,7 +299,7 @@
<style name="TextAppearance.Switch" parent="@android:style/TextAppearance.Material.Title" />
<style name="TextAppearance.CategoryTitle" parent="@android:style/TextAppearance.Material.Body2">
<item name="android:textColor">?android:attr/colorAccent</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
<style name="TextAppearance.TileTitle" parent="@android:style/TextAppearance.Material.Subhead" />

View File

@@ -20,11 +20,11 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
@@ -35,43 +35,39 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.ArrayUtils;
import com.android.settings.HelpUtils;
import com.android.settings.InstrumentedFragment;
import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.SettingsActivity;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.DashboardTile;
import java.util.ArrayList;
import java.util.List;
public class DashboardSummary extends InstrumentedFragment {
private static final String LOG_TAG = "DashboardSummary";
private static final boolean DEBUG = true;
private static final String TAG = "DashboardSummary";
private LayoutInflater mLayoutInflater;
private ViewGroup mDashboard;
private static final int MSG_REBUILD_UI = 1;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REBUILD_UI: {
final Context context = getActivity();
rebuildUI(context);
} break;
}
}
public static final String[] INITIAL_ITEMS = new String[] {
Settings.WifiSettingsActivity.class.getName(),
Settings.DataUsageSummaryActivity.class.getName(),
Settings.PowerUsageSummaryActivity.class.getName(),
Settings.ManageApplicationsActivity.class.getName(),
Settings.StorageSettingsActivity.class.getName(),
Settings.DisplaySettingsActivity.class.getName(),
Settings.NotificationSettingsActivity.class.getName(),
};
private class HomePackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
rebuildUI(context);
}
}
private HomePackageReceiver mHomePackageReceiver = new HomePackageReceiver();
private static final int MSG_REBUILD_UI = 1;
private final HomePackageReceiver mHomePackageReceiver = new HomePackageReceiver();
private RecyclerView mDashboard;
private DashboardAdapter mAdapter;
@Override
protected int getMetricsCategory() {
@@ -117,95 +113,33 @@ public class DashboardSummary extends InstrumentedFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.dashboard, container, false);
}
mLayoutInflater = inflater;
@Override
public void onViewCreated(View view, Bundle bundle) {
mDashboard = (RecyclerView) view.findViewById(R.id.dashboard_container);
LinearLayoutManager llm = new LinearLayoutManager(getContext());
llm.setOrientation(LinearLayoutManager.VERTICAL);
mDashboard.setLayoutManager(llm);
mDashboard.setHasFixedSize(true);
final View rootView = inflater.inflate(R.layout.dashboard, container, false);
mDashboard = (ViewGroup) rootView.findViewById(R.id.dashboard_container);
return rootView;
rebuildUI(getContext());
}
private void rebuildUI(Context context) {
if (!isAdded()) {
Log.w(LOG_TAG, "Cannot build the DashboardSummary UI yet as the Fragment is not added");
Log.w(TAG, "Cannot build the DashboardSummary UI yet as the Fragment is not added");
return;
}
long start = System.currentTimeMillis();
final Resources res = getResources();
mAdapter = new DashboardAdapter(getContext(),
((SettingsActivity) getActivity()).getDashboardCategories(true));
mDashboard.setAdapter(mAdapter);
mDashboard.removeAllViews();
List<DashboardCategory> categories =
((SettingsActivity) context).getDashboardCategories(true);
final int count = categories.size();
for (int n = 0; n < count; n++) {
DashboardCategory category = categories.get(n);
View categoryView = mLayoutInflater.inflate(R.layout.dashboard_category, mDashboard,
false);
TextView categoryLabel = (TextView) categoryView.findViewById(R.id.category_title);
categoryLabel.setText(category.title);
ViewGroup categoryContent =
(ViewGroup) categoryView.findViewById(R.id.category_content);
final int tilesCount = category.getTilesCount();
for (int i = 0; i < tilesCount; i++) {
DashboardTile tile = category.getTile(i);
DashboardTileView tileView = new DashboardTileView(context);
updateTileView(context, res, tile, tileView.getImageView(),
tileView.getTitleTextView(), tileView.getStatusTextView());
tileView.setTile(tile);
categoryContent.addView(tileView);
}
// Add the category
mDashboard.addView(categoryView);
}
long delta = System.currentTimeMillis() - start;
Log.d(LOG_TAG, "rebuildUI took: " + delta + " ms");
}
private void updateTileView(Context context, Resources res, DashboardTile tile,
ImageView tileIcon, TextView tileTextView, TextView statusTextView) {
if (tile.icon != null) {
if (!TextUtils.isEmpty(tile.icon.getResPackage())) {
Drawable drawable = tile.icon.loadDrawable(context);
if (!tile.icon.getResPackage().equals(context.getPackageName())
&& drawable != null) {
// If this drawable is coming from outside Settings, tint it to match the color.
TypedValue tintColor = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.colorAccent,
tintColor, true);
drawable.setTint(tintColor.data);
}
tileIcon.setImageDrawable(drawable);
} else {
tileIcon.setImageIcon(tile.icon);
}
} else {
tileIcon.setImageDrawable(null);
tileIcon.setBackground(null);
}
tileTextView.setText(tile.title);
CharSequence summary = tile.summary;
if (!TextUtils.isEmpty(summary)) {
statusTextView.setVisibility(View.VISIBLE);
statusTextView.setText(summary);
} else {
statusTextView.setVisibility(View.GONE);
}
Log.d(TAG, "rebuildUI took: " + delta + " ms");
}
private void sendRebuildUI() {
@@ -213,4 +147,178 @@ public class DashboardSummary extends InstrumentedFragment {
mHandler.sendEmptyMessage(MSG_REBUILD_UI);
}
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REBUILD_UI: {
final Context context = getActivity();
rebuildUI(context);
} break;
}
}
};
private class HomePackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
rebuildUI(context);
}
}
private static class DashboardItemHolder extends RecyclerView.ViewHolder {
private final ImageView icon;
private final TextView title;
private final TextView summary;
public DashboardItemHolder(View itemView) {
super(itemView);
icon = (ImageView) itemView.findViewById(android.R.id.icon);
title = (TextView) itemView.findViewById(android.R.id.title);
summary = (TextView) itemView.findViewById(android.R.id.summary);
}
}
private static class DashboardAdapter extends RecyclerView.Adapter<DashboardItemHolder> {
private final List<Object> mItems = new ArrayList<>();
private final List<Integer> mTypes = new ArrayList<>();
private final List<Integer> mIds = new ArrayList<>();
private final List<DashboardCategory> mCategories;
private final Context mContext;
private boolean mIsShowingAll;
// Used for counting items;
private int mId;
public DashboardAdapter(Context context, List<DashboardCategory> categories) {
mContext = context;
mCategories = categories;
// TODO: Better place for tinting?
TypedValue tintColor = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.colorAccent,
tintColor, true);
for (int i = 0; i < categories.size(); i++) {
for (int j = 0; j < categories.get(i).tiles.size(); j++) {
DashboardTile tile = categories.get(i).tiles.get(j);
if (!context.getPackageName().equals(
tile.intent.getComponent().getPackageName())) {
// If this drawable is coming from outside Settings, tint it to match the
// color.
tile.icon.setTint(tintColor.data);
}
}
}
setShowingAll(false);
setHasStableIds(true);
}
public void setShowingAll(boolean showingAll) {
mIsShowingAll = showingAll;
reset();
countItem(null, R.layout.dashboard_spacer, true);
for (int i = 0; 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);
Log.d(TAG, "Maybe adding " + tile.intent.getComponent().getClassName());
countItem(tile, R.layout.dashboard_tile, mIsShowingAll
|| ArrayUtils.contains(INITIAL_ITEMS,
tile.intent.getComponent().getClassName()));
}
}
countItem(null, R.layout.see_all, true);
notifyDataSetChanged();
}
private void reset() {
mItems.clear();
mTypes.clear();
mIds.clear();
mId = 0;
}
private void countItem(Object object, int type, boolean add) {
if (add) {
mItems.add(object);
mTypes.add(type);
mIds.add(mId);
}
mId++;
}
@Override
public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
viewType, parent, false));
}
@Override
public void onBindViewHolder(DashboardItemHolder holder, int position) {
switch (mTypes.get(position)) {
case R.layout.dashboard_category:
onBindCategory(holder, (DashboardCategory) mItems.get(position));
break;
case R.layout.dashboard_tile:
final DashboardTile tile = (DashboardTile) mItems.get(position);
onBindTile(holder, tile);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((SettingsActivity) mContext).openTile(tile);
}
});
break;
case R.layout.see_all:
onBindSeeAll(holder);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setShowingAll(!mIsShowingAll);
}
});
break;
}
}
private void onBindTile(DashboardItemHolder holder, DashboardTile dashboardTile) {
holder.icon.setImageIcon(dashboardTile.icon);
holder.title.setText(dashboardTile.title);
if (!TextUtils.isEmpty(dashboardTile.summary)) {
holder.summary.setText(dashboardTile.summary);
holder.summary.setVisibility(View.VISIBLE);
} else {
holder.summary.setVisibility(View.GONE);
}
}
private void onBindCategory(DashboardItemHolder holder, DashboardCategory category) {
holder.title.setText(category.title);
}
private void onBindSeeAll(DashboardItemHolder holder) {
holder.title.setText(mIsShowingAll ? R.string.see_less : R.string.see_all);
}
@Override
public long getItemId(int position) {
return mIds.get(position);
}
@Override
public int getItemViewType(int position) {
return mTypes.get(position);
}
@Override
public int getItemCount() {
return mIds.size();
}
}
}