OSDN Git Service

Merge "Rename "Billing Cycle" to "App usage cycle"." into pi-dev
[android-x86/packages-apps-Settings.git] / src / com / android / settings / dashboard / suggestions / SuggestionAdapter.java
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.settings.dashboard.suggestions;
17
18 import android.app.PendingIntent;
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.graphics.Typeface;
22 import android.graphics.drawable.Drawable;
23 import android.graphics.drawable.Icon;
24 import android.os.Bundle;
25 import android.service.settings.suggestions.Suggestion;
26 import android.support.annotation.VisibleForTesting;
27 import android.support.v7.widget.RecyclerView;
28 import android.text.TextUtils;
29 import android.util.DisplayMetrics;
30 import android.util.Log;
31 import android.view.LayoutInflater;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.view.WindowManager;
35 import android.widget.ImageView;
36 import android.widget.LinearLayout;
37
38 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
39 import com.android.settings.R;
40 import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder;
41 import com.android.settings.overlay.FeatureFactory;
42 import com.android.settingslib.Utils;
43 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
44 import com.android.settingslib.core.lifecycle.Lifecycle;
45 import com.android.settingslib.core.lifecycle.LifecycleObserver;
46 import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
47 import com.android.settingslib.suggestions.SuggestionControllerMixin;
48 import com.android.settingslib.utils.IconCache;
49
50 import java.util.ArrayList;
51 import java.util.List;
52 import java.util.Objects;
53
54 public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder> implements
55     LifecycleObserver, OnSaveInstanceState {
56     public static final String TAG = "SuggestionAdapter";
57
58     private static final String STATE_SUGGESTIONS_SHOWN_LOGGED = "suggestions_shown_logged";
59     private static final String STATE_SUGGESTION_LIST = "suggestion_list";
60
61     private final Context mContext;
62     private final MetricsFeatureProvider mMetricsFeatureProvider;
63     private final IconCache mCache;
64     private final ArrayList<String> mSuggestionsShownLogged;
65     private final SuggestionFeatureProvider mSuggestionFeatureProvider;
66     private final SuggestionControllerMixin mSuggestionControllerMixin;
67     private final Callback mCallback;
68     private final CardConfig mConfig;
69
70     private List<Suggestion> mSuggestions;
71
72     public interface Callback {
73         /**
74          * Called when the close button of the suggestion card is clicked.
75          */
76         void onSuggestionClosed(Suggestion suggestion);
77     }
78
79     public SuggestionAdapter(Context context, SuggestionControllerMixin suggestionControllerMixin,
80         Bundle savedInstanceState, Callback callback, Lifecycle lifecycle) {
81         mContext = context;
82         mSuggestionControllerMixin = suggestionControllerMixin;
83         mCache = new IconCache(context);
84         final FeatureFactory factory = FeatureFactory.getFactory(context);
85         mMetricsFeatureProvider = factory.getMetricsFeatureProvider();
86         mSuggestionFeatureProvider = factory.getSuggestionFeatureProvider(context);
87         mCallback = callback;
88         if (savedInstanceState != null) {
89             mSuggestions = savedInstanceState.getParcelableArrayList(STATE_SUGGESTION_LIST);
90             mSuggestionsShownLogged = savedInstanceState.getStringArrayList(
91                 STATE_SUGGESTIONS_SHOWN_LOGGED);
92         } else {
93             mSuggestionsShownLogged = new ArrayList<>();
94         }
95
96         if (lifecycle != null) {
97             lifecycle.addObserver(this);
98         }
99         mConfig = CardConfig.get(context);
100
101         setHasStableIds(true);
102     }
103
104     @Override
105     public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
106         return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
107                 viewType, parent, false));
108     }
109
110     @Override
111     public void onBindViewHolder(DashboardItemHolder holder, int position) {
112         final Suggestion suggestion = mSuggestions.get(position);
113         final String id = suggestion.getId();
114         final int suggestionCount = mSuggestions.size();
115         if (!mSuggestionsShownLogged.contains(id)) {
116             mMetricsFeatureProvider.action(
117                     mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, id);
118             mSuggestionsShownLogged.add(id);
119         }
120         final Icon icon = suggestion.getIcon();
121         final Drawable drawable = mCache.getIcon(icon);
122         if (drawable != null) {
123             drawable.setTint(Utils.getColorAccent(mContext));
124         }
125         holder.icon.setImageDrawable(drawable);
126         holder.title.setText(suggestion.getTitle());
127         holder.title.setTypeface(Typeface.create(
128             mContext.getString(com.android.internal.R.string.config_headlineFontFamily),
129             Typeface.NORMAL));
130
131         if (suggestionCount == 1) {
132             final CharSequence summary = suggestion.getSummary();
133             if (!TextUtils.isEmpty(summary)) {
134                 holder.summary.setText(summary);
135                 holder.summary.setVisibility(View.VISIBLE);
136             } else {
137                 holder.summary.setVisibility(View.GONE);
138             }
139         } else {
140             mConfig.setCardLayout(holder, position);
141         }
142
143         final ImageView closeButton = holder.itemView.findViewById(R.id.close_button);
144         if (closeButton != null) {
145             closeButton.setOnClickListener(v -> {
146                 mSuggestionFeatureProvider.dismissSuggestion(
147                     mContext, mSuggestionControllerMixin, suggestion);
148                 if (mCallback != null) {
149                     mCallback.onSuggestionClosed(suggestion);
150                 }
151             });
152         }
153
154         View clickHandler = holder.itemView;
155         // If a view with @android:id/primary is defined, use that as the click handler
156         // instead.
157         final View primaryAction = holder.itemView.findViewById(android.R.id.primary);
158         if (primaryAction != null) {
159             clickHandler = primaryAction;
160         }
161         clickHandler.setOnClickListener(v -> {
162             mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_SETTINGS_SUGGESTION, id);
163             try {
164                 suggestion.getPendingIntent().send();
165                 mSuggestionControllerMixin.launchSuggestion(suggestion);
166             } catch (PendingIntent.CanceledException e) {
167                 Log.w(TAG, "Failed to start suggestion " + suggestion.getTitle());
168             }
169         });
170     }
171
172     @Override
173     public long getItemId(int position) {
174         return Objects.hash(mSuggestions.get(position).getId());
175     }
176
177     @Override
178     public int getItemViewType(int position) {
179         final Suggestion suggestion = getSuggestion(position);
180         if ((suggestion.getFlags() & Suggestion.FLAG_HAS_BUTTON) != 0) {
181             return R.layout.suggestion_tile_with_button;
182         }
183         if (getItemCount() == 1) {
184             return R.layout.suggestion_tile;
185         }
186         return R.layout.suggestion_tile_two_cards;
187     }
188
189     @Override
190     public int getItemCount() {
191         return mSuggestions.size();
192     }
193
194     public Suggestion getSuggestion(int position) {
195         final long itemId = getItemId(position);
196         if (mSuggestions == null) {
197             return null;
198         }
199         for (Suggestion suggestion : mSuggestions) {
200             if (Objects.hash(suggestion.getId()) == itemId) {
201                 return suggestion;
202             }
203         }
204         return null;
205     }
206
207     public void removeSuggestion(Suggestion suggestion) {
208         final int position = mSuggestions.indexOf(suggestion);
209         mSuggestions.remove(suggestion);
210         notifyItemRemoved(position);
211     }
212
213     @Override
214     public void onSaveInstanceState(Bundle outState) {
215         if (mSuggestions != null) {
216             outState.putParcelableArrayList(STATE_SUGGESTION_LIST,
217                 new ArrayList<>(mSuggestions));
218         }
219         outState.putStringArrayList(STATE_SUGGESTIONS_SHOWN_LOGGED, mSuggestionsShownLogged);
220     }
221
222     public void setSuggestions(List<Suggestion> suggestions) {
223         mSuggestions = suggestions;
224     }
225
226     public List<Suggestion> getSuggestions() {
227         return mSuggestions;
228     }
229
230     @VisibleForTesting
231     static class CardConfig {
232         // Card start/end margin
233         private final int mMarginInner;
234         private final int mMarginOuter;
235         private final WindowManager mWindowManager;
236
237         private static CardConfig sConfig;
238
239         private CardConfig(Context context) {
240             mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
241             final Resources res = context.getResources();
242             mMarginInner =
243                 res.getDimensionPixelOffset(R.dimen.suggestion_card_inner_margin);
244             mMarginOuter =
245                 res.getDimensionPixelOffset(R.dimen.suggestion_card_outer_margin);
246         }
247
248         public static CardConfig get(Context context) {
249             if (sConfig == null) {
250                 sConfig = new CardConfig(context);
251             }
252             return sConfig;
253         }
254
255         @VisibleForTesting
256         void setCardLayout(DashboardItemHolder holder, int position) {
257             final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
258                 getWidthForTwoCrads(), LinearLayout.LayoutParams.WRAP_CONTENT);
259             params.setMarginStart(position == 0 ? mMarginOuter : mMarginInner);
260             params.setMarginEnd(position != 0 ? mMarginOuter : 0);
261             holder.itemView.setLayoutParams(params);
262         }
263
264         private int getWidthForTwoCrads() {
265             return (getScreenWidth() - mMarginInner - mMarginOuter * 2) / 2;
266         }
267
268         @VisibleForTesting
269         int getScreenWidth() {
270             final DisplayMetrics metrics = new DisplayMetrics();
271             mWindowManager.getDefaultDisplay().getMetrics(metrics);
272             return metrics.widthPixels;
273         }
274     }
275
276 }