• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.annotation.Nullable;
19 import android.content.Context;
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.text.TextUtils;
25 import android.view.View;
26 import android.widget.ImageButton;
27 import android.widget.ImageView;
28 
29 import androidx.annotation.DrawableRes;
30 import androidx.annotation.NonNull;
31 import androidx.annotation.VisibleForTesting;
32 import androidx.preference.Preference;
33 import androidx.preference.PreferenceViewHolder;
34 
35 import com.android.settingslib.R;
36 import com.android.settingslib.Utils;
37 import com.android.wifitrackerlib.WifiEntry;
38 
39 /**
40  * Preference to display a WifiEntry in a wifi picker.
41  */
42 public class WifiEntryPreference extends Preference implements WifiEntry.WifiEntryCallback,
43         View.OnClickListener {
44 
45     private static final int[] STATE_SECURED = {
46             R.attr.state_encrypted
47     };
48 
49     private static final int[] FRICTION_ATTRS = {
50             R.attr.wifi_friction
51     };
52 
53     // These values must be kept within [WifiEntry.WIFI_LEVEL_MIN, WifiEntry.WIFI_LEVEL_MAX]
54     private static final int[] WIFI_CONNECTION_STRENGTH = {
55             R.string.accessibility_no_wifi,
56             R.string.accessibility_wifi_one_bar,
57             R.string.accessibility_wifi_two_bars,
58             R.string.accessibility_wifi_three_bars,
59             R.string.accessibility_wifi_signal_full
60     };
61 
62     // StateListDrawable to display secured lock / metered "$" icon
63     @Nullable private final StateListDrawable mFrictionSld;
64     private final IconInjector mIconInjector;
65     private WifiEntry mWifiEntry;
66     private int mLevel = -1;
67     private boolean mShowX; // Shows the Wi-Fi signl icon of Pie+x when it's true.
68     private CharSequence mContentDescription;
69     private OnButtonClickListener mOnButtonClickListener;
70 
WifiEntryPreference(@onNull Context context, @NonNull WifiEntry wifiEntry)71     public WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry) {
72         this(context, wifiEntry, new IconInjector(context));
73     }
74 
75     @VisibleForTesting
WifiEntryPreference(@onNull Context context, @NonNull WifiEntry wifiEntry, @NonNull IconInjector iconInjector)76     WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry,
77             @NonNull IconInjector iconInjector) {
78         super(context);
79 
80         setLayoutResource(R.layout.preference_access_point);
81         setWidgetLayoutResource(R.layout.access_point_friction_widget);
82         mFrictionSld = getFrictionStateListDrawable();
83         mWifiEntry = wifiEntry;
84         mWifiEntry.setListener(this);
85         mIconInjector = iconInjector;
86         refresh();
87     }
88 
getWifiEntry()89     public WifiEntry getWifiEntry() {
90         return mWifiEntry;
91     }
92 
93     @Override
onBindViewHolder(final PreferenceViewHolder view)94     public void onBindViewHolder(final PreferenceViewHolder view) {
95         super.onBindViewHolder(view);
96         final Drawable drawable = getIcon();
97         if (drawable != null) {
98             drawable.setLevel(mLevel);
99         }
100 
101         view.itemView.setContentDescription(mContentDescription);
102 
103         // Turn off divider
104         view.findViewById(R.id.two_target_divider).setVisibility(View.INVISIBLE);
105 
106         // Enable the icon button when the help string in this WifiEntry is not null.
107         final ImageButton imageButton = (ImageButton) view.findViewById(R.id.icon_button);
108         final ImageView frictionImageView = (ImageView) view.findViewById(
109                 R.id.friction_icon);
110         if (mWifiEntry.getHelpUriString() != null
111                 && mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) {
112             final Drawable drawablehelp = getDrawable(R.drawable.ic_help);
113             drawablehelp.setTintList(
114                     Utils.getColorAttr(getContext(), android.R.attr.colorControlNormal));
115             ((ImageView) imageButton).setImageDrawable(drawablehelp);
116             imageButton.setVisibility(View.VISIBLE);
117             imageButton.setOnClickListener(this);
118             imageButton.setContentDescription(
119                     getContext().getText(R.string.help_label));
120 
121             if (frictionImageView != null) {
122                 frictionImageView.setVisibility(View.GONE);
123             }
124         } else {
125             imageButton.setVisibility(View.GONE);
126 
127             if (frictionImageView != null) {
128                 frictionImageView.setVisibility(View.VISIBLE);
129                 bindFrictionImage(frictionImageView);
130             }
131         }
132     }
133 
134     /**
135      * Updates the title and summary; may indirectly call notifyChanged().
136      */
refresh()137     public void refresh() {
138         setTitle(mWifiEntry.getTitle());
139         final int level = mWifiEntry.getLevel();
140         final boolean showX = mWifiEntry.shouldShowXLevelIcon();
141         if (level != mLevel || showX != mShowX) {
142             mLevel = level;
143             mShowX = showX;
144             updateIcon(mShowX, mLevel);
145             notifyChanged();
146         }
147 
148         setSummary(mWifiEntry.getSummary(false /* concise */));
149         mContentDescription = buildContentDescription();
150     }
151 
152     /**
153      * Indicates the state of the WifiEntry has changed and clients may retrieve updates through
154      * the WifiEntry getter methods.
155      */
onUpdated()156     public void onUpdated() {
157         // TODO(b/70983952): Fill this method in
158         refresh();
159     }
160 
161     /**
162      * Result of the connect request indicated by the WifiEntry.CONNECT_STATUS constants.
163      */
onConnectResult(int status)164     public void onConnectResult(int status) {
165         // TODO(b/70983952): Fill this method in
166     }
167 
168     /**
169      * Result of the disconnect request indicated by the WifiEntry.DISCONNECT_STATUS constants.
170      */
onDisconnectResult(int status)171     public void onDisconnectResult(int status) {
172         // TODO(b/70983952): Fill this method in
173     }
174 
175     /**
176      * Result of the forget request indicated by the WifiEntry.FORGET_STATUS constants.
177      */
onForgetResult(int status)178     public void onForgetResult(int status) {
179         // TODO(b/70983952): Fill this method in
180     }
181 
182     /**
183      * Result of the sign-in request indecated by the WifiEntry.SIGNIN_STATUS constants
184      */
onSignInResult(int status)185     public void onSignInResult(int status) {
186         // TODO(b/70983952): Fill this method in
187     }
188 
189 
updateIcon(boolean showX, int level)190     private void updateIcon(boolean showX, int level) {
191         if (level == -1) {
192             setIcon(null);
193             return;
194         }
195 
196         final Drawable drawable = mIconInjector.getIcon(showX, level);
197         if (drawable != null) {
198             drawable.setTintList(Utils.getColorAttr(getContext(),
199                     android.R.attr.colorControlNormal));
200             setIcon(drawable);
201         } else {
202             setIcon(null);
203         }
204     }
205 
206     @Nullable
getFrictionStateListDrawable()207     private StateListDrawable getFrictionStateListDrawable() {
208         TypedArray frictionSld;
209         try {
210             frictionSld = getContext().getTheme().obtainStyledAttributes(FRICTION_ATTRS);
211         } catch (Resources.NotFoundException e) {
212             // Fallback for platforms that do not need friction icon resources.
213             frictionSld = null;
214         }
215         return frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
216     }
217 
218     /**
219      * Binds the friction icon drawable using a StateListDrawable.
220      *
221      * <p>Friction icons will be rebound when notifyChange() is called, and therefore
222      * do not need to be managed in refresh()</p>.
223      */
bindFrictionImage(ImageView frictionImageView)224     private void bindFrictionImage(ImageView frictionImageView) {
225         if (frictionImageView == null || mFrictionSld == null) {
226             return;
227         }
228         if ((mWifiEntry.getSecurity() != WifiEntry.SECURITY_NONE)
229                 && (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE)) {
230             mFrictionSld.setState(STATE_SECURED);
231         }
232         frictionImageView.setImageDrawable(mFrictionSld.getCurrent());
233     }
234 
235     /**
236      * Helper method to generate content description string.
237      */
238     @VisibleForTesting
buildContentDescription()239     CharSequence buildContentDescription() {
240         final Context context = getContext();
241 
242         CharSequence contentDescription = getTitle();
243         final CharSequence summary = getSummary();
244         if (!TextUtils.isEmpty(summary)) {
245             contentDescription = TextUtils.concat(contentDescription, ",", summary);
246         }
247         int level = mWifiEntry.getLevel();
248         if (level >= 0 && level < WIFI_CONNECTION_STRENGTH.length) {
249             contentDescription = TextUtils.concat(contentDescription, ",",
250                     context.getString(WIFI_CONNECTION_STRENGTH[level]));
251         }
252         return TextUtils.concat(contentDescription, ",",
253                 mWifiEntry.getSecurity() == WifiEntry.SECURITY_NONE
254                         ? context.getString(R.string.accessibility_wifi_security_type_none)
255                         : context.getString(R.string.accessibility_wifi_security_type_secured));
256     }
257 
258 
259     static class IconInjector {
260         private final Context mContext;
261 
IconInjector(Context context)262         IconInjector(Context context) {
263             mContext = context;
264         }
265 
getIcon(boolean showX, int level)266         public Drawable getIcon(boolean showX, int level) {
267             return mContext.getDrawable(Utils.getWifiIconResource(showX, level));
268         }
269     }
270 
271     /**
272      * Set listeners, who want to listen the button client event.
273      */
setOnButtonClickListener(OnButtonClickListener listener)274     public void setOnButtonClickListener(OnButtonClickListener listener) {
275         mOnButtonClickListener = listener;
276         notifyChanged();
277     }
278 
279     @Override
onClick(View view)280     public void onClick(View view) {
281         if (view.getId() == R.id.icon_button) {
282             if (mOnButtonClickListener != null) {
283                 mOnButtonClickListener.onButtonClick(this);
284             }
285         }
286     }
287 
288     /**
289      * Callback to inform the caller that the icon button is clicked.
290      */
291     public interface OnButtonClickListener {
292 
293         /**
294          * Register to listen the button click event.
295          */
onButtonClick(WifiEntryPreference preference)296         void onButtonClick(WifiEntryPreference preference);
297     }
298 
getDrawable(@rawableRes int iconResId)299     private Drawable getDrawable(@DrawableRes int iconResId) {
300         Drawable buttonIcon = null;
301 
302         try {
303             buttonIcon = getContext().getDrawable(iconResId);
304         } catch (Resources.NotFoundException exception) {
305             // Do nothing
306         }
307         return buttonIcon;
308     }
309 
310 }
311