/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.wifi; import android.annotation.Nullable; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.icu.text.Collator; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.util.Log; import android.widget.Toast; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.Indexable; import com.android.settingslib.wifi.AccessPoint; import com.android.settingslib.wifi.AccessPointPreference; import com.android.settingslib.wifi.WifiSavedConfigUtils; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * UI to manage saved networks/access points. * TODO(b/64806699): convert to {@link DashboardFragment} with {@link PreferenceController}s */ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment implements Indexable, WifiDialog.WifiDialogListener { private static final String TAG = "SavedAccessPoints"; @VisibleForTesting static final int MSG_UPDATE_PREFERENCES = 1; private static final Comparator SAVED_NETWORK_COMPARATOR = new Comparator() { final Collator mCollator = Collator.getInstance(); @Override public int compare(AccessPoint ap1, AccessPoint ap2) { return mCollator.compare( nullToEmpty(ap1.getConfigName()), nullToEmpty(ap2.getConfigName())); } private String nullToEmpty(String string) { return (string == null) ? "" : string; } }; @VisibleForTesting final WifiManager.ActionListener mForgetListener = new WifiManager.ActionListener() { @Override public void onSuccess() { postUpdatePreference(); } @Override public void onFailure(int reason) { postUpdatePreference(); } }; @VisibleForTesting final Handler mHandler = new Handler() { @Override public void handleMessage(android.os.Message msg) { if (msg.what == MSG_UPDATE_PREFERENCES) { initPreferences(); } } }; private final WifiManager.ActionListener mSaveListener = new WifiManager.ActionListener() { @Override public void onSuccess() { postUpdatePreference(); } @Override public void onFailure(int reason) { Activity activity = getActivity(); if (activity != null) { Toast.makeText(activity, R.string.wifi_failed_save_message, Toast.LENGTH_SHORT).show(); } } }; private WifiDialog mDialog; private WifiManager mWifiManager; private AccessPoint mDlgAccessPoint; private Bundle mAccessPointSavedState; private AccessPoint mSelectedAccessPoint; private Preference mAddNetworkPreference; private AccessPointPreference.UserBadgeCache mUserBadgeCache; // Instance state key private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state"; @Override public int getMetricsCategory() { return MetricsEvent.WIFI_SAVED_ACCESS_POINTS; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.wifi_display_saved_access_points); mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager()); } @Override public void onResume() { super.onResume(); initPreferences(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); if (savedInstanceState != null) { if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) { mAccessPointSavedState = savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE); } } } private void initPreferences() { PreferenceScreen preferenceScreen = getPreferenceScreen(); final Context context = getPrefContext(); final List accessPoints = WifiSavedConfigUtils.getAllConfigs(context, mWifiManager); Collections.sort(accessPoints, SAVED_NETWORK_COMPARATOR); cacheRemoveAllPrefs(preferenceScreen); final int accessPointsSize = accessPoints.size(); for (int i = 0; i < accessPointsSize; ++i) { AccessPoint ap = accessPoints.get(i); String key = ap.getKey(); LongPressAccessPointPreference preference = (LongPressAccessPointPreference) getCachedPreference(key); if (preference == null) { preference = new LongPressAccessPointPreference( ap, context, mUserBadgeCache, true, this); preference.setKey(key); preference.setIcon(null); preferenceScreen.addPreference(preference); } preference.setOrder(i); } removeCachedPrefs(preferenceScreen); if (mAddNetworkPreference == null) { mAddNetworkPreference = new Preference(getPrefContext()); mAddNetworkPreference.setIcon(R.drawable.ic_menu_add_inset); mAddNetworkPreference.setTitle(R.string.wifi_add_network); } mAddNetworkPreference.setOrder(accessPointsSize); preferenceScreen.addPreference(mAddNetworkPreference); if(getPreferenceScreen().getPreferenceCount() < 1) { Log.w(TAG, "Saved networks activity loaded, but there are no saved networks!"); } } private void postUpdatePreference() { if (!mHandler.hasMessages(MSG_UPDATE_PREFERENCES)) { mHandler.sendEmptyMessage(MSG_UPDATE_PREFERENCES); } } private void showWifiDialog(@Nullable LongPressAccessPointPreference accessPoint) { if (mDialog != null) { removeDialog(WifiSettings.WIFI_DIALOG_ID); mDialog = null; } if (accessPoint != null) { // Save the access point and edit mode mDlgAccessPoint = accessPoint.getAccessPoint(); } else { // No access point is selected. Clear saved state. mDlgAccessPoint = null; mAccessPointSavedState = null; } showDialog(WifiSettings.WIFI_DIALOG_ID); } @Override public Dialog onCreateDialog(int dialogId) { switch (dialogId) { case WifiSettings.WIFI_DIALOG_ID: if (mDlgAccessPoint == null && mAccessPointSavedState == null) { // Add new network mDialog = WifiDialog.createFullscreen(getActivity(), this, null, WifiConfigUiBase.MODE_CONNECT); } else { // Modify network if (mDlgAccessPoint == null) { // Restore AP from save state mDlgAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState); // Reset the saved access point data mAccessPointSavedState = null; } mDialog = WifiDialog.createModal(getActivity(), this, mDlgAccessPoint, WifiConfigUiBase.MODE_VIEW); } mSelectedAccessPoint = mDlgAccessPoint; return mDialog; } return super.onCreateDialog(dialogId); } @Override public int getDialogMetricsCategory(int dialogId) { switch (dialogId) { case WifiSettings.WIFI_DIALOG_ID: return MetricsProto.MetricsEvent.DIALOG_WIFI_SAVED_AP_EDIT; default: return 0; } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // If the dialog is showing, save its state. if (mDialog != null && mDialog.isShowing()) { if (mDlgAccessPoint != null) { mAccessPointSavedState = new Bundle(); mDlgAccessPoint.saveWifiState(mAccessPointSavedState); outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState); } } } @Override public void onForget(WifiDialog dialog) { if (mSelectedAccessPoint != null) { if (mSelectedAccessPoint.isPasspointConfig()) { try { mWifiManager.removePasspointConfiguration( mSelectedAccessPoint.getPasspointFqdn()); } catch (RuntimeException e) { Log.e(TAG, "Failed to remove Passpoint configuration for " + mSelectedAccessPoint.getConfigName()); } postUpdatePreference(); } else { // mForgetListener will call initPreferences upon completion mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, mForgetListener); } mSelectedAccessPoint = null; } } @Override public void onSubmit(WifiDialog dialog) { mWifiManager.save(dialog.getController().getConfig(), mSaveListener); } @Override public boolean onPreferenceTreeClick(Preference preference) { if (preference instanceof LongPressAccessPointPreference) { showWifiDialog((LongPressAccessPointPreference) preference); return true; } else if (preference == mAddNetworkPreference) { showWifiDialog(null); return true; } else { return super.onPreferenceTreeClick(preference); } } }