Support suggestion UI card with a button.
Bug: 65065268 Test: robotests Change-Id: I24c8947e9b23a80de38b8cbd57404736a5d1660a
This commit is contained in:
@@ -33,26 +33,27 @@
|
|||||||
android:layout_width="@dimen/dashboard_tile_image_size"
|
android:layout_width="@dimen/dashboard_tile_image_size"
|
||||||
android:layout_height="@dimen/dashboard_tile_image_size"
|
android:layout_height="@dimen/dashboard_tile_image_size"
|
||||||
android:layout_marginStart="14dp"
|
android:layout_marginStart="14dp"
|
||||||
android:layout_marginEnd="24dp"/>
|
android:layout_marginEnd="24dp" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView android:id="@android:id/title"
|
<TextView
|
||||||
|
android:id="@android:id/title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textAppearance="@style/TextAppearance.TileTitle"
|
android:textAppearance="@style/TextAppearance.TileTitle"
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:fadingEdge="horizontal"/>
|
android:fadingEdge="horizontal" />
|
||||||
|
|
||||||
<TextView android:id="@android:id/summary"
|
<TextView
|
||||||
|
android:id="@android:id/summary"
|
||||||
|
android:textAppearance="@style/TextAppearance.SuggestionSummary"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content" />
|
||||||
android:textAppearance="@style/TextAppearance.Small"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
72
res/layout/suggestion_tile_with_button.xml
Normal file
72
res/layout/suggestion_tile_with_button.xml
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/white"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingBottom="20dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
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:contentDescription="@null" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:layout_marginStart="18dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextAppearance.SuggestionTitle"
|
||||||
|
android:id="@android:id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@android:id/summary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:layout_marginEnd="50dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.SuggestionSummary" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@android:id/primary"
|
||||||
|
style="@style/SuwGlifButton.Primary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:text="@string/suggestion_button_text" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@@ -7321,6 +7321,8 @@
|
|||||||
settings button -->
|
settings button -->
|
||||||
<string name="notification_app_settings_button">Notification settings</string>
|
<string name="notification_app_settings_button">Notification settings</string>
|
||||||
|
|
||||||
|
<!-- Generic label for suggestion card's ok button [CHAR LIMIT=20] -->
|
||||||
|
<string name="suggestion_button_text">Ok</string>
|
||||||
|
|
||||||
<!-- [CHAR LIMIT=35] Feedback on the device -->
|
<!-- [CHAR LIMIT=35] Feedback on the device -->
|
||||||
<string name="device_feedback">Send feedback about this device</string>
|
<string name="device_feedback">Send feedback about this device</string>
|
||||||
|
@@ -318,7 +318,10 @@
|
|||||||
<style name="TextAppearance.SuggestionTitle"
|
<style name="TextAppearance.SuggestionTitle"
|
||||||
parent="@android:style/TextAppearance.Material.Subhead">
|
parent="@android:style/TextAppearance.Material.Subhead">
|
||||||
<item name="android:fontFamily">sans-serif-medium</item>
|
<item name="android:fontFamily">sans-serif-medium</item>
|
||||||
<item name="android:textSize">14sp</item>
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.SuggestionSummary" parent="TextAppearance.Small">
|
||||||
|
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.FingerprintErrorText"
|
<style name="TextAppearance.FingerprintErrorText"
|
||||||
|
@@ -44,7 +44,7 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
|
|||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
private final SuggestionFeatureProvider mSuggestionFeatureProvider;
|
private final SuggestionFeatureProvider mSuggestionFeatureProvider;
|
||||||
@Deprecated // in favor of mNewSuggestions
|
@Deprecated // in favor of mSuggestionsV2
|
||||||
private final List<Tile> mSuggestions;
|
private final List<Tile> mSuggestions;
|
||||||
private final List<Suggestion> mSuggestionsV2;
|
private final List<Suggestion> mSuggestionsV2;
|
||||||
private final IconCache mCache;
|
private final IconCache mCache;
|
||||||
@@ -88,23 +88,15 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
|
|||||||
mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, id);
|
mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, id);
|
||||||
mSuggestionsShownLogged.add(id);
|
mSuggestionsShownLogged.add(id);
|
||||||
}
|
}
|
||||||
// TODO: Add remote view field in Suggestion, and enable this.
|
|
||||||
// if (suggestion.remoteViews != null) {
|
holder.icon.setImageDrawable(mCache.getIcon(suggestion.getIcon()));
|
||||||
// final ViewGroup itemView = (ViewGroup) holder.itemView;
|
holder.title.setText(suggestion.getTitle());
|
||||||
// itemView.removeAllViews();
|
final CharSequence summary = suggestion.getSummary();
|
||||||
// itemView.addView(suggestion.remoteViews.apply(itemView.getContext(),
|
if (!TextUtils.isEmpty(summary)) {
|
||||||
// itemView));
|
holder.summary.setText(summary);
|
||||||
// } else
|
holder.summary.setVisibility(View.VISIBLE);
|
||||||
{
|
} else {
|
||||||
holder.icon.setImageDrawable(mCache.getIcon(suggestion.getIcon()));
|
holder.summary.setVisibility(View.GONE);
|
||||||
holder.title.setText(suggestion.getTitle());
|
|
||||||
final CharSequence summary = suggestion.getSummary();
|
|
||||||
if (!TextUtils.isEmpty(summary)) {
|
|
||||||
holder.summary.setText(summary);
|
|
||||||
holder.summary.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
holder.summary.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
final View divider = holder.itemView.findViewById(R.id.divider);
|
final View divider = holder.itemView.findViewById(R.id.divider);
|
||||||
if (divider != null) {
|
if (divider != null) {
|
||||||
@@ -116,8 +108,6 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
|
|||||||
final View primaryAction = holder.itemView.findViewById(android.R.id.primary);
|
final View primaryAction = holder.itemView.findViewById(android.R.id.primary);
|
||||||
if (primaryAction != null) {
|
if (primaryAction != null) {
|
||||||
clickHandler = primaryAction;
|
clickHandler = primaryAction;
|
||||||
// set the item view to disabled to remove any touch effects
|
|
||||||
holder.itemView.setEnabled(false);
|
|
||||||
}
|
}
|
||||||
clickHandler.setOnClickListener(v -> {
|
clickHandler.setOnClickListener(v -> {
|
||||||
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_SETTINGS_SUGGESTION, id);
|
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_SETTINGS_SUGGESTION, id);
|
||||||
@@ -198,13 +188,12 @@ public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder>
|
|||||||
? R.layout.suggestion_tile_remote_container
|
? R.layout.suggestion_tile_remote_container
|
||||||
: R.layout.suggestion_tile;
|
: R.layout.suggestion_tile;
|
||||||
} else {
|
} else {
|
||||||
|
final Suggestion suggestion = getSuggestionsV2(position);
|
||||||
return R.layout.suggestion_tile;
|
if ((suggestion.getFlags() & Suggestion.FLAG_HAS_BUTTON) != 0) {
|
||||||
// TODO: Add remote view field in Suggestion, and enable this.
|
return R.layout.suggestion_tile_with_button;
|
||||||
// Suggestion suggestion = getSuggestionsV2(position);
|
} else {
|
||||||
// return suggestion.remoteViews != null
|
return R.layout.suggestion_tile;
|
||||||
// ? R.layout.suggestion_tile_remote_container
|
}
|
||||||
// : R.layout.suggestion_tile;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -89,7 +89,7 @@ public class SuggestionDismissController extends ItemTouchHelper.SimpleCallback
|
|||||||
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||||
final int layoutId = viewHolder.getItemViewType();
|
final int layoutId = viewHolder.getItemViewType();
|
||||||
if (layoutId == R.layout.suggestion_tile
|
if (layoutId == R.layout.suggestion_tile
|
||||||
|| layoutId == R.layout.suggestion_tile_remote_container) {
|
|| layoutId == R.layout.suggestion_tile_with_button) {
|
||||||
// Only return swipe direction for suggestion tiles. All other types are not swipeable.
|
// Only return swipe direction for suggestion tiles. All other types are not swipeable.
|
||||||
return super.getSwipeDirs(recyclerView, viewHolder);
|
return super.getSwipeDirs(recyclerView, viewHolder);
|
||||||
}
|
}
|
||||||
|
@@ -18,15 +18,17 @@ package android.service.settings.suggestions;
|
|||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.Parcel;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.widget.RemoteViews;
|
|
||||||
|
|
||||||
public class Suggestion {
|
public class Suggestion {
|
||||||
|
|
||||||
|
public static final int FLAG_HAS_BUTTON = 1 << 0;
|
||||||
|
|
||||||
private final String mId;
|
private final String mId;
|
||||||
private final CharSequence mTitle;
|
private final CharSequence mTitle;
|
||||||
private final CharSequence mSummary;
|
private final CharSequence mSummary;
|
||||||
private final Icon mIcon;
|
private final Icon mIcon;
|
||||||
|
private final int mFlags;
|
||||||
private final PendingIntent mPendingIntent;
|
private final PendingIntent mPendingIntent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,6 +59,10 @@ public class Suggestion {
|
|||||||
return mIcon;
|
return mIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getFlags() {
|
||||||
|
return mFlags;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Intent to launch when the suggestion is activated.
|
* The Intent to launch when the suggestion is activated.
|
||||||
*/
|
*/
|
||||||
@@ -70,13 +76,16 @@ public class Suggestion {
|
|||||||
mIcon = builder.mIcon;
|
mIcon = builder.mIcon;
|
||||||
mPendingIntent = builder.mPendingIntent;
|
mPendingIntent = builder.mPendingIntent;
|
||||||
mId = builder.mId;
|
mId = builder.mId;
|
||||||
|
mFlags = builder.mFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder class for {@link Suggestion}.
|
* Builder class for {@link Suggestion}.
|
||||||
*/
|
*/
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
private final String mId;
|
private final String mId;
|
||||||
|
private int mFlags;
|
||||||
private CharSequence mTitle;
|
private CharSequence mTitle;
|
||||||
private CharSequence mSummary;
|
private CharSequence mSummary;
|
||||||
private Icon mIcon;
|
private Icon mIcon;
|
||||||
@@ -114,6 +123,11 @@ public class Suggestion {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder setFlags(int flags) {
|
||||||
|
mFlags = flags;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets suggestion intent
|
* Sets suggestion intent
|
||||||
*/
|
*/
|
||||||
|
@@ -143,6 +143,21 @@ public class SuggestionAdapterTest {
|
|||||||
.isEqualTo(R.layout.suggestion_tile);
|
.isEqualTo(R.layout.suggestion_tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getItemType_hasButton_shouldReturnSuggestionWithButton() {
|
||||||
|
final List<Suggestion> suggestions = new ArrayList<>();
|
||||||
|
suggestions.add(new Suggestion.Builder("id")
|
||||||
|
.setFlags(Suggestion.FLAG_HAS_BUTTON)
|
||||||
|
.setTitle("123")
|
||||||
|
.setSummary("456")
|
||||||
|
.build());
|
||||||
|
mSuggestionAdapter = new SuggestionAdapter(mContext, null /* suggestions */,
|
||||||
|
suggestions, new ArrayList<>());
|
||||||
|
|
||||||
|
assertThat(mSuggestionAdapter.getItemViewType(0))
|
||||||
|
.isEqualTo(R.layout.suggestion_tile_with_button);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onBindViewHolder_shouldSetListener() {
|
public void onBindViewHolder_shouldSetListener() {
|
||||||
final View view = spy(LayoutInflater.from(mContext).inflate(
|
final View view = spy(LayoutInflater.from(mContext).inflate(
|
||||||
|
@@ -92,7 +92,7 @@ public class SuggestionDismissControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getSwipeDirs_isSuggestionTileCard_shouldReturnDirection() {
|
public void getSwipeDirs_isSuggestionTileCard_shouldReturnDirection() {
|
||||||
final RecyclerView.ViewHolder vh = mock(RecyclerView.ViewHolder.class);
|
final RecyclerView.ViewHolder vh = mock(RecyclerView.ViewHolder.class);
|
||||||
when(vh.getItemViewType()).thenReturn(R.layout.suggestion_tile_remote_container);
|
when(vh.getItemViewType()).thenReturn(R.layout.suggestion_tile_with_button);
|
||||||
|
|
||||||
assertThat(mController.getSwipeDirs(mRecyclerView, vh))
|
assertThat(mController.getSwipeDirs(mRecyclerView, vh))
|
||||||
.isEqualTo(ItemTouchHelper.START | ItemTouchHelper.END);
|
.isEqualTo(ItemTouchHelper.START | ItemTouchHelper.END);
|
||||||
|
Reference in New Issue
Block a user