diff --git a/src/com/android/settings/wifi/ConfigureWifiEntryFragment.java b/src/com/android/settings/wifi/ConfigureWifiEntryFragment.java new file mode 100644 index 00000000000..a28f9907d6b --- /dev/null +++ b/src/com/android/settings/wifi/ConfigureWifiEntryFragment.java @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2019 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.app.ActionBar; +import android.app.Activity; +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkScoreManager; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Process; +import android.os.SimpleClock; +import android.os.SystemClock; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +import androidx.annotation.VisibleForTesting; + +import com.android.settings.R; +import com.android.settings.core.InstrumentedFragment; +import com.android.settings.wifi.details2.WifiNetworkDetailsFragment2; +import com.android.wifitrackerlib.NetworkDetailsTracker; +import com.android.wifitrackerlib.WifiEntry; + +import java.time.Clock; +import java.time.ZoneOffset; + +/** + * Detail page for configuring Wi-Fi network. + * + * The WifiEntry should be saved to the argument when launching this class in order to properly + * render this page. + */ +public class ConfigureWifiEntryFragment extends InstrumentedFragment implements WifiConfigUiBase2 { + + private static final String TAG = "ConfigureWifiEntryFragment"; + + public static final String NETWORK_CONFIG_KEY = "network_config_key"; + + private static final int SUBMIT_BUTTON_ID = android.R.id.button1; + private static final int CANCEL_BUTTON_ID = android.R.id.button2; + + // Max age of tracked WifiEntries + private static final long MAX_SCAN_AGE_MILLIS = 15_000; + // Interval between initiating SavedNetworkTracker scans + private static final long SCAN_INTERVAL_MILLIS = 10_000; + + private WifiConfigController2 mUiController; + private Button mSubmitBtn; + private Button mCancelBtn; + private WifiEntry mWifiEntry; + private NetworkDetailsTracker mNetworkDetailsTracker; + private HandlerThread mWorkerThread; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + + setupNetworkDetailsTracker(); + mWifiEntry = mNetworkDetailsTracker.getWifiEntry(); + } + + @Override + public void onDestroy() { + if (mWorkerThread != null) { + mWorkerThread.quit(); + } + + super.onDestroy(); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.SETTINGS_WIFI_CONFIGURE_NETWORK; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + final View rootView = inflater.inflate(R.layout.wifi_add_network_view, + container, false /* attachToRoot */); + + final Button neutral = rootView.findViewById(android.R.id.button3); + if (neutral != null) { + neutral.setVisibility(View.GONE); + } + + mSubmitBtn = rootView.findViewById(SUBMIT_BUTTON_ID); + mCancelBtn = rootView.findViewById(CANCEL_BUTTON_ID); + mSubmitBtn.setOnClickListener(view -> handleSubmitAction()); + mCancelBtn.setOnClickListener(view -> handleCancelAction()); + + mUiController = new WifiConfigController2(this, rootView, mWifiEntry, + getMode(), false /* requestFocus */); + + /** + * For this add WifiEntry UI, need to remove the Home button, so set related feature as + * false. + */ + final ActionBar actionBar = getActivity().getActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(false); + actionBar.setHomeButtonEnabled(false); + actionBar.setDisplayShowHomeEnabled(false); + } + + return rootView; + } + + @Override + public void onViewStateRestored(Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + mUiController.updatePassword(); + } + + @Override + public int getMode() { + return WifiConfigUiBase2.MODE_CONNECT; + } + + @Override + public WifiConfigController2 getController() { + return mUiController; + } + + @Override + public void dispatchSubmit() { + // Do nothing + } + + @Override + public void setTitle(int id) { + getActivity().setTitle(id); + } + + @Override + public void setTitle(CharSequence title) { + getActivity().setTitle(title); + } + + @Override + public void setSubmitButton(CharSequence text) { + mSubmitBtn.setText(text); + } + + @Override + public void setCancelButton(CharSequence text) { + mCancelBtn.setText(text); + } + + @Override + public void setForgetButton(CharSequence text) { + // AddNetwork doesn't need forget button. + } + + @Override + public Button getSubmitButton() { + return mSubmitBtn; + } + + @Override + public Button getCancelButton() { + return mCancelBtn; + } + + @Override + public Button getForgetButton() { + // AddNetwork doesn't need forget button. + return null; + } + + @VisibleForTesting + void handleSubmitAction() { + final Intent intent = new Intent(); + final Activity activity = getActivity(); + intent.putExtra(NETWORK_CONFIG_KEY, mUiController.getConfig()); + activity.setResult(Activity.RESULT_OK, intent); + activity.finish(); + } + + @VisibleForTesting + void handleCancelAction() { + getActivity().finish(); + } + + private void setupNetworkDetailsTracker() { + if (mNetworkDetailsTracker != null) { + return; + } + + final Context context = getContext(); + mWorkerThread = new HandlerThread(TAG + + "{" + Integer.toHexString(System.identityHashCode(this)) + "}", + Process.THREAD_PRIORITY_BACKGROUND); + mWorkerThread.start(); + final Clock elapsedRealtimeClock = new SimpleClock(ZoneOffset.UTC) { + @Override + public long millis() { + return SystemClock.elapsedRealtime(); + } + }; + + mNetworkDetailsTracker = NetworkDetailsTracker.createNetworkDetailsTracker( + getSettingsLifecycle(), + context, + context.getSystemService(WifiManager.class), + context.getSystemService(ConnectivityManager.class), + context.getSystemService(NetworkScoreManager.class), + new Handler(Looper.getMainLooper()), + mWorkerThread.getThreadHandler(), + elapsedRealtimeClock, + MAX_SCAN_AGE_MILLIS, + SCAN_INTERVAL_MILLIS, + getArguments().getString(WifiNetworkDetailsFragment2.KEY_CHOSEN_WIFIENTRY_KEY)); + } +} diff --git a/src/com/android/settings/wifi/WifiEntryShell.java b/src/com/android/settings/wifi/WifiEntryShell.java index 977059def89..781bc843c4e 100644 --- a/src/com/android/settings/wifi/WifiEntryShell.java +++ b/src/com/android/settings/wifi/WifiEntryShell.java @@ -16,6 +16,8 @@ package com.android.settings.wifi; +import android.net.wifi.WifiConfiguration; + import com.android.wifitrackerlib.WifiEntry; /** diff --git a/src/com/android/settings/wifi/WifiSettings2.java b/src/com/android/settings/wifi/WifiSettings2.java index ac9374fcd71..ac5e31cd5f4 100644 --- a/src/com/android/settings/wifi/WifiSettings2.java +++ b/src/com/android/settings/wifi/WifiSettings2.java @@ -19,9 +19,11 @@ package com.android.settings.wifi; import static android.os.UserManager.DISALLOW_CONFIG_WIFI; import android.app.Activity; +import android.app.Dialog; import android.app.settings.SettingsEnums; import android.content.ContentResolver; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.net.ConnectivityManager; @@ -38,10 +40,12 @@ import android.os.Process; import android.os.SimpleClock; import android.os.SystemClock; import android.provider.Settings; +import android.text.TextUtils; import android.util.FeatureFlagUtils; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; +import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; @@ -64,27 +68,45 @@ import com.android.settings.location.ScanningSettings; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.widget.SwitchBarController; import com.android.settings.wifi.details2.WifiNetworkDetailsFragment2; +import com.android.settings.wifi.dpp.WifiDppUtils; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.search.Indexable; import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.wifi.LongPressWifiEntryPreference; import com.android.wifitrackerlib.WifiEntry; +import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback; +import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback.ConnectStatus; +import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback.DisconnectStatus; +import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback.ForgetStatus; +import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback.SignInStatus; import com.android.wifitrackerlib.WifiPickerTracker; import java.time.Clock; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** * UI for Wi-Fi settings screen */ @SearchIndexable public class WifiSettings2 extends RestrictedSettingsFragment - implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback { + implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback, + WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener { private static final String TAG = "WifiSettings2"; + // IDs of context menu + static final int MENU_ID_CONNECT = Menu.FIRST + 1; + @VisibleForTesting + static final int MENU_ID_DISCONNECT = Menu.FIRST + 2; + @VisibleForTesting + static final int MENU_ID_FORGET = Menu.FIRST + 3; + static final int MENU_ID_MODIFY = Menu.FIRST + 4; + // Max age of tracked WifiEntries private static final long MAX_SCAN_AGE_MILLIS = 15_000; // Interval between initiating WifiPickerTracker scans @@ -92,6 +114,7 @@ public class WifiSettings2 extends RestrictedSettingsFragment @VisibleForTesting static final int ADD_NETWORK_REQUEST = 2; + static final int CONFIG_NETWORK_REQUEST = 3; private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list"; // TODO(b/70983952): Rename these to use WifiEntry instead of AccessPoint. @@ -105,6 +128,20 @@ public class WifiSettings2 extends RestrictedSettingsFragment private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0; + public static final int WIFI_DIALOG_ID = 1; + + // Instance state keys + private static final String SAVE_DIALOG_MODE = "dialog_mode"; + private static final String SAVE_DIALOG_WIFIENTRY_KEY = "wifi_ap_key"; + + // Cache at onCreateContextMenu and use at onContextItemSelected. Don't use it in other methods. + private WifiEntry mSelectedWifiEntry; + + // Save the dialog details + private int mDialogMode; + private String mDialogWifiEntryKey; + private WifiEntry mDialogWifiEntry; + private static boolean isVerboseLoggingEnabled() { return WifiPickerTracker.isVerboseLoggingEnabled(); } @@ -136,7 +173,7 @@ public class WifiSettings2 extends RestrictedSettingsFragment @VisibleForTesting WifiPickerTracker mWifiPickerTracker; - private WifiDialog mDialog; + private WifiDialog2 mDialog; private View mProgressHeader; @@ -275,6 +312,23 @@ public class WifiSettings2 extends RestrictedSettingsFragment }; registerForContextMenu(getListView()); setHasOptionsMenu(true); + + if (savedInstanceState != null) { + mDialogMode = savedInstanceState.getInt(SAVE_DIALOG_MODE); + mDialogWifiEntryKey = savedInstanceState.getString(SAVE_DIALOG_WIFIENTRY_KEY); + + if (!TextUtils.isEmpty(mDialogWifiEntryKey)) { + List wifiEntries = mWifiPickerTracker.getWifiEntries(); + Optional matchedWifiEntry = wifiEntries.stream().filter(wifiEntry -> + TextUtils.equals(wifiEntry.getKey(), mDialogWifiEntryKey)).findAny(); + if (matchedWifiEntry.isPresent()) { + mDialogWifiEntry = matchedWifiEntry.get(); + } else { + throw new IllegalStateException("Failed to restore WifiEntry of key: " + + mDialogWifiEntryKey); + } + } + } } @Override @@ -283,7 +337,7 @@ public class WifiSettings2 extends RestrictedSettingsFragment mWifiEnabler.teardownSwitchController(); } mWorkerThread.quit(); - + super.onDestroyView(); } @@ -361,6 +415,16 @@ public class WifiSettings2 extends RestrictedSettingsFragment } } return; + } else if (requestCode == CONFIG_NETWORK_REQUEST) { + if (resultCode == Activity.RESULT_OK) { + final WifiConfiguration wifiConfiguration = data.getParcelableExtra( + ConfigureWifiEntryFragment.NETWORK_CONFIG_KEY); + if (wifiConfiguration != null) { + mWifiManager.save(wifiConfiguration, + new WifiSaveThenConnectActionListener(wifiConfiguration)); + } + } + return; } final boolean formerlyRestricted = mIsRestricted; @@ -384,17 +448,73 @@ public class WifiSettings2 extends RestrictedSettingsFragment return SettingsEnums.WIFI; } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // If dialog has been shown, save its state. + if (mDialog != null) { + outState.putInt(SAVE_DIALOG_MODE, mDialogMode); + outState.putString(SAVE_DIALOG_WIFIENTRY_KEY, mDialogWifiEntryKey); + } + } + @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { - // TODO(b/70983952): Add context menu options here. This should be driven by the appropriate - // "can do action" APIs from WifiEntry. + Preference preference = (Preference) view.getTag(); + if (!(preference instanceof LongPressWifiEntryPreference)) { + // Do nothing. + return; + } + + // Cache the WifiEntry for onContextItemSelected. Don't use it in other methods. + mSelectedWifiEntry = ((LongPressWifiEntryPreference) preference).getWifiEntry(); + + menu.setHeaderTitle(mSelectedWifiEntry.getTitle()); + if (mSelectedWifiEntry.canConnect()) { + menu.add(Menu.NONE, MENU_ID_CONNECT, 0 /* order */, R.string.wifi_connect); + } + + if (mSelectedWifiEntry.canDisconnect()) { + menu.add(Menu.NONE, MENU_ID_DISCONNECT, 0 /* order */, + R.string.wifi_disconnect_button_text); + } + + // "forget" for normal saved network. And "disconnect" for ephemeral network because it + // could only be disconnected and be put in blacklists so it won't be used again. + if (mSelectedWifiEntry.canForget()) { + menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, R.string.forget); + } + + WifiConfiguration config = mSelectedWifiEntry.getWifiConfiguration(); + // Some configs are ineditable + if (WifiUtils.isNetworkLockedDown(getActivity(), config)) { + return; + } + + if (mSelectedWifiEntry.isSaved() && mSelectedWifiEntry.getConnectedState() + != WifiEntry.CONNECTED_STATE_CONNECTED) { + menu.add(Menu.NONE, MENU_ID_MODIFY, 0 /* order */, R.string.wifi_modify); + } } @Override public boolean onContextItemSelected(MenuItem item) { - // TODO(b/70983952): Add context menu selection logic here. This should simply call the - // appropriate WifiEntry action APIs (connect, forget, disconnect, etc). - return false; + switch (item.getItemId()) { + case MENU_ID_CONNECT: + connect(mSelectedWifiEntry, true /* editIfNoConfig */, false /* fullScreenEdit */); + return true; + case MENU_ID_DISCONNECT: + mSelectedWifiEntry.disconnect(); + return true; + case MENU_ID_FORGET: + forget(mSelectedWifiEntry); + return true; + case MENU_ID_MODIFY: + showDialog(mSelectedWifiEntry, WifiConfigUiBase2.MODE_MODIFY); + return true; + default: + return super.onContextItemSelected(item); + } } @Override @@ -405,12 +525,10 @@ public class WifiSettings2 extends RestrictedSettingsFragment return super.onPreferenceTreeClick(preference); } - // TODO(b/70983952) Add WifiEntry click logic. This should be as simple as calling - // WifiEntry.connect(). if (preference instanceof LongPressWifiEntryPreference) { final WifiEntry selectedEntry = ((LongPressWifiEntryPreference) preference).getWifiEntry(); - selectedEntry.connect(); + connect(selectedEntry, true /* editIfNoConfig */, true /* fullScreenEdit */); } else if (preference == mAddWifiNetworkPreference) { onAddNetworkPressed(); } else { @@ -419,6 +537,54 @@ public class WifiSettings2 extends RestrictedSettingsFragment return true; } + private void showDialog(WifiEntry wifiEntry, int dialogMode) { + if (WifiUtils.isNetworkLockedDown(getActivity(), wifiEntry.getWifiConfiguration()) + && wifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) { + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), + RestrictedLockUtilsInternal.getDeviceOwner(getActivity())); + return; + } + + if (mDialog != null) { + removeDialog(WIFI_DIALOG_ID); + mDialog = null; + } + + // Save the access point and edit mode + mDialogWifiEntry = wifiEntry; + mDialogWifiEntryKey = wifiEntry.getKey(); + mDialogMode = dialogMode; + + showDialog(WIFI_DIALOG_ID); + } + + @Override + public Dialog onCreateDialog(int dialogId) { + switch (dialogId) { + case WIFI_DIALOG_ID: + // modify network + mDialog = WifiDialog2 + .createModal(getActivity(), this, mDialogWifiEntry, mDialogMode); + return mDialog; + default: + return super.onCreateDialog(dialogId); + } + } + + @Override + public void onDialogShowing() { + super.onDialogShowing(); + setOnDismissListener(this); + } + + @Override + public void onDismiss(DialogInterface dialog) { + // We don't keep any dialog object when dialog was dismissed. + mDialog = null; + mDialogWifiEntry = null; + mDialogWifiEntryKey = null; + } + /** Called when the state of Wifi has changed. */ @Override public void onWifiStateChanged() { @@ -584,7 +750,8 @@ public class WifiSettings2 extends RestrictedSettingsFragment .launch(); } - private LongPressWifiEntryPreference createLongPressWifiEntryPreference(WifiEntry wifiEntry) { + @VisibleForTesting + LongPressWifiEntryPreference createLongPressWifiEntryPreference(WifiEntry wifiEntry) { return new LongPressWifiEntryPreference(getPrefContext(), wifiEntry, this); } @@ -715,6 +882,88 @@ public class WifiSettings2 extends RestrictedSettingsFragment return R.string.help_url_wifi; } + @Override + public void onForget(WifiDialog2 dialog) { + forget(mDialogWifiEntry); + } + + @Override + public void onSubmit(WifiDialog2 dialog) { + final int dialogMode = mDialog.getController().getMode(); + + if (dialogMode == WifiConfigUiBase2.MODE_MODIFY) { + mWifiManager.save(mDialogWifiEntry.getWifiConfiguration(), mSaveListener); + } else if (dialogMode == WifiConfigUiBase2.MODE_CONNECT + || (dialogMode == WifiConfigUiBase2.MODE_VIEW && mDialogWifiEntry.canConnect())) { + connect(mDialogWifiEntry, false /* editIfNoConfig */, false /* fullScreenEdit*/); + } + } + + @Override + public void onScan(WifiDialog2 dialog, String ssid) { + // Launch QR code scanner to join a network. + startActivityForResult(WifiDppUtils.getEnrolleeQrCodeScannerIntent(ssid), + REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER); + } + + private void forget(WifiEntry wifiEntry) { + mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_FORGET); + wifiEntry.forget(); + } + + private void connect(WifiEntry wifiEntry, boolean editIfNoConfig, boolean fullScreenEdit) { + mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_CONNECT, + wifiEntry.isSaved()); + + // If it's an unsaved secure WifiEntry, it will callback + // WifiEntryCallback#onConnectResult with + // WifiEntryCallback#CONNECT_STATUS_FAILURE_NO_CONFIG + wifiEntry.setListener(new WifiEntryConnectCallback(wifiEntry, editIfNoConfig, + fullScreenEdit)); + wifiEntry.connect(); + } + + private class WifiSaveThenConnectActionListener implements WifiManager.ActionListener { + final WifiConfiguration mWifiConfiguration; + + WifiSaveThenConnectActionListener(WifiConfiguration wifiConfiguration) { + mWifiConfiguration = wifiConfiguration; + } + + @Override + public void onSuccess() { + mWifiManager.connect(mWifiConfiguration, new WifiConnectActionListener()); + } + + @Override + public void onFailure(int reason) { + final Activity activity = getActivity(); + if (isFisishingOrDestroyed(activity)) { + return; + } + + Toast.makeText(activity, R.string.wifi_failed_save_message, Toast.LENGTH_SHORT).show(); + } + }; + + private class WifiConnectActionListener implements WifiManager.ActionListener { + @Override + public void onSuccess() { + // Do nothing. + } + + @Override + public void onFailure(int reason) { + final Activity activity = getActivity(); + if (isFisishingOrDestroyed(activity)) { + return; + } + + Toast.makeText(activity, R.string.wifi_failed_connect_message, Toast.LENGTH_SHORT) + .show(); + } + }; + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { @Override @@ -736,4 +985,72 @@ public class WifiSettings2 extends RestrictedSettingsFragment return result; } }; + + private class WifiEntryConnectCallback implements WifiEntryCallback { + final WifiEntry mConnectWifiEntry; + final boolean mEditIfNoConfig; + final boolean mFullScreenEdit; + + WifiEntryConnectCallback(WifiEntry connectWifiEntry, boolean editIfNoConfig, + boolean fullScreenEdit) { + mConnectWifiEntry = connectWifiEntry; + mEditIfNoConfig = editIfNoConfig; + mFullScreenEdit = fullScreenEdit; + } + + @Override + public void onUpdated() { + // Do nothing. + } + + @Override + public void onConnectResult(@ConnectStatus int status) { + final Activity activity = getActivity(); + if (isFisishingOrDestroyed(activity)) { + return; + } + + if (status == WifiEntryCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) { + if (mEditIfNoConfig) { + // Edit an unsaved secure Wi-Fi network. + if (mFullScreenEdit) { + final Bundle bundle = new Bundle(); + bundle.putString(WifiNetworkDetailsFragment2.KEY_CHOSEN_WIFIENTRY_KEY, + mConnectWifiEntry.getKey()); + new SubSettingLauncher(getContext()) + .setTitleText(mConnectWifiEntry.getTitle()) + .setDestination(ConfigureWifiEntryFragment.class.getName()) + .setArguments(bundle) + .setSourceMetricsCategory(getMetricsCategory()) + .setResultListener(WifiSettings2.this, CONFIG_NETWORK_REQUEST) + .launch(); + } else { + showDialog(mConnectWifiEntry, WifiConfigUiBase2.MODE_MODIFY); + } + } + } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) { + Toast.makeText(getContext(), R.string.wifi_failed_connect_message, + Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onDisconnectResult(@DisconnectStatus int status) { + // Do nothing. + } + + @Override + public void onForgetResult(@ForgetStatus int status) { + // Do nothing. + } + + @Override + public void onSignInResult(@SignInStatus int status) { + // Do nothing. + } + } + + private boolean isFisishingOrDestroyed(Activity activity) { + return activity == null || activity.isFinishing() || activity.isDestroyed(); + } } diff --git a/tests/robotests/src/com/android/settings/wifi/ConfigureWifiEntryFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/ConfigureWifiEntryFragmentTest.java new file mode 100644 index 00000000000..1f0c3127d55 --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/ConfigureWifiEntryFragmentTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2019 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 static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.app.settings.SettingsEnums; +import android.os.Bundle; + +import com.android.settings.testutils.shadow.ShadowConnectivityManager; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.androidx.fragment.FragmentController; + +// TODO(b/70983952): Can't test because b/146802959, should remove @Ignore tag after it's fixed. +@Ignore +@RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowConnectivityManager.class) +public class ConfigureWifiEntryFragmentTest { + + private static final String KEY_SSID = "key_ssid"; + private static final String KEY_SECURITY = "key_security"; + + private ConfigureWifiEntryFragment mConfigureWifiEntryFragment; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + Bundle bundle = new Bundle(); + + bundle.putString(KEY_SSID, "Test AP"); + bundle.putInt(KEY_SECURITY, 1 /* WEP */); + mConfigureWifiEntryFragment = spy(new ConfigureWifiEntryFragment()); + mConfigureWifiEntryFragment.setArguments(bundle); + FragmentController.setupFragment(mConfigureWifiEntryFragment); + } + + @Test + public void getMetricsCategory_shouldReturnConfigureNetwork() { + assertThat(mConfigureWifiEntryFragment.getMetricsCategory()).isEqualTo( + SettingsEnums.SETTINGS_WIFI_CONFIGURE_NETWORK); + } + + @Test + public void getMode_shouldBeModeConnected() { + assertThat(mConfigureWifiEntryFragment.getMode()).isEqualTo( + WifiConfigUiBase.MODE_CONNECT); + } + + @Test + public void launchFragment_shouldShowSubmitButton() { + assertThat(mConfigureWifiEntryFragment.getSubmitButton()).isNotNull(); + } + + @Test + public void launchFragment_shouldShowCancelButton() { + assertThat(mConfigureWifiEntryFragment.getCancelButton()).isNotNull(); + } + + @Test + public void onClickSubmitButton_shouldHandleSubmitAction() { + mConfigureWifiEntryFragment.getSubmitButton().performClick(); + + verify(mConfigureWifiEntryFragment).handleSubmitAction(); + } + + @Test + public void onClickCancelButton_shouldHandleCancelAction() { + mConfigureWifiEntryFragment.getCancelButton().performClick(); + + verify(mConfigureWifiEntryFragment).handleCancelAction(); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSettings2Test.java b/tests/robotests/src/com/android/settings/wifi/WifiSettings2Test.java index d523866a987..aeec19abd0a 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiSettings2Test.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiSettings2Test.java @@ -36,6 +36,8 @@ import android.os.Bundle; import android.os.PowerManager; import android.os.UserManager; import android.provider.Settings; +import android.view.ContextMenu; +import android.view.View; import androidx.fragment.app.FragmentActivity; import androidx.preference.Preference; @@ -47,9 +49,12 @@ import com.android.settings.datausage.DataUsagePreference; import com.android.settings.testutils.shadow.ShadowDataUsageUtils; import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settingslib.search.SearchIndexableRaw; +import com.android.settingslib.wifi.LongPressWifiEntryPreference; +import com.android.wifitrackerlib.WifiEntry; import com.android.wifitrackerlib.WifiPickerTracker; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -249,26 +254,28 @@ public class WifiSettings2Test { assertThat(adapter.hasStableIds()).isTrue(); } -// TODO(b/70983952): Add test for context menu -// @Test -// public void onCreateContextMenu_shouldHaveForgetMenuForConnectedAccessPreference() { -// final FragmentActivity mockActivity = mock(FragmentActivity.class); -// when(mockActivity.getApplicationContext()).thenReturn(mContext); -// when(mWifiSettings2.getActivity()).thenReturn(mockActivity); -// -// final AccessPoint accessPoint = mock(AccessPoint.class); -// when(accessPoint.isConnectable()).thenReturn(false); -// when(accessPoint.isSaved()).thenReturn(true); -// when(accessPoint.isActive()).thenReturn(true); -// -// final ConnectedAccessPointPreference connectedPreference = -// mWifiSettings2.createConnectedAccessPointPreference(accessPoint, mContext); -// final View view = mock(View.class); -// when(view.getTag()).thenReturn(connectedPreference); -// -// final ContextMenu menu = mock(ContextMenu.class); -// mWifiSettings2.onCreateContextMenu(menu, view, null /* info */); -// -// verify(menu).add(anyInt(), eq(WifiSettings.MENU_ID_FORGET), anyInt(), anyInt()); -// } + //TODO(b/70983952): Remove @Ignore when WifiEntry API is constructed. + @Test + @Ignore + public void onCreateContextMenu_shouldHaveForgetAndDisconnectMenuForConnectedWifiEntry() { + final FragmentActivity activity = mock(FragmentActivity.class); + when(activity.getApplicationContext()).thenReturn(mContext); + when(mWifiSettings2.getActivity()).thenReturn(activity); + + final WifiEntry wifiEntry = mock(WifiEntry.class); + when(wifiEntry.canDisconnect()).thenReturn(true); + when(wifiEntry.isSaved()).thenReturn(true); + when(wifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED); + + final LongPressWifiEntryPreference connectedWifiEntryPreference = + mWifiSettings2.createLongPressWifiEntryPreference(wifiEntry); + final View view = mock(View.class); + when(view.getTag()).thenReturn(connectedWifiEntryPreference); + + final ContextMenu menu = mock(ContextMenu.class); + mWifiSettings2.onCreateContextMenu(menu, view, null /* info */); + + verify(menu).add(anyInt(), eq(WifiSettings2.MENU_ID_FORGET), anyInt(), anyInt()); + verify(menu).add(anyInt(), eq(WifiSettings2.MENU_ID_DISCONNECT), anyInt(), anyInt()); + } }