Home | History | Annotate | Download | only in wifi
      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.settings.wifi;
     18 
     19 import android.annotation.Nullable;
     20 import android.app.Activity;
     21 import android.app.Dialog;
     22 import android.content.Context;
     23 import android.icu.text.Collator;
     24 import android.net.wifi.WifiManager;
     25 import android.os.Bundle;
     26 import android.os.Handler;
     27 import android.support.annotation.VisibleForTesting;
     28 import android.support.v7.preference.Preference;
     29 import android.support.v7.preference.PreferenceScreen;
     30 import android.util.Log;
     31 import android.widget.Toast;
     32 
     33 import com.android.internal.logging.nano.MetricsProto;
     34 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     35 import com.android.settings.R;
     36 import com.android.settings.SettingsPreferenceFragment;
     37 import com.android.settings.search.Indexable;
     38 import com.android.settingslib.wifi.AccessPoint;
     39 import com.android.settingslib.wifi.AccessPointPreference;
     40 import com.android.settingslib.wifi.WifiSavedConfigUtils;
     41 
     42 import java.util.Collections;
     43 import java.util.Comparator;
     44 import java.util.List;
     45 
     46 /**
     47  * UI to manage saved networks/access points.
     48  * TODO(b/64806699): convert to {@link DashboardFragment} with {@link PreferenceController}s
     49  */
     50 public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment
     51         implements Indexable, WifiDialog.WifiDialogListener {
     52     private static final String TAG = "SavedAccessPoints";
     53     @VisibleForTesting
     54     static final int MSG_UPDATE_PREFERENCES = 1;
     55     private static final Comparator<AccessPoint> SAVED_NETWORK_COMPARATOR =
     56             new Comparator<AccessPoint>() {
     57         final Collator mCollator = Collator.getInstance();
     58         @Override
     59         public int compare(AccessPoint ap1, AccessPoint ap2) {
     60             return mCollator.compare(
     61                     nullToEmpty(ap1.getConfigName()), nullToEmpty(ap2.getConfigName()));
     62         }
     63 
     64         private String nullToEmpty(String string) {
     65             return (string == null) ? "" : string;
     66         }
     67     };
     68 
     69     @VisibleForTesting
     70     final WifiManager.ActionListener mForgetListener = new WifiManager.ActionListener() {
     71         @Override
     72         public void onSuccess() {
     73             postUpdatePreference();
     74         }
     75 
     76         @Override
     77         public void onFailure(int reason) {
     78             postUpdatePreference();
     79         }
     80     };
     81 
     82     @VisibleForTesting
     83     final Handler mHandler = new Handler() {
     84         @Override
     85         public void handleMessage(android.os.Message msg) {
     86             if (msg.what == MSG_UPDATE_PREFERENCES) {
     87                 initPreferences();
     88             }
     89         }
     90     };
     91 
     92     private final WifiManager.ActionListener mSaveListener = new WifiManager.ActionListener() {
     93         @Override
     94         public void onSuccess() {
     95             postUpdatePreference();
     96         }
     97         @Override
     98         public void onFailure(int reason) {
     99             Activity activity = getActivity();
    100             if (activity != null) {
    101                 Toast.makeText(activity,
    102                     R.string.wifi_failed_save_message,
    103                     Toast.LENGTH_SHORT).show();
    104             }
    105         }
    106     };
    107 
    108     private WifiDialog mDialog;
    109     private WifiManager mWifiManager;
    110     private AccessPoint mDlgAccessPoint;
    111     private Bundle mAccessPointSavedState;
    112     private AccessPoint mSelectedAccessPoint;
    113     private Preference mAddNetworkPreference;
    114 
    115     private AccessPointPreference.UserBadgeCache mUserBadgeCache;
    116 
    117     // Instance state key
    118     private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state";
    119 
    120     @Override
    121     public int getMetricsCategory() {
    122         return MetricsEvent.WIFI_SAVED_ACCESS_POINTS;
    123     }
    124 
    125     @Override
    126     public void onCreate(Bundle savedInstanceState) {
    127         super.onCreate(savedInstanceState);
    128         addPreferencesFromResource(R.xml.wifi_display_saved_access_points);
    129         mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
    130     }
    131 
    132     @Override
    133     public void onResume() {
    134         super.onResume();
    135         initPreferences();
    136     }
    137 
    138     @Override
    139     public void onActivityCreated(Bundle savedInstanceState) {
    140         super.onActivityCreated(savedInstanceState);
    141         mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    142 
    143         if (savedInstanceState != null) {
    144             if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {
    145                 mAccessPointSavedState =
    146                     savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);
    147             }
    148         }
    149     }
    150 
    151     private void initPreferences() {
    152         PreferenceScreen preferenceScreen = getPreferenceScreen();
    153         final Context context = getPrefContext();
    154 
    155         final List<AccessPoint> accessPoints =
    156                 WifiSavedConfigUtils.getAllConfigs(context, mWifiManager);
    157         Collections.sort(accessPoints, SAVED_NETWORK_COMPARATOR);
    158         cacheRemoveAllPrefs(preferenceScreen);
    159 
    160         final int accessPointsSize = accessPoints.size();
    161         for (int i = 0; i < accessPointsSize; ++i) {
    162             AccessPoint ap = accessPoints.get(i);
    163             String key = ap.getKey();
    164             LongPressAccessPointPreference preference =
    165                     (LongPressAccessPointPreference) getCachedPreference(key);
    166             if (preference == null) {
    167                 preference = new LongPressAccessPointPreference(
    168                         ap, context, mUserBadgeCache, true, this);
    169                 preference.setKey(key);
    170                 preference.setIcon(null);
    171                 preferenceScreen.addPreference(preference);
    172             }
    173             preference.setOrder(i);
    174         }
    175 
    176         removeCachedPrefs(preferenceScreen);
    177 
    178         if (mAddNetworkPreference == null) {
    179             mAddNetworkPreference = new Preference(getPrefContext());
    180             mAddNetworkPreference.setIcon(R.drawable.ic_menu_add_inset);
    181             mAddNetworkPreference.setTitle(R.string.wifi_add_network);
    182         }
    183         mAddNetworkPreference.setOrder(accessPointsSize);
    184         preferenceScreen.addPreference(mAddNetworkPreference);
    185 
    186         if(getPreferenceScreen().getPreferenceCount() < 1) {
    187             Log.w(TAG, "Saved networks activity loaded, but there are no saved networks!");
    188         }
    189     }
    190 
    191     private void postUpdatePreference() {
    192         if (!mHandler.hasMessages(MSG_UPDATE_PREFERENCES)) {
    193             mHandler.sendEmptyMessage(MSG_UPDATE_PREFERENCES);
    194         }
    195     }
    196 
    197     private void showWifiDialog(@Nullable LongPressAccessPointPreference accessPoint) {
    198         if (mDialog != null) {
    199             removeDialog(WifiSettings.WIFI_DIALOG_ID);
    200             mDialog = null;
    201         }
    202 
    203         if (accessPoint != null) {
    204             // Save the access point and edit mode
    205             mDlgAccessPoint = accessPoint.getAccessPoint();
    206         } else {
    207             // No access point is selected. Clear saved state.
    208             mDlgAccessPoint = null;
    209             mAccessPointSavedState = null;
    210         }
    211 
    212         showDialog(WifiSettings.WIFI_DIALOG_ID);
    213     }
    214 
    215     @Override
    216     public Dialog onCreateDialog(int dialogId) {
    217         switch (dialogId) {
    218             case WifiSettings.WIFI_DIALOG_ID:
    219                 if (mDlgAccessPoint == null && mAccessPointSavedState == null) {
    220                     // Add new network
    221                     mDialog = WifiDialog.createFullscreen(getActivity(), this, null,
    222                             WifiConfigUiBase.MODE_CONNECT);
    223                 } else {
    224                     // Modify network
    225                     if (mDlgAccessPoint == null) {
    226                         // Restore AP from save state
    227                         mDlgAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
    228                         // Reset the saved access point data
    229                         mAccessPointSavedState = null;
    230                     }
    231                     mDialog = WifiDialog.createModal(getActivity(), this, mDlgAccessPoint,
    232                             WifiConfigUiBase.MODE_VIEW);
    233                 }
    234                 mSelectedAccessPoint = mDlgAccessPoint;
    235 
    236                 return mDialog;
    237         }
    238         return super.onCreateDialog(dialogId);
    239     }
    240 
    241     @Override
    242     public int getDialogMetricsCategory(int dialogId) {
    243         switch (dialogId) {
    244             case WifiSettings.WIFI_DIALOG_ID:
    245                 return MetricsProto.MetricsEvent.DIALOG_WIFI_SAVED_AP_EDIT;
    246             default:
    247                 return 0;
    248         }
    249     }
    250 
    251     @Override
    252     public void onSaveInstanceState(Bundle outState) {
    253         super.onSaveInstanceState(outState);
    254 
    255         // If the dialog is showing, save its state.
    256         if (mDialog != null && mDialog.isShowing()) {
    257             if (mDlgAccessPoint != null) {
    258                 mAccessPointSavedState = new Bundle();
    259                 mDlgAccessPoint.saveWifiState(mAccessPointSavedState);
    260                 outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState);
    261             }
    262         }
    263     }
    264 
    265     @Override
    266     public void onForget(WifiDialog dialog) {
    267         if (mSelectedAccessPoint != null) {
    268             if (mSelectedAccessPoint.isPasspointConfig()) {
    269                 try {
    270                     mWifiManager.removePasspointConfiguration(
    271                             mSelectedAccessPoint.getPasspointFqdn());
    272                 } catch (RuntimeException e) {
    273                     Log.e(TAG, "Failed to remove Passpoint configuration for "
    274                             + mSelectedAccessPoint.getConfigName());
    275                 }
    276                 postUpdatePreference();
    277             } else {
    278                 // mForgetListener will call initPreferences upon completion
    279                 mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, mForgetListener);
    280             }
    281             mSelectedAccessPoint = null;
    282         }
    283     }
    284 
    285     @Override
    286     public void onSubmit(WifiDialog dialog) {
    287         mWifiManager.save(dialog.getController().getConfig(), mSaveListener);
    288     }
    289 
    290     @Override
    291     public boolean onPreferenceTreeClick(Preference preference) {
    292         if (preference instanceof LongPressAccessPointPreference) {
    293             showWifiDialog((LongPressAccessPointPreference) preference);
    294             return true;
    295         } else if (preference == mAddNetworkPreference) {
    296             showWifiDialog(null);
    297             return true;
    298         } else {
    299             return super.onPreferenceTreeClick(preference);
    300         }
    301     }
    302 }
    303