• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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  */
16 package com.android.settingslib.wifi;
17 
18 import android.content.Context;
19 import android.content.pm.PackageManager;
20 import android.content.res.Resources;
21 import android.content.res.TypedArray;
22 import android.graphics.drawable.Drawable;
23 import android.graphics.drawable.StateListDrawable;
24 import android.net.NetworkBadging;
25 import android.net.wifi.WifiConfiguration;
26 import android.os.Looper;
27 import android.os.UserHandle;
28 import android.support.v7.preference.Preference;
29 import android.support.v7.preference.PreferenceViewHolder;
30 import android.text.TextUtils;
31 import android.util.AttributeSet;
32 import android.util.SparseArray;
33 import android.widget.ImageView;
34 import android.widget.TextView;
35 
36 import com.android.settingslib.R;
37 import com.android.settingslib.TronUtils;
38 import com.android.settingslib.Utils;
39 
40 public class AccessPointPreference extends Preference {
41 
42     private static final int[] STATE_SECURED = {
43             R.attr.state_encrypted
44     };
45 
46     private static final int[] STATE_METERED = {
47             R.attr.state_metered
48     };
49 
50     private static final int[] wifi_friction_attributes = { R.attr.wifi_friction };
51 
52     private final StateListDrawable mFrictionSld;
53     private final int mBadgePadding;
54     private final UserBadgeCache mBadgeCache;
55     private TextView mTitleView;
56 
57     private boolean mForSavedNetworks = false;
58     private AccessPoint mAccessPoint;
59     private Drawable mBadge;
60     private int mLevel;
61     private CharSequence mContentDescription;
62     private int mDefaultIconResId;
63     private int mWifiBadge = NetworkBadging.BADGING_NONE;
64 
65     static final int[] WIFI_CONNECTION_STRENGTH = {
66             R.string.accessibility_wifi_one_bar,
67             R.string.accessibility_wifi_two_bars,
68             R.string.accessibility_wifi_three_bars,
69             R.string.accessibility_wifi_signal_full
70     };
71 
72     // Used for dummy pref.
AccessPointPreference(Context context, AttributeSet attrs)73     public AccessPointPreference(Context context, AttributeSet attrs) {
74         super(context, attrs);
75         mFrictionSld = null;
76         mBadgePadding = 0;
77         mBadgeCache = null;
78     }
79 
AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache, boolean forSavedNetworks)80     public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
81             boolean forSavedNetworks) {
82         super(context);
83         setWidgetLayoutResource(R.layout.access_point_friction_widget);
84         mBadgeCache = cache;
85         mAccessPoint = accessPoint;
86         mForSavedNetworks = forSavedNetworks;
87         mAccessPoint.setTag(this);
88         mLevel = -1;
89 
90         TypedArray frictionSld;
91         try {
92             frictionSld = context.getTheme().obtainStyledAttributes(wifi_friction_attributes);
93         } catch (Resources.NotFoundException e) {
94             // Fallback for platforms that do not need friction icon resources.
95             frictionSld = null;
96         }
97         mFrictionSld = frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
98 
99         // Distance from the end of the title at which this AP's user badge should sit.
100         mBadgePadding = context.getResources()
101                 .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
102         refresh();
103     }
104 
AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache, int iconResId, boolean forSavedNetworks)105     public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
106             int iconResId, boolean forSavedNetworks) {
107         super(context);
108         setWidgetLayoutResource(R.layout.access_point_friction_widget);
109         mBadgeCache = cache;
110         mAccessPoint = accessPoint;
111         mForSavedNetworks = forSavedNetworks;
112         mAccessPoint.setTag(this);
113         mLevel = -1;
114         mDefaultIconResId = iconResId;
115 
116         TypedArray frictionSld;
117         try {
118             frictionSld = context.getTheme().obtainStyledAttributes(wifi_friction_attributes);
119         } catch (Resources.NotFoundException e) {
120             // Fallback for platforms that do not need friction icon resources.
121             frictionSld = null;
122         }
123         mFrictionSld = frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
124 
125         // Distance from the end of the title at which this AP's user badge should sit.
126         mBadgePadding = context.getResources()
127                 .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
128     }
129 
getAccessPoint()130     public AccessPoint getAccessPoint() {
131         return mAccessPoint;
132     }
133 
134     @Override
onBindViewHolder(final PreferenceViewHolder view)135     public void onBindViewHolder(final PreferenceViewHolder view) {
136         super.onBindViewHolder(view);
137         if (mAccessPoint == null) {
138             // Used for dummy pref.
139             return;
140         }
141         Drawable drawable = getIcon();
142         if (drawable != null) {
143             drawable.setLevel(mLevel);
144         }
145 
146         mTitleView = (TextView) view.findViewById(com.android.internal.R.id.title);
147         if (mTitleView != null) {
148             // Attach to the end of the title view
149             mTitleView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, mBadge, null);
150             mTitleView.setCompoundDrawablePadding(mBadgePadding);
151         }
152         view.itemView.setContentDescription(mContentDescription);
153 
154         ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
155         bindFrictionImage(frictionImageView);
156     }
157 
updateIcon(int level, Context context)158     protected void updateIcon(int level, Context context) {
159         if (level == -1) {
160             safeSetDefaultIcon();
161             return;
162         }
163         TronUtils.logWifiSettingsBadge(context, mWifiBadge);
164         Drawable drawable = NetworkBadging.getWifiIcon(level, mWifiBadge, getContext().getTheme());
165         if (!mForSavedNetworks && drawable != null) {
166             drawable.setTint(Utils.getColorAttr(context, android.R.attr.colorControlNormal));
167             setIcon(drawable);
168         } else {
169             safeSetDefaultIcon();
170         }
171     }
172 
173     /**
174      * Binds the friction icon drawable using a StateListDrawable.
175      *
176      * <p>Friction icons will be rebound when notifyChange() is called, and therefore
177      * do not need to be managed in refresh()</p>.
178      */
bindFrictionImage(ImageView frictionImageView)179     private void bindFrictionImage(ImageView frictionImageView) {
180         if (frictionImageView == null || mFrictionSld == null) {
181             return;
182         }
183         if (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
184             mFrictionSld.setState(STATE_SECURED);
185         } else if (mAccessPoint.isMetered()) {
186             mFrictionSld.setState(STATE_METERED);
187         }
188         Drawable drawable = mFrictionSld.getCurrent();
189         frictionImageView.setImageDrawable(drawable);
190     }
191 
safeSetDefaultIcon()192     private void safeSetDefaultIcon() {
193         if (mDefaultIconResId != 0) {
194             setIcon(mDefaultIconResId);
195         } else {
196             setIcon(null);
197         }
198     }
199 
updateBadge(Context context)200     protected void updateBadge(Context context) {
201         WifiConfiguration config = mAccessPoint.getConfig();
202         if (config != null) {
203             // Fetch badge (may be null)
204             // Get the badge using a cache since the PM will ask the UserManager for the list
205             // of profiles every time otherwise.
206             mBadge = mBadgeCache.getUserBadge(config.creatorUid);
207         }
208     }
209 
210     /**
211      * Updates the title and summary; may indirectly call notifyChanged().
212      */
refresh()213     public void refresh() {
214         if (mForSavedNetworks) {
215             setTitle(mAccessPoint.getConfigName());
216         } else {
217             setTitle(mAccessPoint.getSsid());
218         }
219 
220         final Context context = getContext();
221         int level = mAccessPoint.getLevel();
222         int wifiBadge = mAccessPoint.getBadge();
223         if (level != mLevel || wifiBadge != mWifiBadge) {
224             mLevel = level;
225             mWifiBadge = wifiBadge;
226             updateIcon(mLevel, context);
227             notifyChanged();
228         }
229 
230         updateBadge(context);
231 
232         setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
233                 : mAccessPoint.getSettingsSummary());
234 
235         mContentDescription = getTitle();
236         if (getSummary() != null) {
237             mContentDescription = TextUtils.concat(mContentDescription, ",", getSummary());
238         }
239         if (level >= 0 && level < WIFI_CONNECTION_STRENGTH.length) {
240             mContentDescription = TextUtils.concat(mContentDescription, ",",
241                     getContext().getString(WIFI_CONNECTION_STRENGTH[level]));
242         }
243     }
244 
245     @Override
notifyChanged()246     protected void notifyChanged() {
247         if (Looper.getMainLooper() != Looper.myLooper()) {
248             // Let our BG thread callbacks call setTitle/setSummary.
249             postNotifyChanged();
250         } else {
251             super.notifyChanged();
252         }
253     }
254 
onLevelChanged()255     public void onLevelChanged() {
256         postNotifyChanged();
257     }
258 
postNotifyChanged()259     private void postNotifyChanged() {
260         if (mTitleView != null) {
261             mTitleView.post(mNotifyChanged);
262         } // Otherwise we haven't been bound yet, and don't need to update.
263     }
264 
265     private final Runnable mNotifyChanged = new Runnable() {
266         @Override
267         public void run() {
268             notifyChanged();
269         }
270     };
271 
272     public static class UserBadgeCache {
273         private final SparseArray<Drawable> mBadges = new SparseArray<>();
274         private final PackageManager mPm;
275 
UserBadgeCache(PackageManager pm)276         public UserBadgeCache(PackageManager pm) {
277             mPm = pm;
278         }
279 
getUserBadge(int userId)280         private Drawable getUserBadge(int userId) {
281             int index = mBadges.indexOfKey(userId);
282             if (index < 0) {
283                 Drawable badge = mPm.getUserBadgeForDensity(new UserHandle(userId), 0 /* dpi */);
284                 mBadges.put(userId, badge);
285                 return badge;
286             }
287             return mBadges.valueAt(index);
288         }
289     }
290 }
291