Home | History | Annotate | Download | only in connectivity
      1 /*
      2  * Copyright (C) 2014 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.tv.settings.connectivity;
     18 
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.res.Resources;
     22 import android.net.wifi.ScanResult;
     23 import android.net.wifi.WifiInfo;
     24 import android.net.wifi.WifiManager;
     25 import android.os.Handler;
     26 import android.os.Message;
     27 import android.support.v17.leanback.widget.ArrayObjectAdapter;
     28 import android.support.v17.leanback.widget.HeaderItem;
     29 import android.support.v17.leanback.widget.ObjectAdapter;
     30 import android.support.v17.leanback.widget.ListRow;
     31 import android.text.TextUtils;
     32 import android.util.Log;
     33 import android.util.Pair;
     34 import android.util.SparseArray;
     35 
     36 import com.android.tv.settings.BrowseInfoBase;
     37 import com.android.tv.settings.MenuItem;
     38 import com.android.tv.settings.R;
     39 
     40 import java.util.ArrayList;
     41 import java.util.Collections;
     42 import java.util.HashMap;
     43 import java.util.List;
     44 
     45 /**
     46  * Gets the list of browse headers and browse items.
     47  */
     48 public class WifiNetworksBrowseInfo extends BrowseInfoBase {
     49 
     50     private static final String TAG = "WifiNetworksBrowseInfo";
     51     private static final boolean DEBUG = false;
     52 
     53     private static final int FIRST_HEADER_ID = 1;
     54     private static final int SECOND_HEADER_ID = 2;
     55     private static final int OTHER_OPTIONS_WPS = 0;
     56     private static final int OTHER_OPTIONS_ADD_NETWORK = 1;
     57     private static final int MSG_NETWORK_REFRESH = 1;
     58     private static final int NETWORK_REFRESH_TIMEOUT = 15000;
     59     private static final int NUMBER_SIGNAL_LEVELS = 4;
     60 
     61     private final Context mContext;
     62     private final Handler mHandler;
     63     private final WifiManager mWifiManager;
     64     private int mNextItemId;
     65     private final HashMap<Pair<String, WifiSecurity>, Integer> mIdToSsidMap;
     66 
     67     WifiNetworksBrowseInfo(Context context) {
     68         mContext = context;
     69         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
     70         mHandler = new Handler() {
     71             @Override
     72             public void handleMessage(Message msg) {
     73                 refreshAvailableNetworksBrowseItems();
     74                 mHandler.sendEmptyMessageDelayed(MSG_NETWORK_REFRESH, NETWORK_REFRESH_TIMEOUT);
     75             }
     76         };
     77         mIdToSsidMap = new HashMap<Pair<String, WifiSecurity>, Integer>();
     78         mNextItemId = 0;
     79         mRows.put(FIRST_HEADER_ID, new ArrayObjectAdapter());
     80         mRows.put(SECOND_HEADER_ID, new ArrayObjectAdapter());
     81     }
     82 
     83     @Override
     84     public void refreshContent() {
     85         init();
     86     }
     87 
     88     public void onShutdown() {
     89         stopScanning();
     90         mIdToSsidMap.clear();
     91     }
     92 
     93     void init() {
     94         mHeaderItems.clear();
     95         String header1 = mContext.getString(R.string.wifi_setting_header_available_networks);
     96         String header2 = mContext.getString(R.string.wifi_setting_header_other_options);
     97         addBrowseHeader(FIRST_HEADER_ID, header1);
     98         addBrowseHeader(SECOND_HEADER_ID, header2);
     99 
    100         ArrayObjectAdapter row = mRows.get(FIRST_HEADER_ID);
    101         initAvailableNetworksBrowseItems(row);
    102         initOtherOptionsBrowseItems();
    103     }
    104 
    105     protected void startScanning() {
    106         mHandler.sendEmptyMessage(MSG_NETWORK_REFRESH);
    107     }
    108 
    109     protected void stopScanning() {
    110         mHandler.removeMessages(MSG_NETWORK_REFRESH);
    111     }
    112 
    113     private void addBrowseHeader(int id, String name) {
    114         mHeaderItems.add(new HeaderItem(id, name, null));
    115     }
    116 
    117     private void initAvailableNetworksBrowseItems(ArrayObjectAdapter row) {
    118         WifiInfo currentConnection = mWifiManager.getConnectionInfo();
    119         List<ScanResult> networks = getAvailableNetworks(currentConnection);
    120 
    121         if (networks.size() > 0) {
    122             for (ScanResult network : networks) {
    123                 if (network != null) {
    124                     WifiSecurity security = WifiSecurity.getSecurity(network);
    125 
    126                     String networkDescription = security.isOpen() ? "" : security.getName(mContext);
    127                     Intent intent =
    128                             WifiConnectionActivity.createIntent(mContext, network, security);
    129                     int signalLevel = WifiManager.calculateSignalLevel(
    130                             network.level, NUMBER_SIGNAL_LEVELS);
    131                     int imageResourceId = getNetworkIconResourceId(
    132                             network, signalLevel);
    133                     if (WifiConfigHelper.areSameNetwork(mWifiManager, network, currentConnection)) {
    134                         networkDescription = mContext.getString(R.string.connected);
    135                         intent = getConnectedNetworkIntent();
    136                         signalLevel = WifiManager.calculateSignalLevel(
    137                                 currentConnection.getRssi(), NUMBER_SIGNAL_LEVELS);
    138                         imageResourceId = getCurrentNetworkIconResourceId(network, signalLevel);
    139                     }
    140 
    141                     Integer itemId = getItemId(network, security);
    142 
    143                     if (DEBUG) {
    144                         Log.d(TAG, "Network " + itemId + " has SSID=" + network.SSID +
    145                                 ", BSSID=" + network.BSSID +
    146                                 ", current connected SSID=" + currentConnection.getSSID() +
    147                                 ", current connected BSSID=" + currentConnection.getBSSID());
    148                     }
    149 
    150                     row.add(new MenuItem.Builder().id(itemId).title(network.SSID)
    151                             .description(networkDescription)
    152                             .imageResourceId(mContext, imageResourceId).intent(intent)
    153                             .build());
    154                 }
    155             }
    156         } else {
    157             row.add(new MenuItem.Builder().id(generateNextItemId())
    158                     .title(mContext.getString(R.string.title_wifi_no_networks_available))
    159                     .imageResourceId(mContext, R.drawable.ic_settings_wifi_scan).build());
    160         }
    161     }
    162 
    163     private Integer getItemId(ScanResult network, WifiSecurity security) {
    164         Pair<String, WifiSecurity> key = Pair.create(network.SSID, security);
    165         Integer itemId = mIdToSsidMap.get(key);
    166         if (itemId == null) {
    167             itemId = generateNextItemId();
    168             mIdToSsidMap.put(key, itemId);
    169         }
    170         return itemId;
    171     }
    172 
    173     private int generateNextItemId() {
    174         int id = mNextItemId;
    175         mNextItemId++;
    176         return id;
    177     }
    178 
    179     private Intent getConnectedNetworkIntent() {
    180         return new Intent(mContext, WifiConfigurationActivity.class);
    181     }
    182 
    183     private void initOtherOptionsBrowseItems() {
    184         String wpsName = mContext.getString(R.string.wifi_setting_other_options_wps);
    185         String addNetworkName = mContext.getString(R.string.wifi_setting_other_options_add_network);
    186         ArrayObjectAdapter row = mRows.get(SECOND_HEADER_ID);
    187 
    188         addOtherOptionBrowseItem(row, OTHER_OPTIONS_WPS, wpsName);
    189         addOtherOptionBrowseItem(row, OTHER_OPTIONS_ADD_NETWORK, addNetworkName);
    190     }
    191 
    192     private void addOtherOptionBrowseItem(ArrayObjectAdapter row, int id, String name) {
    193         row.add(new MenuItem.Builder().id(id).title(name)
    194                 .imageResourceId(mContext, getOtherOptionsIconResourceId(id))
    195                 .intent(getOtherOptionsIntent(id)).build());
    196     }
    197 
    198     private Intent getOtherOptionsIntent(int otherOptionIndex) {
    199         Intent intent = null;
    200         switch (otherOptionIndex) {
    201             case OTHER_OPTIONS_WPS:
    202                 intent = new Intent(mContext, WpsConnectionActivity.class);
    203                 break;
    204             case OTHER_OPTIONS_ADD_NETWORK:
    205                 intent = new Intent(mContext, AddWifiNetworkActivity.class);
    206                 break;
    207             default:
    208                 Log.d(TAG, "Unknown otherOptionIndex: " + otherOptionIndex);
    209                 break;
    210         }
    211         return intent;
    212     }
    213 
    214     private int getCurrentNetworkIconResourceId(
    215             ScanResult scanResult, int signalLevel) {
    216         int resourceId = 0;
    217         if (scanResult != null) {
    218             WifiSecurity security = WifiSecurity.getSecurity(scanResult);
    219             if (security.isOpen()) {
    220                 switch (signalLevel)
    221                 {
    222                     case 0:
    223                         resourceId = R.drawable.ic_settings_wifi_active_1;
    224                         break;
    225                     case 1:
    226                         resourceId = R.drawable.ic_settings_wifi_active_2;
    227                         break;
    228                     case 2:
    229                         resourceId = R.drawable.ic_settings_wifi_active_3;
    230                         break;
    231                     case 3:
    232                         resourceId = R.drawable.ic_settings_wifi_active_4;
    233                         break;
    234                 }
    235             } else {
    236                 switch (signalLevel)
    237                 {
    238                     case 0:
    239                         resourceId = R.drawable.ic_settings_wifi_secure_active_1;
    240                         break;
    241                     case 1:
    242                         resourceId = R.drawable.ic_settings_wifi_secure_active_2;
    243                         break;
    244                     case 2:
    245                         resourceId = R.drawable.ic_settings_wifi_secure_active_3;
    246                         break;
    247                     case 3:
    248                         resourceId = R.drawable.ic_settings_wifi_secure_active_4;
    249                         break;
    250                 }
    251             }
    252         }
    253         return resourceId;
    254     }
    255 
    256     private int getNetworkIconResourceId(ScanResult scanResult, int signalLevel) {
    257         int resourceId = 0;
    258         if (scanResult != null) {
    259             WifiSecurity security = WifiSecurity.getSecurity(scanResult);
    260             if (security.isOpen()) {
    261                 switch (signalLevel)
    262                 {
    263                     case 0:
    264                         resourceId = R.drawable.ic_settings_wifi_1;
    265                         break;
    266                     case 1:
    267                         resourceId = R.drawable.ic_settings_wifi_2;
    268                         break;
    269                     case 2:
    270                         resourceId = R.drawable.ic_settings_wifi_3;
    271                         break;
    272                     case 3:
    273                         resourceId = R.drawable.ic_settings_wifi_4;
    274                         break;
    275                 }
    276             } else {
    277                 switch (signalLevel)
    278                 {
    279                     case 0:
    280                         resourceId = R.drawable.ic_settings_wifi_secure_1;
    281                         break;
    282                     case 1:
    283                         resourceId = R.drawable.ic_settings_wifi_secure_2;
    284                         break;
    285                     case 2:
    286                         resourceId = R.drawable.ic_settings_wifi_secure_3;
    287                         break;
    288                     case 3:
    289                         resourceId = R.drawable.ic_settings_wifi_secure_4;
    290                         break;
    291                 }
    292             }
    293         }
    294         return resourceId;
    295     }
    296 
    297     private List<ScanResult> getAvailableNetworks(WifiInfo connectedWifiInfo) {
    298         String currentConnectedSSID = connectedWifiInfo == null ? "" : connectedWifiInfo.getSSID();
    299         currentConnectedSSID = WifiInfo.removeDoubleQuotes(currentConnectedSSID);
    300         WifiSecurity currentConnectedSecurity = WifiConfigHelper.getCurrentConnectionSecurity(
    301                 mWifiManager, connectedWifiInfo);
    302 
    303         // TODO : Refactor with similar code in SelectFromListWizard
    304         final List<ScanResult> results = mWifiManager.getScanResults();
    305 
    306         if (results.size() == 0) {
    307             Log.w(TAG, "No results found! Initiate scan...");
    308             mWifiManager.startScan();
    309         }
    310 
    311         final HashMap<Pair<String, WifiSecurity>, ScanResult> consolidatedScanResults =
    312                 new HashMap<Pair<String, WifiSecurity>, ScanResult>();
    313         HashMap<Pair<String, WifiSecurity>, Boolean> specialNetworks = new HashMap<
    314                 Pair<String, WifiSecurity>, Boolean>();
    315         for (ScanResult result : results) {
    316             if (TextUtils.isEmpty(result.SSID)) {
    317                 continue;
    318             }
    319 
    320             Pair<String, WifiSecurity> key = Pair.create(
    321                     result.SSID, WifiSecurity.getSecurity(result));
    322             ScanResult existing = consolidatedScanResults.get(key);
    323 
    324             if (WifiConfigHelper.areSameNetwork(mWifiManager, result, connectedWifiInfo)) {
    325                 // The currently connected network should always be included.
    326                 consolidatedScanResults.put(key, result);
    327                 specialNetworks.put(key, true);
    328             } else {
    329                 if (existing == null ||
    330                         (!specialNetworks.containsKey(key) && existing.level < result.level)) {
    331                     consolidatedScanResults.put(key, result);
    332                 }
    333             }
    334         }
    335 
    336         ArrayList<ScanResult> networkList = new ArrayList<ScanResult>();
    337         networkList.addAll(consolidatedScanResults.values());
    338         ScanResultComparator comparator = connectedWifiInfo == null ? new ScanResultComparator() :
    339                 new ScanResultComparator(currentConnectedSSID, currentConnectedSecurity);
    340         Collections.sort(networkList, comparator);
    341         return networkList;
    342     }
    343 
    344     private int getOtherOptionsIconResourceId(int otherOptionIndex) {
    345         int resourceId = 0;
    346         switch (otherOptionIndex) {
    347             case OTHER_OPTIONS_WPS:
    348                 resourceId = R.drawable.ic_settings_wifi_wps;
    349                 break;
    350             case OTHER_OPTIONS_ADD_NETWORK:
    351                 resourceId = R.drawable.ic_settings_add;
    352                 break;
    353         }
    354         return resourceId;
    355     }
    356 
    357     private void refreshAvailableNetworksBrowseItems() {
    358         ArrayObjectAdapter row = mRows.get(FIRST_HEADER_ID);
    359         row.clear();
    360         initAvailableNetworksBrowseItems(row);
    361     }
    362 }
    363