Loading suggestions via legacy SuggestionService sometimes
When legacy_suggestion flag is turned on, load Suggestions from SuggestionService instead of contextual homepage, because contextual homepage infrastructure might not be availble on all devices. Bug: 118842099 Test: robo Change-Id: I91710c005e11be5a9b3dd39ceff670106e7f80c3
This commit is contained in:
@@ -32,8 +32,8 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="@dimen/suggestion_card_icon_size"
|
||||
android:layout_height="@dimen/suggestion_card_icon_size"
|
||||
android:layout_width="@dimen/homepage_card_icon_size"
|
||||
android:layout_height="@dimen/homepage_card_icon_size"
|
||||
android:tint="?android:attr/colorAccent"/>
|
||||
|
||||
<LinearLayout
|
||||
|
@@ -32,8 +32,8 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="@dimen/suggestion_card_icon_size"
|
||||
android:layout_height="@dimen/suggestion_card_icon_size"
|
||||
android:layout_width="@dimen/homepage_card_icon_size"
|
||||
android:layout_height="@dimen/homepage_card_icon_size"
|
||||
android:tint="?android:attr/colorAccent"/>
|
||||
|
||||
<TextView
|
||||
|
70
res/layout/homepage_suggestion_tile.xml
Normal file
70
res/layout/homepage_suggestion_tile.xml
Normal file
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 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.
|
||||
-->
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/suggestion_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/ContextualCardStyle">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="112dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="@dimen/homepage_card_icon_size"
|
||||
android:layout_height="@dimen/homepage_card_icon_size"
|
||||
style="@style/SuggestionCardIcon"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="6dp"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/SuggestionCardText"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/TextAppearance.SuggestionTitle"
|
||||
android:fadingEdge="horizontal"/>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/SuggestionCardText"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/TextAppearance.SuggestionSummary"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
@@ -134,6 +134,12 @@
|
||||
have distinct intensity levels -->
|
||||
<bool name="config_vibration_supports_multiple_intensities">false</bool>
|
||||
|
||||
<!--
|
||||
Whether or not the homepage should be powered by legacy suggestion (versus contextual cards)
|
||||
Default to true as not all devices support contextual cards.
|
||||
-->
|
||||
<bool name="config_use_legacy_suggestion">true</bool>
|
||||
|
||||
<!-- Whether or not TopLevelSettings should force rounded icon for injected tiles -->
|
||||
<bool name="config_force_rounded_icon_TopLevelSettings">true</bool>
|
||||
|
||||
|
@@ -303,17 +303,6 @@
|
||||
<dimen name="suggestion_condition_header_padding_expanded">5dp</dimen>
|
||||
<dimen name="condition_header_height">36dp</dimen>
|
||||
|
||||
<!-- Suggestion cards size and padding -->
|
||||
<dimen name="suggestion_card_icon_size">24dp</dimen>
|
||||
<dimen name="suggestion_card_outer_margin">14dp</dimen>
|
||||
<dimen name="suggestion_card_inner_margin">12dp</dimen>
|
||||
<dimen name="suggestion_card_padding_bottom_one_card">16dp</dimen>
|
||||
<dimen name="suggestion_card_corner_radius">2dp</dimen>
|
||||
<dimen name="suggestion_card_icon_side_margin">12dp</dimen>
|
||||
<dimen name="suggestion_card_button_side_margin">8dp</dimen>
|
||||
<dimen name="suggestion_card_button_top_margin">16dp</dimen>
|
||||
<dimen name="suggestion_card_button_bottom_margin">18dp</dimen>
|
||||
|
||||
<!-- Condition cards size and padding -->
|
||||
<dimen name="condition_card_elevation">2dp</dimen>
|
||||
|
||||
@@ -331,6 +320,7 @@
|
||||
<dimen name="homepage_bottombar_fab_cradle">68dp</dimen>
|
||||
|
||||
<!-- Homepage cards size and padding -->
|
||||
<dimen name="homepage_card_icon_size">24dp</dimen>
|
||||
<dimen name="homepage_card_corner_radius">8dp</dimen>
|
||||
<dimen name="homepage_card_elevation">2dp</dimen>
|
||||
<dimen name="homepage_card_vertical_margin">4dp</dimen>
|
||||
|
@@ -350,16 +350,8 @@
|
||||
<style name="SuggestionCardIcon">
|
||||
<item name="android:layout_centerHorizontal">false</item>
|
||||
<item name="android:layout_alignParentStart">true</item>
|
||||
<item name="android:layout_marginStart">@dimen/suggestion_card_icon_side_margin</item>
|
||||
<item name="android:layout_marginEnd">@dimen/suggestion_card_icon_side_margin</item>
|
||||
</style>
|
||||
|
||||
<style name="SuggestionCardButton">
|
||||
<item name="android:layout_gravity">start</item>
|
||||
<item name="android:layout_marginStart">@dimen/suggestion_card_button_side_margin</item>
|
||||
<item name="android:layout_marginEnd">@dimen/suggestion_card_button_side_margin</item>
|
||||
<item name="android:layout_marginTop">@dimen/suggestion_card_button_top_margin</item>
|
||||
<item name="android:layout_marginBottom">@dimen/suggestion_card_button_bottom_margin</item>
|
||||
<item name="android:layout_marginStart">12dp</item>
|
||||
<item name="android:layout_marginEnd">12dp</item>
|
||||
</style>
|
||||
|
||||
<style name="FingerprintLayoutTheme">
|
||||
|
@@ -33,12 +33,12 @@ public class ContextualCard {
|
||||
/**
|
||||
* Flags indicating the type of the ContextualCard.
|
||||
*/
|
||||
@IntDef({CardType.DEFAULT, CardType.SLICE, CardType.SUGGESTION, CardType.CONDITIONAL})
|
||||
@IntDef({CardType.DEFAULT, CardType.SLICE, CardType.LEGACY_SUGGESTION, CardType.CONDITIONAL})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface CardType {
|
||||
int DEFAULT = 0;
|
||||
int SLICE = 1;
|
||||
int SUGGESTION = 2;
|
||||
int LEGACY_SUGGESTION = 2;
|
||||
int CONDITIONAL = 3;
|
||||
}
|
||||
|
||||
|
@@ -18,11 +18,16 @@ package com.android.settings.homepage.contextualcards;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.homepage.contextualcards.ContextualCard.CardType;
|
||||
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardController;
|
||||
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
|
||||
import com.android.settings.homepage.contextualcards.legacysuggestion
|
||||
.LegacySuggestionContextualCardController;
|
||||
import com.android.settings.homepage.contextualcards.legacysuggestion
|
||||
.LegacySuggestionContextualCardRenderer;
|
||||
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardController;
|
||||
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;
|
||||
|
||||
@@ -34,6 +39,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class ContextualCardLookupTable {
|
||||
private static final String TAG = "ContextualCardLookup";
|
||||
|
||||
static class ControllerRendererMapping implements Comparable<ControllerRendererMapping> {
|
||||
@CardType
|
||||
final int mCardType;
|
||||
@@ -41,7 +47,7 @@ public class ContextualCardLookupTable {
|
||||
final Class<? extends ContextualCardController> mControllerClass;
|
||||
final Class<? extends ContextualCardRenderer> mRendererClass;
|
||||
|
||||
ControllerRendererMapping(@CardType int cardType, int viewType,
|
||||
ControllerRendererMapping(@CardType int cardType, @LayoutRes int viewType,
|
||||
Class<? extends ContextualCardController> controllerClass,
|
||||
Class<? extends ContextualCardRenderer> rendererClass) {
|
||||
mCardType = cardType;
|
||||
@@ -69,6 +75,10 @@ public class ContextualCardLookupTable {
|
||||
ConditionContextualCardRenderer.FULL_WIDTH_VIEW_TYPE,
|
||||
ConditionContextualCardController.class,
|
||||
ConditionContextualCardRenderer.class));
|
||||
add(new ControllerRendererMapping(CardType.LEGACY_SUGGESTION,
|
||||
LegacySuggestionContextualCardRenderer.VIEW_TYPE,
|
||||
LegacySuggestionContextualCardController.class,
|
||||
LegacySuggestionContextualCardRenderer.class));
|
||||
add(new ControllerRendererMapping(CardType.SLICE,
|
||||
SliceContextualCardRenderer.VIEW_TYPE,
|
||||
SliceContextualCardController.class,
|
||||
|
@@ -16,7 +16,8 @@
|
||||
|
||||
package com.android.settings.homepage.contextualcards;
|
||||
|
||||
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
|
||||
import static com.android.settings.homepage.contextualcards.ContextualCardLoader
|
||||
.CARD_CONTENT_LOADER_ID;
|
||||
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
|
||||
@@ -57,8 +58,8 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
|
||||
private static final String TAG = "ContextualCardManager";
|
||||
//The list for Settings Custom Card
|
||||
@ContextualCard.CardType
|
||||
private static final int[] SETTINGS_CARDS = {ContextualCard.CardType.CONDITIONAL};
|
||||
private static final int[] SETTINGS_CARDS =
|
||||
{ContextualCard.CardType.CONDITIONAL, ContextualCard.CardType.LEGACY_SUGGESTION};
|
||||
|
||||
private final Context mContext;
|
||||
private final ControllerRendererPool mControllerRendererPool;
|
||||
@@ -68,14 +69,14 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
|
||||
private ContextualCardUpdateListener mListener;
|
||||
|
||||
public ContextualCardManager(Context context, @NonNull Lifecycle lifecycle) {
|
||||
public ContextualCardManager(Context context, Lifecycle lifecycle) {
|
||||
mContext = context;
|
||||
mLifecycle = lifecycle;
|
||||
mContextualCards = new ArrayList<>();
|
||||
mLifecycleObservers = new ArrayList<>();
|
||||
mControllerRendererPool = new ControllerRendererPool();
|
||||
//for data provided by Settings
|
||||
for (int cardType : SETTINGS_CARDS) {
|
||||
for (@ContextualCard.CardType int cardType : SETTINGS_CARDS) {
|
||||
setupController(cardType);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +95,7 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
}
|
||||
}
|
||||
|
||||
private void setupController(int cardType) {
|
||||
private void setupController(@ContextualCard.CardType int cardType) {
|
||||
final ContextualCardController controller = mControllerRendererPool.getController(mContext,
|
||||
cardType);
|
||||
if (controller == null) {
|
||||
|
@@ -18,6 +18,7 @@ package com.android.settings.homepage.contextualcards;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
@@ -28,6 +29,7 @@ public interface ContextualCardRenderer {
|
||||
/**
|
||||
* The layout type of the renderer.
|
||||
*/
|
||||
@LayoutRes
|
||||
int getViewType(boolean isHalfWidth);
|
||||
|
||||
/**
|
||||
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.settings.homepage.contextualcards;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -31,5 +33,6 @@ public interface ContextualCardUpdateListener {
|
||||
* null, which means all cards from corresponding {@link
|
||||
* ContextualCard.CardType} are removed.
|
||||
*/
|
||||
@MainThread
|
||||
void onContextualCardUpdated(Map<Integer, List<ContextualCard>> cards);
|
||||
}
|
@@ -26,6 +26,10 @@ import androidx.lifecycle.LifecycleOwner;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardController;
|
||||
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
|
||||
import com.android.settings.homepage.contextualcards.legacysuggestion
|
||||
.LegacySuggestionContextualCardController;
|
||||
import com.android.settings.homepage.contextualcards.legacysuggestion
|
||||
.LegacySuggestionContextualCardRenderer;
|
||||
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardController;
|
||||
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;
|
||||
|
||||
@@ -111,6 +115,8 @@ public class ControllerRendererPool {
|
||||
return new ConditionContextualCardController(context);
|
||||
} else if (SliceContextualCardController.class == clz) {
|
||||
return new SliceContextualCardController();
|
||||
} else if (LegacySuggestionContextualCardController.class == clz) {
|
||||
return new LegacySuggestionContextualCardController(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -118,9 +124,12 @@ public class ControllerRendererPool {
|
||||
private ContextualCardRenderer createCardRenderer(Context context,
|
||||
LifecycleOwner lifecycleOwner, Class<?> clz) {
|
||||
if (ConditionContextualCardRenderer.class == clz) {
|
||||
return new ConditionContextualCardRenderer(context, this /*controllerRendererPool*/);
|
||||
return new ConditionContextualCardRenderer(context, this /* controllerRendererPool */);
|
||||
} else if (SliceContextualCardRenderer.class == clz) {
|
||||
return new SliceContextualCardRenderer(context, lifecycleOwner);
|
||||
} else if (LegacySuggestionContextualCardRenderer.class == clz) {
|
||||
return new LegacySuggestionContextualCardRenderer(context,
|
||||
this /* controllerRendererPool */);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
@@ -37,7 +38,9 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
* Card renderer for {@link ConditionalContextualCard}.
|
||||
*/
|
||||
public class ConditionContextualCardRenderer implements ContextualCardRenderer {
|
||||
@LayoutRes
|
||||
public static final int HALF_WIDTH_VIEW_TYPE = R.layout.homepage_condition_half_tile;
|
||||
@LayoutRes
|
||||
public static final int FULL_WIDTH_VIEW_TYPE = R.layout.homepage_condition_full_tile;
|
||||
|
||||
private final Context mContext;
|
||||
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
package com.android.settings.homepage.contextualcards.legacysuggestion;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
|
||||
import com.android.settings.homepage.contextualcards.ContextualCard;
|
||||
|
||||
public class LegacySuggestionContextualCard extends ContextualCard {
|
||||
|
||||
private final PendingIntent mPendingIntent;
|
||||
|
||||
public LegacySuggestionContextualCard(Builder builder) {
|
||||
super(builder);
|
||||
mPendingIntent = builder.mPendingIntent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCardType() {
|
||||
return CardType.LEGACY_SUGGESTION;
|
||||
}
|
||||
|
||||
public PendingIntent getPendingIntent() {
|
||||
return mPendingIntent;
|
||||
}
|
||||
|
||||
public static class Builder extends ContextualCard.Builder {
|
||||
|
||||
private PendingIntent mPendingIntent;
|
||||
|
||||
public Builder setPendingIntent(PendingIntent pendingIntent) {
|
||||
mPendingIntent = pendingIntent;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setCardType(int cardType) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot change card type for " + getClass().getName());
|
||||
}
|
||||
|
||||
public LegacySuggestionContextualCard build() {
|
||||
return new LegacySuggestionContextualCard(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
package com.android.settings.homepage.contextualcards.legacysuggestion;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.service.settings.suggestions.Suggestion;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCard;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardController;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
import com.android.settingslib.suggestions.SuggestionController;
|
||||
import com.android.settingslib.suggestions.SuggestionController.ServiceConnectionListener;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class LegacySuggestionContextualCardController implements ContextualCardController,
|
||||
LifecycleObserver, OnStart, OnStop, ServiceConnectionListener {
|
||||
|
||||
private static final String TAG = "LegacySuggestCardCtrl";
|
||||
|
||||
@VisibleForTesting
|
||||
SuggestionController mSuggestionController;
|
||||
|
||||
private ContextualCardUpdateListener mCardUpdateListener;
|
||||
private final Context mContext;
|
||||
|
||||
|
||||
public LegacySuggestionContextualCardController(Context context) {
|
||||
mContext = context;
|
||||
if (!mContext.getResources().getBoolean(R.bool.config_use_legacy_suggestion)) {
|
||||
Log.w(TAG, "Legacy suggestion contextual card disabled, skipping.");
|
||||
return;
|
||||
}
|
||||
final ComponentName suggestionServiceComponent =
|
||||
FeatureFactory.getFactory(mContext).getSuggestionFeatureProvider(mContext)
|
||||
.getSuggestionServiceComponent();
|
||||
mSuggestionController = new SuggestionController(
|
||||
mContext, suggestionServiceComponent, this /* listener */);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCardType() {
|
||||
return ContextualCard.CardType.LEGACY_SUGGESTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrimaryClick(ContextualCard card) {
|
||||
try {
|
||||
((LegacySuggestionContextualCard) card).getPendingIntent().send();
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
Log.w(TAG, "Failed to start suggestion " + card.getTitleText());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionClick(ContextualCard card) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCardUpdateListener(ContextualCardUpdateListener listener) {
|
||||
mCardUpdateListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (mSuggestionController == null) {
|
||||
return;
|
||||
}
|
||||
mSuggestionController.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (mSuggestionController == null) {
|
||||
return;
|
||||
}
|
||||
mSuggestionController.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
loadSuggestions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected() {
|
||||
|
||||
}
|
||||
|
||||
private void loadSuggestions() {
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
if (mSuggestionController == null || mCardUpdateListener == null) {
|
||||
return;
|
||||
}
|
||||
final List<Suggestion> suggestions = mSuggestionController.getSuggestions();
|
||||
Log.d(TAG, "Loaded suggests: "
|
||||
+ suggestions == null ? "null" : String.valueOf(suggestions.size()));
|
||||
|
||||
final List<ContextualCard> cards = new ArrayList<>();
|
||||
if (suggestions != null) {
|
||||
// Convert suggestion to ContextualCard
|
||||
for (Suggestion suggestion : suggestions) {
|
||||
final LegacySuggestionContextualCard.Builder cardBuilder =
|
||||
new LegacySuggestionContextualCard.Builder();
|
||||
if (suggestion.getIcon() != null) {
|
||||
cardBuilder.setIconDrawable(suggestion.getIcon().loadDrawable(mContext));
|
||||
}
|
||||
cardBuilder
|
||||
.setPendingIntent(suggestion.getPendingIntent())
|
||||
.setName(suggestion.getId())
|
||||
.setTitleText(suggestion.getTitle().toString())
|
||||
.setSummaryText(suggestion.getSummary().toString());
|
||||
|
||||
cards.add(cardBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
// Update adapter
|
||||
final Map<Integer, List<ContextualCard>> suggestionCards = new ArrayMap<>();
|
||||
suggestionCards.put(ContextualCard.CardType.LEGACY_SUGGESTION, cards);
|
||||
ThreadUtils.postOnMainThread(
|
||||
() -> mCardUpdateListener.onContextualCardUpdated(suggestionCards));
|
||||
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
package com.android.settings.homepage.contextualcards.legacysuggestion;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCard;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
|
||||
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
|
||||
|
||||
public class LegacySuggestionContextualCardRenderer implements ContextualCardRenderer {
|
||||
|
||||
@LayoutRes
|
||||
public static final int VIEW_TYPE = R.layout.homepage_suggestion_tile;
|
||||
|
||||
private final Context mContext;
|
||||
private final ControllerRendererPool mControllerRendererPool;
|
||||
|
||||
public LegacySuggestionContextualCardRenderer(Context context,
|
||||
ControllerRendererPool controllerRendererPool) {
|
||||
mContext = context;
|
||||
mControllerRendererPool = controllerRendererPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType(boolean isHalfWidth) {
|
||||
return VIEW_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder createViewHolder(View view) {
|
||||
return new LegacySuggestionViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(RecyclerView.ViewHolder holder, ContextualCard card) {
|
||||
final LegacySuggestionViewHolder vh = (LegacySuggestionViewHolder) holder;
|
||||
vh.icon.setImageDrawable(card.getIconDrawable());
|
||||
vh.title.setText(card.getTitleText());
|
||||
vh.summary.setText(card.getSummaryText());
|
||||
vh.itemView.setOnClickListener(v ->
|
||||
mControllerRendererPool.getController(mContext,
|
||||
card.getCardType()).onPrimaryClick(card));
|
||||
}
|
||||
|
||||
private static class LegacySuggestionViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public final ImageView icon;
|
||||
public final TextView title;
|
||||
public final TextView summary;
|
||||
|
||||
public LegacySuggestionViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
icon = itemView.findViewById(android.R.id.icon);
|
||||
title = itemView.findViewById(android.R.id.title);
|
||||
summary = itemView.findViewById(android.R.id.summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -62,6 +62,7 @@
|
||||
<bool name="config_show_wifi_mac_address">false</bool>
|
||||
<bool name="config_disable_uninstall_update">true</bool>
|
||||
<bool name="config_show_device_name">false</bool>
|
||||
<bool name="config_use_legacy_suggestion">false</bool>
|
||||
|
||||
<!-- Whether or not extra preview panels should be used for screen zoom setting. -->
|
||||
<bool name="config_enable_extra_screen_zoom_preview">false</bool>
|
||||
|
@@ -30,7 +30,7 @@ public class ConditionalContextualCardTest {
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void newInstance_changeCardType_shouldCrash() {
|
||||
new ConditionalContextualCard.Builder()
|
||||
.setCardType(ContextualCard.CardType.SUGGESTION)
|
||||
.setCardType(ContextualCard.CardType.LEGACY_SUGGESTION)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
package com.android.settings.homepage.contextualcards.legacysuggestion;
|
||||
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
||||
import com.android.settingslib.suggestions.SuggestionController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(shadows = ShadowThreadUtils.class)
|
||||
public class LegacySuggestionContextualCardControllerTest {
|
||||
|
||||
@Mock
|
||||
private SuggestionController mSuggestionController;
|
||||
@Mock
|
||||
private ContextualCardUpdateListener mCardUpdateListener;
|
||||
|
||||
private Context mContext;
|
||||
private LegacySuggestionContextualCardController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
FakeFeatureFactory.setupForTest();
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new LegacySuggestionContextualCardController(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void init_configOn_shouldCreateSuggestionController() {
|
||||
final LegacySuggestionContextualCardController controller =
|
||||
new LegacySuggestionContextualCardController(mContext);
|
||||
assertThat(controller.mSuggestionController).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void init_configOff_shouldNotCreateSuggestionController() {
|
||||
final LegacySuggestionContextualCardController controller =
|
||||
new LegacySuggestionContextualCardController(mContext);
|
||||
|
||||
assertThat(controller.mSuggestionController).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void goThroughLifecycle_hasSuggestionController_shouldStartStopController() {
|
||||
mController.mSuggestionController = mSuggestionController;
|
||||
mController.onStart();
|
||||
verify(mSuggestionController).start();
|
||||
|
||||
mController.onStop();
|
||||
verify(mSuggestionController).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onServiceConnected_shouldLoadSuggestion() {
|
||||
mController.mSuggestionController = mSuggestionController;
|
||||
mController.setCardUpdateListener(mCardUpdateListener);
|
||||
mController.onServiceConnected();
|
||||
|
||||
verify(mSuggestionController).getSuggestions();
|
||||
}
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
package com.android.settings.homepage.contextualcards.legacysuggestion;
|
||||
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCard;
|
||||
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class LegacySuggestionContextualCardRendererTest {
|
||||
@Mock
|
||||
private ControllerRendererPool mControllerRendererPool;
|
||||
@Mock
|
||||
private LegacySuggestionContextualCardController mController;
|
||||
private Context mContext;
|
||||
private LegacySuggestionContextualCardRenderer mRenderer;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mRenderer = new LegacySuggestionContextualCardRenderer(mContext, mControllerRendererPool);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindView_shouldSetListener() {
|
||||
final int viewType = mRenderer.getViewType(true /* isHalfWidth */);
|
||||
final RecyclerView recyclerView = new RecyclerView(mContext);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
|
||||
final View card = LayoutInflater.from(mContext).inflate(viewType, recyclerView, false);
|
||||
final RecyclerView.ViewHolder viewHolder = mRenderer.createViewHolder(card);
|
||||
|
||||
when(mControllerRendererPool.getController(mContext,
|
||||
ContextualCard.CardType.LEGACY_SUGGESTION)).thenReturn(mController);
|
||||
|
||||
mRenderer.bindView(viewHolder, buildContextualCard());
|
||||
|
||||
assertThat(card).isNotNull();
|
||||
assertThat(card.hasOnClickListeners()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void viewClick_shouldInvokeControllerPrimaryClick() {
|
||||
final int viewType = mRenderer.getViewType(true /* isHalfWidth */);
|
||||
final RecyclerView recyclerView = new RecyclerView(mContext);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
|
||||
final View card = LayoutInflater.from(mContext).inflate(viewType, recyclerView, false);
|
||||
final RecyclerView.ViewHolder viewHolder = mRenderer.createViewHolder(card);
|
||||
when(mControllerRendererPool.getController(mContext,
|
||||
ContextualCard.CardType.LEGACY_SUGGESTION)).thenReturn(mController);
|
||||
|
||||
mRenderer.bindView(viewHolder, buildContextualCard());
|
||||
|
||||
assertThat(card).isNotNull();
|
||||
card.performClick();
|
||||
|
||||
verify(mController).onPrimaryClick(any(ContextualCard.class));
|
||||
}
|
||||
|
||||
private ContextualCard buildContextualCard() {
|
||||
return new LegacySuggestionContextualCard.Builder()
|
||||
.setName("test_name")
|
||||
.setTitleText("test_title")
|
||||
.setSummaryText("test_summary")
|
||||
.setIconDrawable(mContext.getDrawable(R.drawable.ic_do_not_disturb_on_24dp))
|
||||
.build();
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
package com.android.settings.homepage.contextualcards.legacysuggestion;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
|
||||
import com.android.settings.homepage.contextualcards.ContextualCard;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class LegacySuggestionContextualCardTest {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void newInstance_changeCardType_shouldCrash() {
|
||||
new LegacySuggestionContextualCard.Builder()
|
||||
.setCardType(ContextualCard.CardType.CONDITIONAL)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCardType_shouldAlwaysBeSuggestionType() {
|
||||
assertThat(new LegacySuggestionContextualCard.Builder().build().getCardType())
|
||||
.isEqualTo(ContextualCard.CardType.LEGACY_SUGGESTION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void build_shouldSetPendingIntent() {
|
||||
assertThat(new LegacySuggestionContextualCard.Builder()
|
||||
.setPendingIntent(mock(PendingIntent.class))
|
||||
.build()
|
||||
.getPendingIntent()).isNotNull();
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user