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