1 /*
2  * Copyright (C) 2015 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 
17 package com.android.packageinstaller.permission.ui.wear.settings;
18 
19 import android.content.Context;
20 import android.support.wearable.view.CircledImageView;
21 import android.support.wearable.view.WearableListView;
22 import android.util.Log;
23 import android.view.Gravity;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.widget.FrameLayout;
27 import android.widget.TextView;
28 
29 import com.android.packageinstaller.R;
30 
31 import java.util.ArrayList;
32 
33 /**
34  * Common adapter for settings views. Maintains a list of 'Settings', consisting of a name,
35  * icon and optional activity-specific data.
36  */
37 public class SettingsAdapter<T> extends WearableListView.Adapter {
38     private static final String TAG = "SettingsAdapter";
39     private final Context mContext;
40 
41     public static final class Setting<S> {
42         public static final int ID_INVALID = -1;
43 
44         public final int id;
45         public int nameResourceId;
46         public CharSequence name;
47         public int iconResource;
48         public boolean inProgress;
49         public S data;
50 
Setting(CharSequence name, int iconResource, S data)51         public Setting(CharSequence name, int iconResource, S data) {
52             this(name, iconResource, data, ID_INVALID);
53         }
54 
Setting(CharSequence name, int iconResource, S data, int id)55         public Setting(CharSequence name, int iconResource, S data, int id) {
56             this.name = name;
57             this.iconResource = iconResource;
58             this.data = data;
59             this.inProgress = false;
60             this.id = id;
61         }
62 
Setting(int nameResource, int iconResource, S data, int id)63         public Setting(int nameResource, int iconResource, S data, int id) {
64             this.nameResourceId = nameResource;
65             this.iconResource = iconResource;
66             this.data = data;
67             this.inProgress = false;
68             this.id = id;
69         }
70 
Setting(int nameResource, int iconResource, int id)71         public Setting(int nameResource, int iconResource, int id) {
72             this.nameResourceId = nameResource;
73             this.iconResource = iconResource;
74             this.data = null;
75             this.inProgress = false;
76             this.id = id;
77         }
78 
Setting(CharSequence name, int iconResource, int id)79         public Setting(CharSequence name, int iconResource, int id) {
80             this(name, iconResource, null, id);
81         }
82 
83     }
84 
85     private final int mItemLayoutId;
86     private final float mDefaultCircleRadiusPercent;
87     private final float mSelectedCircleRadiusPercent;
88 
89     protected ArrayList<Setting<T>> mSettings = new ArrayList<Setting<T>>();
90 
SettingsAdapter(Context context, int itemLayoutId)91     public SettingsAdapter(Context context, int itemLayoutId) {
92         mContext = context;
93         mItemLayoutId = itemLayoutId;
94         mDefaultCircleRadiusPercent = context.getResources().getFraction(
95                 R.dimen.default_settings_circle_radius_percent, 1, 1);
96         mSelectedCircleRadiusPercent = context.getResources().getFraction(
97                 R.dimen.selected_settings_circle_radius_percent, 1, 1);
98     }
99 
100     @Override
onCreateViewHolder(ViewGroup parent, int viewType)101     public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
102         return new SettingsItemHolder(new SettingsItem(parent.getContext()));
103     }
104 
105     @Override
onBindViewHolder(WearableListView.ViewHolder holder, int position)106     public void onBindViewHolder(WearableListView.ViewHolder holder, int position) {
107         Setting<T> setting = mSettings.get(position);
108         if (setting.iconResource == -1) {
109             ((SettingsItemHolder) holder).imageView.setVisibility(View.GONE);
110         } else {
111             ((SettingsItemHolder) holder).imageView.setVisibility(View.VISIBLE);
112             ((SettingsItemHolder) holder).imageView.setImageResource(
113                     mSettings.get(position).iconResource);
114         }
115         Log.d(TAG, "onBindViewHolder " + setting.name + " " + setting.id + " " + setting
116                 .nameResourceId);
117         if (setting.name == null && setting.nameResourceId != 0) {
118             setting.name = mContext.getString(setting.nameResourceId);
119         }
120         ((SettingsItemHolder) holder).textView.setText(setting.name);
121     }
122 
123     @Override
getItemCount()124     public int getItemCount() {
125         return mSettings.size();
126     }
127 
addSetting(CharSequence name, int iconResource)128     public void addSetting(CharSequence name, int iconResource) {
129         addSetting(name, iconResource, null);
130     }
131 
addSetting(CharSequence name, int iconResource, T intent)132     public void addSetting(CharSequence name, int iconResource, T intent) {
133         addSetting(mSettings.size(), name, iconResource, intent);
134     }
135 
addSetting(int index, CharSequence name, int iconResource, T intent)136     public void addSetting(int index, CharSequence name, int iconResource, T intent) {
137         addSetting(Setting.ID_INVALID, index, name, iconResource, intent);
138     }
139 
addSetting(int id, int index, CharSequence name, int iconResource, T intent)140     public void addSetting(int id, int index, CharSequence name, int iconResource, T intent) {
141         mSettings.add(index, new Setting<T>(name, iconResource, intent, id));
142         notifyItemInserted(index);
143     }
144 
addSettingDontNotify(Setting<T> setting)145     public void addSettingDontNotify(Setting<T> setting) {
146         mSettings.add(setting);
147     }
148 
addSetting(Setting<T> setting)149     public void addSetting(Setting<T> setting) {
150         mSettings.add(setting);
151         notifyItemInserted(mSettings.size() - 1);
152     }
153 
addSetting(int index, Setting<T> setting)154     public void addSetting(int index, Setting<T> setting) {
155         mSettings.add(index, setting);
156         notifyItemInserted(index);
157     }
158 
159     /**
160      * Returns the index of the setting in the adapter based on the ID supplied when it was
161      * originally added.
162      * @param id the setting's id
163      * @return index in the adapter of the setting. -1 if not found.
164      */
findSetting(int id)165     public int findSetting(int id) {
166         for (int i = mSettings.size() - 1; i >= 0; --i) {
167             Setting setting = mSettings.get(i);
168 
169             if (setting.id == id) {
170                 return i;
171             }
172         }
173 
174         return -1;
175     }
176 
177     /**
178      * Removes a setting at the given index.
179      * @param index the index of the setting to be removed
180      */
removeSetting(int index)181     public void removeSetting(int index) {
182         mSettings.remove(index);
183         notifyDataSetChanged();
184     }
185 
clearSettings()186     public void clearSettings() {
187         mSettings.clear();
188         notifyDataSetChanged();
189     }
190 
191     /**
192      * Updates a setting in place.
193      * @param index the index of the setting
194      * @param name the updated setting name
195      * @param iconResource the update setting icon
196      * @param intent the updated intent for the setting
197      */
updateSetting(int index, CharSequence name, int iconResource, T intent)198     public void updateSetting(int index, CharSequence name, int iconResource, T intent) {
199         Setting<T> setting = mSettings.get(index);
200         setting.iconResource = iconResource;
201         setting.name = name;
202         setting.data = intent;
203         notifyItemChanged(index);
204     }
205 
get(int position)206     public Setting<T> get(int position) {
207         return mSettings.get(position);
208     }
209 
210     protected static class SettingsItemHolder extends ExtendedViewHolder {
211         public final CircledImageView imageView;
212         public final TextView textView;
213 
SettingsItemHolder(View itemView)214         public SettingsItemHolder(View itemView) {
215             super(itemView);
216 
217             imageView = ((CircledImageView) itemView.findViewById(R.id.image));
218             textView = ((TextView) itemView.findViewById(R.id.text));
219         }
220     }
221 
222     protected class SettingsItem extends FrameLayout implements ExtendedOnCenterProximityListener {
223 
224         protected final CircledImageView mImage;
225         protected final TextView mText;
226 
SettingsItem(Context context)227         public SettingsItem(Context context) {
228             super(context);
229             View view = View.inflate(context, mItemLayoutId, null);
230             FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
231                     FrameLayout.LayoutParams.MATCH_PARENT,
232                     FrameLayout.LayoutParams.MATCH_PARENT);
233             params.gravity = Gravity.CENTER_VERTICAL;
234             addView(view, params);
235             mImage = (CircledImageView) findViewById(R.id.image);
236             mText = (TextView) findViewById(R.id.text);
237         }
238 
239         @Override
getProximityMinValue()240         public float getProximityMinValue() {
241             return mDefaultCircleRadiusPercent;
242         }
243 
244         @Override
getProximityMaxValue()245         public float getProximityMaxValue() {
246             return mSelectedCircleRadiusPercent;
247         }
248 
249         @Override
getCurrentProximityValue()250         public float getCurrentProximityValue() {
251             return mImage.getCircleRadiusPressedPercent();
252         }
253 
254         @Override
setScalingAnimatorValue(float value)255         public void setScalingAnimatorValue(float value) {
256             mImage.setCircleRadiusPercent(value);
257             mImage.setCircleRadiusPressedPercent(value);
258         }
259 
260         @Override
onCenterPosition(boolean animate)261         public void onCenterPosition(boolean animate) {
262             mImage.setAlpha(1f);
263             mText.setAlpha(1f);
264         }
265 
266         @Override
onNonCenterPosition(boolean animate)267         public void onNonCenterPosition(boolean animate) {
268             mImage.setAlpha(0.5f);
269             mText.setAlpha(0.5f);
270         }
271 
getTextView()272         TextView getTextView() {
273             return mText;
274         }
275     }
276 }
277