Home | History | Annotate | Download | only in wifi
      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 
     17 package com.android.settingslib.wifi;
     18 
     19 import android.content.Context;
     20 import android.content.pm.PackageManager;
     21 import android.graphics.drawable.Drawable;
     22 import android.graphics.drawable.StateListDrawable;
     23 import android.net.wifi.WifiConfiguration;
     24 import android.os.Looper;
     25 import android.os.UserHandle;
     26 import android.support.v7.preference.Preference;
     27 import android.support.v7.preference.PreferenceViewHolder;
     28 import android.text.TextUtils;
     29 import android.util.AttributeSet;
     30 import android.util.SparseArray;
     31 import android.widget.TextView;
     32 
     33 import com.android.settingslib.R;
     34 
     35 public class AccessPointPreference extends Preference {
     36 
     37     private static final int[] STATE_SECURED = {
     38             R.attr.state_encrypted
     39     };
     40     private static final int[] STATE_NONE = {};
     41 
     42     private static int[] wifi_signal_attributes = { R.attr.wifi_signal };
     43 
     44     private final StateListDrawable mWifiSld;
     45     private final int mBadgePadding;
     46     private final UserBadgeCache mBadgeCache;
     47 
     48     private TextView mTitleView;
     49     private boolean mForSavedNetworks = false;
     50     private AccessPoint mAccessPoint;
     51     private Drawable mBadge;
     52     private int mLevel;
     53     private CharSequence mContentDescription;
     54 
     55     static final int[] WIFI_CONNECTION_STRENGTH = {
     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     // Used for dummy pref.
     63     public AccessPointPreference(Context context, AttributeSet attrs) {
     64         super(context, attrs);
     65         mWifiSld = null;
     66         mBadgePadding = 0;
     67         mBadgeCache = null;
     68     }
     69 
     70     public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
     71             boolean forSavedNetworks) {
     72         super(context);
     73         mBadgeCache = cache;
     74         mAccessPoint = accessPoint;
     75         mForSavedNetworks = forSavedNetworks;
     76         mAccessPoint.setTag(this);
     77         mLevel = -1;
     78 
     79         mWifiSld = (StateListDrawable) context.getTheme()
     80                 .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
     81 
     82         // Distance from the end of the title at which this AP's user badge should sit.
     83         mBadgePadding = context.getResources()
     84                 .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
     85         refresh();
     86     }
     87 
     88     public AccessPoint getAccessPoint() {
     89         return mAccessPoint;
     90     }
     91 
     92     @Override
     93     public void onBindViewHolder(final PreferenceViewHolder view) {
     94         super.onBindViewHolder(view);
     95         if (mAccessPoint == null) {
     96             // Used for dummy pref.
     97             return;
     98         }
     99         Drawable drawable = getIcon();
    100         if (drawable != null) {
    101             drawable.setLevel(mLevel);
    102         }
    103 
    104         mTitleView = (TextView) view.findViewById(com.android.internal.R.id.title);
    105         if (mTitleView != null) {
    106             // Attach to the end of the title view
    107             mTitleView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, mBadge, null);
    108             mTitleView.setCompoundDrawablePadding(mBadgePadding);
    109         }
    110         view.itemView.setContentDescription(mContentDescription);
    111     }
    112 
    113     protected void updateIcon(int level, Context context) {
    114         if (level == -1) {
    115             setIcon(null);
    116         } else {
    117             if (getIcon() == null) {
    118                 // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
    119                 // set the icon (drawable) to that state's drawable.
    120                 // If sld is null then we are indexing and therefore do not have access to
    121                 // (nor need to display) the drawable.
    122                 if (mWifiSld != null) {
    123                     mWifiSld.setState((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
    124                             ? STATE_SECURED
    125                             : STATE_NONE);
    126                     Drawable drawable = mWifiSld.getCurrent();
    127                     if (!mForSavedNetworks) {
    128                         setIcon(drawable);
    129                     } else {
    130                         setIcon(null);
    131                     }
    132                 }
    133             }
    134         }
    135     }
    136 
    137     protected void updateBadge(Context context) {
    138         WifiConfiguration config = mAccessPoint.getConfig();
    139         if (config != null) {
    140             // Fetch badge (may be null)
    141             // Get the badge using a cache since the PM will ask the UserManager for the list
    142             // of profiles every time otherwise.
    143             mBadge = mBadgeCache.getUserBadge(config.creatorUid);
    144         }
    145     }
    146 
    147     /**
    148      * Updates the title and summary; may indirectly call notifyChanged().
    149      */
    150     public void refresh() {
    151         if (mForSavedNetworks) {
    152             setTitle(mAccessPoint.getConfigName());
    153         } else {
    154             setTitle(mAccessPoint.getSsid());
    155         }
    156 
    157         final Context context = getContext();
    158         int level = mAccessPoint.getLevel();
    159         if (level != mLevel) {
    160             mLevel = level;
    161             updateIcon(mLevel, context);
    162             notifyChanged();
    163         }
    164         updateBadge(context);
    165 
    166         setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
    167                 : mAccessPoint.getSettingsSummary());
    168 
    169         mContentDescription = getTitle();
    170         if (getSummary() != null) {
    171             mContentDescription = TextUtils.concat(mContentDescription, ",", getSummary());
    172         }
    173         if (level >= 0 && level < WIFI_CONNECTION_STRENGTH.length) {
    174             mContentDescription = TextUtils.concat(mContentDescription, ",",
    175                     getContext().getString(WIFI_CONNECTION_STRENGTH[level]));
    176         }
    177     }
    178 
    179     @Override
    180     protected void notifyChanged() {
    181         if (Looper.getMainLooper() != Looper.myLooper()) {
    182             // Let our BG thread callbacks call setTitle/setSummary.
    183             postNotifyChanged();
    184         } else {
    185             super.notifyChanged();
    186         }
    187     }
    188 
    189     public void onLevelChanged() {
    190         postNotifyChanged();
    191     }
    192 
    193     private void postNotifyChanged() {
    194         if (mTitleView != null) {
    195             mTitleView.post(mNotifyChanged);
    196         } // Otherwise we haven't been bound yet, and don't need to update.
    197     }
    198 
    199     private final Runnable mNotifyChanged = new Runnable() {
    200         @Override
    201         public void run() {
    202             notifyChanged();
    203         }
    204     };
    205 
    206     public static class UserBadgeCache {
    207         private final SparseArray<Drawable> mBadges = new SparseArray<>();
    208         private final PackageManager mPm;
    209 
    210         public UserBadgeCache(PackageManager pm) {
    211             mPm = pm;
    212         }
    213 
    214         private Drawable getUserBadge(int userId) {
    215             int index = mBadges.indexOfKey(userId);
    216             if (index < 0) {
    217                 Drawable badge = mPm.getUserBadgeForDensity(new UserHandle(userId), 0 /* dpi */);
    218                 mBadges.put(userId, badge);
    219                 return badge;
    220             }
    221             return mBadges.valueAt(index);
    222         }
    223     }
    224 }
    225