blob: 6269a717b3335fc479930b99641ef1c659bcf346 [file] [log] [blame]
Tony Mantler98608e42016-01-22 14:58:48 -08001/*
2 * Copyright (C) 2016 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 */
Tony Mantler98608e42016-01-22 14:58:48 -080016package com.android.settingslib.wifi;
17
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -070018import android.annotation.Nullable;
Tony Mantler98608e42016-01-22 14:58:48 -080019import android.content.Context;
20import android.content.pm.PackageManager;
Stephen Chen2c096592017-01-18 15:25:31 -080021import android.content.res.Resources;
22import android.content.res.TypedArray;
Tony Mantler98608e42016-01-22 14:58:48 -080023import android.graphics.drawable.Drawable;
24import android.graphics.drawable.StateListDrawable;
25import android.net.wifi.WifiConfiguration;
26import android.os.Looper;
27import android.os.UserHandle;
Tony Mantler98608e42016-01-22 14:58:48 -080028import android.text.TextUtils;
29import android.util.AttributeSet;
30import android.util.SparseArray;
jackqdyuleidce9f792017-11-02 10:38:42 -070031import android.view.View;
Stephen Chen2c096592017-01-18 15:25:31 -080032import android.widget.ImageView;
Tony Mantler98608e42016-01-22 14:58:48 -080033import android.widget.TextView;
Sundeep Ghumanbf339f52017-01-23 15:41:43 -080034
Fan Zhangf7802ea2018-08-28 15:15:19 -070035import androidx.annotation.VisibleForTesting;
36import androidx.preference.Preference;
37import androidx.preference.PreferenceViewHolder;
38
Tony Mantler98608e42016-01-22 14:58:48 -080039import com.android.settingslib.R;
Sundeep Ghumanbf339f52017-01-23 15:41:43 -080040import com.android.settingslib.TronUtils;
Sundeep Ghumanf84e0572017-01-10 13:43:03 -080041import com.android.settingslib.Utils;
Eric Schwarzenbach44268e32017-08-04 16:38:07 -070042import com.android.settingslib.wifi.AccessPoint.Speed;
Tony Mantler98608e42016-01-22 14:58:48 -080043
jackqdyuleif7846032018-01-29 14:49:37 -080044public class AccessPointPreference extends Preference {
Tony Mantler98608e42016-01-22 14:58:48 -080045
46 private static final int[] STATE_SECURED = {
47 R.attr.state_encrypted
48 };
Tony Mantler98608e42016-01-22 14:58:48 -080049
Stephen Chenaed318e2017-03-31 16:58:38 -070050 private static final int[] STATE_METERED = {
51 R.attr.state_metered
52 };
53
Fan Zhang60b850d2017-07-18 15:59:06 -070054 private static final int[] FRICTION_ATTRS = {
55 R.attr.wifi_friction
56 };
57
58 private static final int[] WIFI_CONNECTION_STRENGTH = {
59 R.string.accessibility_no_wifi,
60 R.string.accessibility_wifi_one_bar,
61 R.string.accessibility_wifi_two_bars,
62 R.string.accessibility_wifi_three_bars,
63 R.string.accessibility_wifi_signal_full
64 };
Tony Mantler98608e42016-01-22 14:58:48 -080065
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -070066 @Nullable private final StateListDrawable mFrictionSld;
Tony Mantler98608e42016-01-22 14:58:48 -080067 private final int mBadgePadding;
68 private final UserBadgeCache mBadgeCache;
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -070069 private final IconInjector mIconInjector;
Tony Mantler98608e42016-01-22 14:58:48 -080070 private TextView mTitleView;
Adam Newmanc0a82762018-03-08 16:46:16 -080071 private boolean mShowDivider;
Salvador Martinez45a15942016-08-11 17:14:11 -070072
Tony Mantler98608e42016-01-22 14:58:48 -080073 private boolean mForSavedNetworks = false;
74 private AccessPoint mAccessPoint;
75 private Drawable mBadge;
76 private int mLevel;
77 private CharSequence mContentDescription;
Salvador Martinez45a15942016-08-11 17:14:11 -070078 private int mDefaultIconResId;
Eric Schwarzenbach44268e32017-08-04 16:38:07 -070079 private int mWifiSpeed = Speed.NONE;
Tony Mantler98608e42016-01-22 14:58:48 -080080
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -070081 @Nullable
82 private static StateListDrawable getFrictionStateListDrawable(Context context) {
83 TypedArray frictionSld;
84 try {
85 frictionSld = context.getTheme().obtainStyledAttributes(FRICTION_ATTRS);
86 } catch (Resources.NotFoundException e) {
87 // Fallback for platforms that do not need friction icon resources.
88 frictionSld = null;
89 }
90 return frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
91 }
92
Tony Mantler98608e42016-01-22 14:58:48 -080093 // Used for dummy pref.
94 public AccessPointPreference(Context context, AttributeSet attrs) {
95 super(context, attrs);
Stephen Chen2c096592017-01-18 15:25:31 -080096 mFrictionSld = null;
Tony Mantler98608e42016-01-22 14:58:48 -080097 mBadgePadding = 0;
98 mBadgeCache = null;
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -070099 mIconInjector = new IconInjector(context);
Tony Mantler98608e42016-01-22 14:58:48 -0800100 }
101
102 public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
103 boolean forSavedNetworks) {
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -0700104 this(accessPoint, context, cache, 0 /* iconResId */, forSavedNetworks);
Tony Mantler98608e42016-01-22 14:58:48 -0800105 refresh();
106 }
107
Salvador Martinez45a15942016-08-11 17:14:11 -0700108 public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
109 int iconResId, boolean forSavedNetworks) {
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -0700110 this(accessPoint, context, cache, iconResId, forSavedNetworks,
111 getFrictionStateListDrawable(context), -1 /* level */, new IconInjector(context));
112 }
113
114 @VisibleForTesting
115 AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
116 int iconResId, boolean forSavedNetworks, StateListDrawable frictionSld,
117 int level, IconInjector iconInjector) {
Salvador Martinez45a15942016-08-11 17:14:11 -0700118 super(context);
Adam Newmanc0a82762018-03-08 16:46:16 -0800119 setLayoutResource(R.layout.preference_access_point);
120 setWidgetLayoutResource(getWidgetLayoutResourceId());
Salvador Martinez45a15942016-08-11 17:14:11 -0700121 mBadgeCache = cache;
122 mAccessPoint = accessPoint;
123 mForSavedNetworks = forSavedNetworks;
124 mAccessPoint.setTag(this);
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -0700125 mLevel = level;
Salvador Martinez45a15942016-08-11 17:14:11 -0700126 mDefaultIconResId = iconResId;
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -0700127 mFrictionSld = frictionSld;
128 mIconInjector = iconInjector;
Salvador Martinez45a15942016-08-11 17:14:11 -0700129 mBadgePadding = context.getResources()
130 .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
131 }
132
Adam Newmanc0a82762018-03-08 16:46:16 -0800133 protected int getWidgetLayoutResourceId() {
134 return R.layout.access_point_friction_widget;
135 }
136
Tony Mantler98608e42016-01-22 14:58:48 -0800137 public AccessPoint getAccessPoint() {
138 return mAccessPoint;
139 }
140
141 @Override
142 public void onBindViewHolder(final PreferenceViewHolder view) {
143 super.onBindViewHolder(view);
144 if (mAccessPoint == null) {
145 // Used for dummy pref.
146 return;
147 }
148 Drawable drawable = getIcon();
149 if (drawable != null) {
150 drawable.setLevel(mLevel);
151 }
152
Fan Zhangb6cec0d2017-09-05 11:02:03 -0700153 mTitleView = (TextView) view.findViewById(android.R.id.title);
Tony Mantler98608e42016-01-22 14:58:48 -0800154 if (mTitleView != null) {
155 // Attach to the end of the title view
156 mTitleView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, mBadge, null);
157 mTitleView.setCompoundDrawablePadding(mBadgePadding);
158 }
159 view.itemView.setContentDescription(mContentDescription);
Stephen Chen2c096592017-01-18 15:25:31 -0800160
Sundeep Ghuman4d8781e2017-03-15 16:03:55 -0700161 ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
162 bindFrictionImage(frictionImageView);
Adam Newmanc0a82762018-03-08 16:46:16 -0800163
164 final View divider = view.findViewById(R.id.two_target_divider);
165 divider.setVisibility(shouldShowDivider() ? View.VISIBLE : View.INVISIBLE);
166 }
167
168 public boolean shouldShowDivider() {
169 return mShowDivider;
170 }
171
172 public void setShowDivider(boolean showDivider) {
173 mShowDivider = showDivider;
174 notifyChanged();
Tony Mantler98608e42016-01-22 14:58:48 -0800175 }
176
177 protected void updateIcon(int level, Context context) {
178 if (level == -1) {
Salvador Martinez45a15942016-08-11 17:14:11 -0700179 safeSetDefaultIcon();
Stephen Chened8f5292017-01-30 16:31:23 -0800180 return;
181 }
Sundeep Ghuman53200ed2017-06-21 16:54:36 -0700182 TronUtils.logWifiSettingsSpeed(context, mWifiSpeed);
Sundeep Ghuman271e5de2017-05-30 14:11:39 -0700183
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -0700184 Drawable drawable = mIconInjector.getIcon(level);
Stephen Chened8f5292017-01-30 16:31:23 -0800185 if (!mForSavedNetworks && drawable != null) {
Jason Changb4e879d2018-04-11 11:17:58 +0800186 drawable.setTintList(Utils.getColorAttr(context, android.R.attr.colorControlNormal));
Stephen Chened8f5292017-01-30 16:31:23 -0800187 setIcon(drawable);
Tony Mantler98608e42016-01-22 14:58:48 -0800188 } else {
Stephen Chened8f5292017-01-30 16:31:23 -0800189 safeSetDefaultIcon();
Tony Mantler98608e42016-01-22 14:58:48 -0800190 }
191 }
192
Stephen Chen2c096592017-01-18 15:25:31 -0800193 /**
194 * Binds the friction icon drawable using a StateListDrawable.
195 *
196 * <p>Friction icons will be rebound when notifyChange() is called, and therefore
197 * do not need to be managed in refresh()</p>.
198 */
199 private void bindFrictionImage(ImageView frictionImageView) {
200 if (frictionImageView == null || mFrictionSld == null) {
201 return;
202 }
Hai Shalomaa6f9202018-10-16 14:30:02 -0700203 if ((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
204 && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
Sundeep Ghuman4d8781e2017-03-15 16:03:55 -0700205 mFrictionSld.setState(STATE_SECURED);
Stephen Chen21f68682017-04-04 13:23:31 -0700206 } else if (mAccessPoint.isMetered()) {
Stephen Chenaed318e2017-03-31 16:58:38 -0700207 mFrictionSld.setState(STATE_METERED);
Stephen Chen2c096592017-01-18 15:25:31 -0800208 }
209 Drawable drawable = mFrictionSld.getCurrent();
210 frictionImageView.setImageDrawable(drawable);
211 }
212
Salvador Martinez45a15942016-08-11 17:14:11 -0700213 private void safeSetDefaultIcon() {
214 if (mDefaultIconResId != 0) {
215 setIcon(mDefaultIconResId);
216 } else {
217 setIcon(null);
218 }
219 }
220
Tony Mantler98608e42016-01-22 14:58:48 -0800221 protected void updateBadge(Context context) {
222 WifiConfiguration config = mAccessPoint.getConfig();
223 if (config != null) {
224 // Fetch badge (may be null)
225 // Get the badge using a cache since the PM will ask the UserManager for the list
226 // of profiles every time otherwise.
227 mBadge = mBadgeCache.getUserBadge(config.creatorUid);
228 }
229 }
230
231 /**
232 * Updates the title and summary; may indirectly call notifyChanged().
233 */
234 public void refresh() {
Quang Luong19429e42019-02-20 17:10:51 -0800235 setTitle(this, mAccessPoint);
Tony Mantler98608e42016-01-22 14:58:48 -0800236 final Context context = getContext();
Sundeep Ghumanaaa8a1b2017-03-13 14:40:56 -0700237 int level = mAccessPoint.getLevel();
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700238 int wifiSpeed = mAccessPoint.getSpeed();
239 if (level != mLevel || wifiSpeed != mWifiSpeed) {
Tony Mantler98608e42016-01-22 14:58:48 -0800240 mLevel = level;
Sundeep Ghuman55adc6b2017-06-05 16:46:59 -0700241 mWifiSpeed = wifiSpeed;
Tony Mantler98608e42016-01-22 14:58:48 -0800242 updateIcon(mLevel, context);
Julia Reynolds8897a502016-06-14 17:28:47 +0000243 notifyChanged();
Tony Mantler98608e42016-01-22 14:58:48 -0800244 }
Sundeep Ghumanf84e0572017-01-10 13:43:03 -0800245
Tony Mantler98608e42016-01-22 14:58:48 -0800246 updateBadge(context);
247
248 setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
249 : mAccessPoint.getSettingsSummary());
250
Fan Zhang60b850d2017-07-18 15:59:06 -0700251 mContentDescription = buildContentDescription(getContext(), this /* pref */, mAccessPoint);
Tony Mantler98608e42016-01-22 14:58:48 -0800252 }
253
254 @Override
255 protected void notifyChanged() {
256 if (Looper.getMainLooper() != Looper.myLooper()) {
257 // Let our BG thread callbacks call setTitle/setSummary.
258 postNotifyChanged();
259 } else {
260 super.notifyChanged();
261 }
262 }
263
Fan Zhangb6cec0d2017-09-05 11:02:03 -0700264 @VisibleForTesting
Quang Luong19429e42019-02-20 17:10:51 -0800265 static void setTitle(AccessPointPreference preference, AccessPoint ap) {
266 preference.setTitle(ap.getTitle());
Fan Zhangb6cec0d2017-09-05 11:02:03 -0700267 }
268
Fan Zhang60b850d2017-07-18 15:59:06 -0700269 /**
270 * Helper method to generate content description string.
271 */
272 @VisibleForTesting
273 static CharSequence buildContentDescription(Context context, Preference pref, AccessPoint ap) {
274 CharSequence contentDescription = pref.getTitle();
275 final CharSequence summary = pref.getSummary();
276 if (!TextUtils.isEmpty(summary)) {
277 contentDescription = TextUtils.concat(contentDescription, ",", summary);
278 }
279 int level = ap.getLevel();
280 if (level >= 0 && level < WIFI_CONNECTION_STRENGTH.length) {
281 contentDescription = TextUtils.concat(contentDescription, ",",
282 context.getString(WIFI_CONNECTION_STRENGTH[level]));
283 }
284 return TextUtils.concat(contentDescription, ",",
285 ap.getSecurity() == AccessPoint.SECURITY_NONE
286 ? context.getString(R.string.accessibility_wifi_security_type_none)
287 : context.getString(R.string.accessibility_wifi_security_type_secured));
288 }
289
Tony Mantler98608e42016-01-22 14:58:48 -0800290 public void onLevelChanged() {
291 postNotifyChanged();
292 }
293
294 private void postNotifyChanged() {
295 if (mTitleView != null) {
296 mTitleView.post(mNotifyChanged);
297 } // Otherwise we haven't been bound yet, and don't need to update.
298 }
299
300 private final Runnable mNotifyChanged = new Runnable() {
301 @Override
302 public void run() {
303 notifyChanged();
304 }
305 };
306
307 public static class UserBadgeCache {
308 private final SparseArray<Drawable> mBadges = new SparseArray<>();
309 private final PackageManager mPm;
310
311 public UserBadgeCache(PackageManager pm) {
312 mPm = pm;
313 }
314
315 private Drawable getUserBadge(int userId) {
316 int index = mBadges.indexOfKey(userId);
317 if (index < 0) {
318 Drawable badge = mPm.getUserBadgeForDensity(new UserHandle(userId), 0 /* dpi */);
319 mBadges.put(userId, badge);
320 return badge;
321 }
322 return mBadges.valueAt(index);
323 }
324 }
Eric Schwarzenbach6efd09a2017-08-22 10:33:00 -0700325
326 static class IconInjector {
327 private final Context mContext;
328
329 public IconInjector(Context context) {
330 mContext = context;
331 }
332
333 public Drawable getIcon(int level) {
334 return mContext.getDrawable(Utils.getWifiIconResource(level));
335 }
336 }
Tony Mantler98608e42016-01-22 14:58:48 -0800337}