Merge "Refactor hotspot into a full page"

This commit is contained in:
TreeHugger Robot
2017-06-14 21:33:19 +00:00
committed by Android (Google) Code Review
25 changed files with 1820 additions and 18 deletions

View File

@@ -17,10 +17,16 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"> xmlns:settings="http://schemas.android.com/apk/res-auto">
<Preference
android:key="wifi_tether"
android:title="@string/wifi_tether_checkbox_text"
android:summary="@string/summary_placeholder"
android:fragment="com.android.settings.wifi.tether.WifiTetherSettings" />
<SwitchPreference <SwitchPreference
android:key="usb_tether_settings" android:key="usb_tether_settings"
android:title="@string/usb_tethering_button_text" android:title="@string/usb_tethering_button_text"
android:summary="@string/usb_tethering_subtext"/> android:summary="@string/usb_tethering_subtext" />
<SwitchPreference <SwitchPreference
android:key="enable_wifi_ap" android:key="enable_wifi_ap"
@@ -35,7 +41,7 @@
<SwitchPreference <SwitchPreference
android:key="enable_bluetooth_tethering" android:key="enable_bluetooth_tethering"
android:title="@string/bluetooth_tether_checkbox_text" android:title="@string/bluetooth_tether_checkbox_text"
android:summary="@string/bluetooth_tethering_subtext"/> android:summary="@string/bluetooth_tethering_subtext" />
<Preference <Preference
android:key="disabled_on_data_saver" android:key="disabled_on_data_saver"

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<com.android.settings.widget.ValidatedEditTextPreference
android:key="wifi_tether_network_name"
android:title="@string/wifi_ssid"
android:summary="@string/summary_placeholder" />
<com.android.settings.widget.ValidatedEditTextPreference
android:key="wifi_tether_network_password"
android:title="@string/wifi_password" />
<ListPreference
android:key="wifi_tether_network_ap_band"
android:title="@string/wifi_ap_band_config"
android:summary="@string/summary_placeholder" />
</PreferenceScreen>

View File

@@ -43,6 +43,8 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.datausage.DataSaverBackend; import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.wifi.WifiApDialog; import com.android.settings.wifi.WifiApDialog;
import com.android.settings.wifi.WifiApEnabler; import com.android.settings.wifi.WifiApEnabler;
import com.android.settings.wifi.tether.WifiTetherPreferenceController;
import com.android.settings.wifi.tether.WifiTetherSettings;
import com.android.settingslib.TetherUtil; import com.android.settingslib.TetherUtil;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@@ -63,7 +65,6 @@ public class TetherSettings extends RestrictedSettingsFragment
private static final String USB_TETHER_SETTINGS = "usb_tether_settings"; private static final String USB_TETHER_SETTINGS = "usb_tether_settings";
private static final String ENABLE_WIFI_AP = "enable_wifi_ap"; private static final String ENABLE_WIFI_AP = "enable_wifi_ap";
private static final String ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering"; private static final String ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering";
private static final String TETHER_CHOICE = "TETHER_TYPE";
private static final String DATA_SAVER_FOOTER = "disabled_on_data_saver"; private static final String DATA_SAVER_FOOTER = "disabled_on_data_saver";
private static final int DIALOG_AP_SETTINGS = 1; private static final int DIALOG_AP_SETTINGS = 1;
@@ -100,17 +101,14 @@ public class TetherSettings extends RestrictedSettingsFragment
private WifiConfiguration mWifiConfig = null; private WifiConfiguration mWifiConfig = null;
private ConnectivityManager mCm; private ConnectivityManager mCm;
private WifiTetherPreferenceController mWifiTetherPreferenceController;
private boolean mRestartWifiApAfterConfigChange; private boolean mRestartWifiApAfterConfigChange;
private boolean mUsbConnected; private boolean mUsbConnected;
private boolean mMassStorageActive; private boolean mMassStorageActive;
private boolean mBluetoothEnableForTether; private boolean mBluetoothEnableForTether;
/* Stores the package name and the class name of the provisioning app */
private String[] mProvisionApp;
private static final int PROVISION_REQUEST = 0;
private boolean mUnavailable; private boolean mUnavailable;
private DataSaverBackend mDataSaverBackend; private DataSaverBackend mDataSaverBackend;
@@ -126,6 +124,13 @@ public class TetherSettings extends RestrictedSettingsFragment
super(UserManager.DISALLOW_CONFIG_TETHERING); super(UserManager.DISALLOW_CONFIG_TETHERING);
} }
@Override
public void onAttach(Context context) {
super.onAttach(context);
mWifiTetherPreferenceController =
new WifiTetherPreferenceController(context, getLifecycle());
}
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
@@ -154,6 +159,7 @@ public class TetherSettings extends RestrictedSettingsFragment
mEnableWifiAp = mEnableWifiAp =
(SwitchPreference) findPreference(ENABLE_WIFI_AP); (SwitchPreference) findPreference(ENABLE_WIFI_AP);
Preference wifiApSettings = findPreference(WIFI_AP_SSID_AND_SECURITY); Preference wifiApSettings = findPreference(WIFI_AP_SSID_AND_SECURITY);
mUsbTether = (SwitchPreference) findPreference(USB_TETHER_SETTINGS); mUsbTether = (SwitchPreference) findPreference(USB_TETHER_SETTINGS);
mBluetoothTether = (SwitchPreference) findPreference(ENABLE_BLUETOOTH_TETHERING); mBluetoothTether = (SwitchPreference) findPreference(ENABLE_BLUETOOTH_TETHERING);
@@ -175,12 +181,18 @@ public class TetherSettings extends RestrictedSettingsFragment
getPreferenceScreen().removePreference(mUsbTether); getPreferenceScreen().removePreference(mUsbTether);
} }
if (wifiAvailable && !Utils.isMonkeyRunning()) { mWifiTetherPreferenceController.displayPreference(getPreferenceScreen());
mWifiApEnabler = new WifiApEnabler(activity, mDataSaverBackend, mEnableWifiAp); if (WifiTetherSettings.isTetherSettingPageEnabled()) {
initWifiTethering(); removePreference(ENABLE_WIFI_AP);
removePreference(WIFI_AP_SSID_AND_SECURITY);
} else { } else {
getPreferenceScreen().removePreference(mEnableWifiAp); if (wifiAvailable && !Utils.isMonkeyRunning()) {
getPreferenceScreen().removePreference(wifiApSettings); mWifiApEnabler = new WifiApEnabler(activity, mDataSaverBackend, mEnableWifiAp);
initWifiTethering();
} else {
getPreferenceScreen().removePreference(mEnableWifiAp);
getPreferenceScreen().removePreference(wifiApSettings);
}
} }
if (!bluetoothAvailable) { if (!bluetoothAvailable) {

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2017 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.widget;
import android.app.AlertDialog;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
import com.android.settings.CustomEditTextPreference;
/**
* {@code EditTextPreference} that supports input validation.
*/
public class ValidatedEditTextPreference extends CustomEditTextPreference {
public interface Validator {
boolean isTextValid(String value);
}
private final EditTextWatcher mTextWatcher = new EditTextWatcher();
private Validator mValidator;
private boolean mIsPassword;
public ValidatedEditTextPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public ValidatedEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ValidatedEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ValidatedEditTextPreference(Context context) {
super(context);
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
if (mValidator != null) {
final EditText editText = view.findViewById(android.R.id.edit);
if (editText != null) {
editText.removeTextChangedListener(mTextWatcher);
if (mIsPassword) {
editText.setInputType(
InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
editText.setMaxLines(1);
}
editText.addTextChangedListener(mTextWatcher);
}
}
}
public void setIsPassword(boolean isPassword) {
mIsPassword = isPassword;
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
public boolean isPassword() {
return mIsPassword;
}
public void setValidator(Validator validator) {
mValidator = validator;
}
private class EditTextWatcher implements TextWatcher {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
final EditText editText = getEditText();
if (mValidator != null && editText != null) {
final AlertDialog dialog = (AlertDialog) getDialog();
final boolean valid = mValidator.isTextValid(editText.getText().toString());
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(valid);
}
}
}
}

View File

@@ -32,6 +32,10 @@ import com.android.settings.datausage.DataSaverBackend;
import java.util.ArrayList; import java.util.ArrayList;
/**
* @deprecated in favor of WifiTetherPreferenceController and WifiTetherSettings
*/
@Deprecated
public class WifiApEnabler { public class WifiApEnabler {
private final Context mContext; private final Context mContext;
private final SwitchPreference mSwitch; private final SwitchPreference mSwitch;

View File

@@ -110,7 +110,6 @@ public class WifiConfigController implements TextWatcher,
public static final int WIFI_PEAP_PHASE2_AKA = 4; public static final int WIFI_PEAP_PHASE2_AKA = 4;
public static final int WIFI_PEAP_PHASE2_AKA_PRIME = 5; public static final int WIFI_PEAP_PHASE2_AKA_PRIME = 5;
private static final int SSID_ASCII_MAX_LENGTH = 32;
/* Phase2 methods supported by PEAP are limited */ /* Phase2 methods supported by PEAP are limited */
private final ArrayAdapter<String> mPhase2PeapAdapter; private final ArrayAdapter<String> mPhase2PeapAdapter;
@@ -463,7 +462,7 @@ public class WifiConfigController implements TextWatcher,
if (mSsidView != null) { if (mSsidView != null) {
final String ssid = mSsidView.getText().toString(); final String ssid = mSsidView.getText().toString();
if (ssid.length() > SSID_ASCII_MAX_LENGTH) { if (WifiUtils.isSSIDTooLong(ssid)) {
mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE); mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE);
} }
} }

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2017 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.text.TextUtils;
public class WifiUtils {
private static final int SSID_ASCII_MIN_LENGTH = 1;
private static final int SSID_ASCII_MAX_LENGTH = 32;
private static final int PASSWORD_MIN_LENGTH = 8;
private static final int PASSWORD_MAX_LENGTH = 63;
public static boolean isSSIDTooLong(String ssid) {
if (TextUtils.isEmpty(ssid)) {
return false;
}
return ssid.length() > SSID_ASCII_MAX_LENGTH;
}
public static boolean isSSIDTooShort(String ssid) {
if (TextUtils.isEmpty(ssid)) {
return true;
}
return ssid.length() < SSID_ASCII_MIN_LENGTH;
}
public static boolean isPasswordValid(String password) {
if (TextUtils.isEmpty(password)) {
return false;
}
final int length = password.length();
return length >= PASSWORD_MIN_LENGTH && length <= PASSWORD_MAX_LENGTH;
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 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.tether;
import android.net.ConnectivityManager;
class NoOpOnStartTetheringCallback extends ConnectivityManager.OnStartTetheringCallback {
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import static android.net.wifi.WifiConfiguration.AP_BAND_2GHZ;
import static android.net.wifi.WifiConfiguration.AP_BAND_5GHZ;
public class WifiTetherApBandPreferenceController extends WifiTetherBasePreferenceController {
private static final String PREF_KEY = "wifi_tether_network_ap_band";
private static final String[] BAND_VALUES =
{String.valueOf(AP_BAND_2GHZ), String.valueOf(AP_BAND_5GHZ)};
private final String[] mBandEntries;
private int mBandIndex;
public WifiTetherApBandPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
mBandEntries = mContext.getResources().getStringArray(R.array.wifi_ap_band_config_full);
final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
if (config != null) {
mBandIndex = config.apBand;
} else {
mBandIndex = 0;
}
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
ListPreference preference = (ListPreference) mPreference;
if (!is5GhzBandSupported()) {
preference.setEnabled(false);
preference.setSummary(R.string.wifi_ap_choose_2G);
} else {
preference.setEntries(mBandEntries);
preference.setEntryValues(BAND_VALUES);
preference.setSummary(mBandEntries[mBandIndex]);
preference.setValue(String.valueOf(mBandIndex));
}
}
@Override
public String getPreferenceKey() {
return PREF_KEY;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mBandIndex = Integer.parseInt((String) newValue);
preference.setSummary(mBandEntries[mBandIndex]);
mListener.onTetherConfigUpdated();
return true;
}
private boolean is5GhzBandSupported() {
if (mBandIndex > 0) {
return true;
}
return mWifiManager.is5GHzBandSupported();
}
public int getBandIndex() {
return mBandIndex;
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceController;
public abstract class WifiTetherBasePreferenceController extends PreferenceController
implements Preference.OnPreferenceChangeListener {
public interface OnTetherConfigUpdateListener {
void onTetherConfigUpdated();
}
protected final WifiManager mWifiManager;
protected final String[] mWifiRegexs;
protected final ConnectivityManager mCm;
protected final OnTetherConfigUpdateListener mListener;
protected Preference mPreference;
public WifiTetherBasePreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context);
mListener = listener;
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mWifiRegexs = mCm.getTetherableWifiRegexs();
}
@Override
public boolean isAvailable() {
return mWifiManager != null && mWifiRegexs != null && mWifiRegexs.length > 0;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.widget.ValidatedEditTextPreference;
import com.android.settings.wifi.WifiUtils;
public class WifiTetherPasswordPreferenceController extends WifiTetherBasePreferenceController
implements ValidatedEditTextPreference.Validator {
private static final String PREF_KEY = "wifi_tether_network_password";
private String mPassword;
public WifiTetherPasswordPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
if (config != null) {
mPassword = config.preSharedKey;
}
}
@Override
public String getPreferenceKey() {
return PREF_KEY;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
((ValidatedEditTextPreference) mPreference).setText(mPassword);
((ValidatedEditTextPreference) mPreference).setIsPassword(true);
((ValidatedEditTextPreference) mPreference).setValidator(this);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mPassword = (String) newValue;
((ValidatedEditTextPreference) mPreference).setText(mPassword);
mListener.onTetherConfigUpdated();
return true;
}
public String getPassword() {
return mPassword;
}
@Override
public boolean isTextValid(String value) {
return WifiUtils.isPasswordValid(value);
}
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.text.BidiFormatter;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
import java.util.List;
public class WifiTetherPreferenceController extends PreferenceController
implements LifecycleObserver, OnResume, OnPause {
public static final IntentFilter WIFI_TETHER_INTENT_FILTER;
private static final String WIFI_TETHER_SETTINGS = "wifi_tether";
private final ConnectivityManager mConnectivityManager;
private final String[] mWifiRegexs;
private final WifiManager mWifiManager;
private Preference mPreference;
static {
WIFI_TETHER_INTENT_FILTER = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
WIFI_TETHER_INTENT_FILTER.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
WIFI_TETHER_INTENT_FILTER.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
}
public WifiTetherPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mWifiRegexs = mConnectivityManager.getTetherableWifiRegexs();
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public boolean isAvailable() {
return mWifiRegexs != null
&& mWifiRegexs.length != 0
&& WifiTetherSettings.isTetherSettingPageEnabled()
&& !Utils.isMonkeyRunning();
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(WIFI_TETHER_SETTINGS);
}
@Override
public String getPreferenceKey() {
return WIFI_TETHER_SETTINGS;
}
@Override
public void onResume() {
if (mPreference != null) {
mContext.registerReceiver(mReceiver, WIFI_TETHER_INTENT_FILTER);
clearSummaryForAirplaneMode();
}
}
@Override
public void onPause() {
if (mPreference != null) {
mContext.unregisterReceiver(mReceiver);
}
}
//
// Everything below is copied from WifiApEnabler
//
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
int state = intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
int reason = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON,
WifiManager.SAP_START_FAILURE_GENERAL);
handleWifiApStateChanged(state, reason);
} else if (ConnectivityManager.ACTION_TETHER_STATE_CHANGED.equals(action)) {
List<String> active = intent.getStringArrayListExtra(
ConnectivityManager.EXTRA_ACTIVE_TETHER);
List<String> errored = intent.getStringArrayListExtra(
ConnectivityManager.EXTRA_ERRORED_TETHER);
updateTetherState(active.toArray(), errored.toArray());
} else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
clearSummaryForAirplaneMode();
}
}
};
private void handleWifiApStateChanged(int state, int reason) {
switch (state) {
case WifiManager.WIFI_AP_STATE_ENABLED:
/**
* Summary on enable is handled by tether
* broadcast notice
*/
break;
case WifiManager.WIFI_AP_STATE_DISABLING:
mPreference.setSummary(R.string.wifi_tether_stopping);
break;
case WifiManager.WIFI_AP_STATE_DISABLED:
mPreference.setSummary(R.string.wifi_hotspot_off_subtext);
clearSummaryForAirplaneMode();
break;
default:
if (reason == WifiManager.SAP_START_FAILURE_NO_CHANNEL) {
mPreference.setSummary(R.string.wifi_sap_no_channel_error);
} else {
mPreference.setSummary(R.string.wifi_error);
}
clearSummaryForAirplaneMode();
}
}
private void updateTetherState(Object[] tethered, Object[] errored) {
boolean wifiTethered = matchRegex(tethered);
boolean wifiErrored = matchRegex(errored);
if (wifiTethered) {
WifiConfiguration wifiConfig = mWifiManager.getWifiApConfiguration();
updateConfigSummary(wifiConfig);
} else if (wifiErrored) {
mPreference.setSummary(R.string.wifi_error);
} else {
mPreference.setSummary(R.string.wifi_hotspot_off_subtext);
}
}
private boolean matchRegex(Object[] tethers) {
for (Object o : tethers) {
String s = (String) o;
for (String regex : mWifiRegexs) {
if (s.matches(regex)) {
return true;
}
}
}
return false;
}
private void updateConfigSummary(WifiConfiguration wifiConfig) {
final String s = mContext.getString(
com.android.internal.R.string.wifi_tether_configure_ssid_default);
mPreference.setSummary(mContext.getString(R.string.wifi_tether_enabled_subtext,
BidiFormatter.getInstance().unicodeWrap(
(wifiConfig == null) ? s : wifiConfig.SSID)));
}
private void clearSummaryForAirplaneMode() {
boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
if (isAirplaneMode) {
mPreference.setSummary(R.string.summary_placeholder);
}
}
//
// Everything above is copied from WifiApEnabler
//
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.EditTextPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.widget.ValidatedEditTextPreference;
import com.android.settings.wifi.WifiUtils;
public class WifiTetherSSIDPreferenceController extends WifiTetherBasePreferenceController
implements ValidatedEditTextPreference.Validator {
private static final String PREF_KEY = "wifi_tether_network_name";
@VisibleForTesting
static final String DEFAULT_SSID = "AndroidAP";
private String mSSID;
public WifiTetherSSIDPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
}
@Override
public String getPreferenceKey() {
return PREF_KEY;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
if (config != null) {
mSSID = config.SSID;
} else {
mSSID = DEFAULT_SSID;
}
((ValidatedEditTextPreference) mPreference).setValidator(this);
updateSsidDisplay((EditTextPreference) mPreference);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mSSID = (String) newValue;
updateSsidDisplay((EditTextPreference) preference);
mListener.onTetherConfigUpdated();
return true;
}
@Override
public boolean isTextValid(String value) {
return !WifiUtils.isSSIDTooLong(value) && !WifiUtils.isSSIDTooShort(value);
}
public String getSSID() {
return mSSID;
}
private void updateSsidDisplay(EditTextPreference preference) {
preference.setText(mSSID);
preference.setSummary(mSSID);
}
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.SystemProperties;
import android.os.UserManager;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.PreferenceController;
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.widget.SwitchBar;
import java.util.ArrayList;
import java.util.List;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION;
public class WifiTetherSettings extends RestrictedDashboardFragment
implements WifiTetherBasePreferenceController.OnTetherConfigUpdateListener {
public static boolean isTetherSettingPageEnabled() {
return SystemProperties.getBoolean("settings.ui.wifi.tether.enabled", true);
}
private static final IntentFilter TETHER_STATE_CHANGE_FILTER;
private WifiTetherSwitchBarController mSwitchBarController;
private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
private WifiTetherApBandPreferenceController mApBandPreferenceController;
private WifiManager mWifiManager;
private boolean mRestartWifiApAfterConfigChange;
@VisibleForTesting
TetherChangeReceiver mTetherChangeReceiver;
static {
TETHER_STATE_CHANGE_FILTER = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
TETHER_STATE_CHANGE_FILTER.addAction(WIFI_AP_STATE_CHANGED_ACTION);
}
public WifiTetherSettings() {
super(UserManager.DISALLOW_CONFIG_TETHERING);
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.WIFI_TETHER_SETTINGS;
}
@Override
protected String getLogTag() {
return "WifiTetherSettings";
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mTetherChangeReceiver = new TetherChangeReceiver();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Assume we are in a SettingsActivity. This is only safe because we currently use
// SettingsActivity as base for all preference fragments.
final SettingsActivity activity = (SettingsActivity) getActivity();
final SwitchBar switchBar = activity.getSwitchBar();
mSwitchBarController = new WifiTetherSwitchBarController(activity, switchBar);
getLifecycle().addObserver(mSwitchBarController);
switchBar.show();
}
@Override
public void onStart() {
super.onStart();
final Context context = getContext();
if (context != null) {
context.registerReceiver(mTetherChangeReceiver, TETHER_STATE_CHANGE_FILTER);
}
}
@Override
public void onStop() {
super.onStop();
final Context context = getContext();
if (context != null) {
context.unregisterReceiver(mTetherChangeReceiver);
}
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.wifi_tether_settings;
}
@Override
protected List<PreferenceController> getPreferenceControllers(Context context) {
final List<PreferenceController> controllers = new ArrayList<>();
mSSIDPreferenceController = new WifiTetherSSIDPreferenceController(context, this);
mPasswordPreferenceController = new WifiTetherPasswordPreferenceController(context, this);
mApBandPreferenceController = new WifiTetherApBandPreferenceController(context, this);
controllers.add(mSSIDPreferenceController);
controllers.add(mPasswordPreferenceController);
controllers.add(mApBandPreferenceController);
return controllers;
}
@Override
public void onTetherConfigUpdated() {
final WifiConfiguration config = buildNewConfig();
/**
* if soft AP is stopped, bring up
* else restart with new config
* TODO: update config on a running access point when framework support is added
*/
if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
Log.d("TetheringSettings",
"Wifi AP config changed while enabled, stop and restart");
mRestartWifiApAfterConfigChange = true;
mSwitchBarController.stopTether();
}
mWifiManager.setWifiApConfiguration(config);
}
private WifiConfiguration buildNewConfig() {
final WifiConfiguration config = new WifiConfiguration();
config.SSID = mSSIDPreferenceController.getSSID();
config.preSharedKey = mPasswordPreferenceController.getPassword();
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.apBand = mApBandPreferenceController.getBandIndex();
return config;
}
@VisibleForTesting
class TetherChangeReceiver extends BroadcastReceiver {
private static final String TAG = "TetherChangeReceiver";
@Override
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_TETHER_STATE_CHANGED)) {
if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED
&& mRestartWifiApAfterConfigChange) {
mRestartWifiApAfterConfigChange = false;
Log.d(TAG, "Restarting WifiAp due to prior config change.");
mSwitchBarController.startTether();
}
} else if (action.equals(WIFI_AP_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0);
if (state == WifiManager.WIFI_AP_STATE_DISABLED
&& mRestartWifiApAfterConfigChange) {
mRestartWifiApAfterConfigChange = false;
Log.d(TAG, "Restarting WifiAp due to prior config change.");
mSwitchBarController.startTether();
}
}
}
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.widget.Switch;
import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import static android.net.ConnectivityManager.TETHERING_WIFI;
public class WifiTetherSwitchBarController implements SwitchBar.OnSwitchChangeListener,
LifecycleObserver, OnStart, OnStop {
private final Context mContext;
private final SwitchBar mSwitchBar;
private final ConnectivityManager mConnectivityManager;
private final DataSaverBackend mDataSaverBackend;
private final NoOpOnStartTetheringCallback mOnStartTetheringCallback;
WifiTetherSwitchBarController(Context context, SwitchBar switchBar) {
mContext = context;
mSwitchBar = switchBar;
mDataSaverBackend = new DataSaverBackend(context);
mOnStartTetheringCallback = new NoOpOnStartTetheringCallback();
mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mSwitchBar.addOnSwitchChangeListener(this);
}
@Override
public void onStart() {
mContext.registerReceiver(mReceiver,
WifiTetherPreferenceController.WIFI_TETHER_INTENT_FILTER);
}
@Override
public void onStop() {
mContext.unregisterReceiver(mReceiver);
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
if (isChecked) {
startTether();
} else {
stopTether();
}
}
void stopTether() {
mSwitchBar.setEnabled(false);
mConnectivityManager.stopTethering(TETHERING_WIFI);
}
void startTether() {
mSwitchBar.setEnabled(false);
mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
final int state = intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
handleWifiApStateChanged(state);
} else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
enableWifiSwitch();
}
}
};
private void handleWifiApStateChanged(int state) {
switch (state) {
case WifiManager.WIFI_AP_STATE_ENABLING:
mSwitchBar.setEnabled(false);
break;
case WifiManager.WIFI_AP_STATE_ENABLED:
if (!mSwitchBar.isChecked()) {
mSwitchBar.setChecked(true);
}
enableWifiSwitch();
break;
case WifiManager.WIFI_AP_STATE_DISABLING:
if (mSwitchBar.isChecked()) {
mSwitchBar.setChecked(false);
}
mSwitchBar.setEnabled(false);
break;
case WifiManager.WIFI_AP_STATE_DISABLED:
mSwitchBar.setChecked(false);
enableWifiSwitch();
break;
default:
mSwitchBar.setChecked(false);
enableWifiSwitch();
break;
}
}
private void enableWifiSwitch() {
boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
if (!isAirplaneMode) {
mSwitchBar.setEnabled(!mDataSaverBackend.isDataSaverEnabled());
} else {
mSwitchBar.setEnabled(false);
}
}
}

View File

@@ -13,3 +13,4 @@ com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionLo
com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMicrophone com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMicrophone
com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages
com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment
com.android.settings.wifi.tether.WifiTetherSettings

View File

@@ -16,10 +16,10 @@
package com.android.settings.core.codeinspection; package com.android.settings.core.codeinspection;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.core.instrumentation.InstrumentableFragmentCodeInspector; import com.android.settings.core.instrumentation.InstrumentableFragmentCodeInspector;
import com.android.settings.search.SearchIndexProviderCodeInspector; import com.android.settings.search.SearchIndexProviderCodeInspector;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2017 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.widget;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.View;
import android.widget.EditText;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class ValidatedEditTextPreferenceTest {
@Mock
private View mView;
@Mock
private ValidatedEditTextPreference.Validator mValidator;
private ValidatedEditTextPreference mPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mPreference = new ValidatedEditTextPreference(RuntimeEnvironment.application);
}
@Test
public void bindDialogView_noTextWatcher_shouldDoNothing() {
mPreference.onBindDialogView(mView);
verifyZeroInteractions(mView);
}
@Test
public void bindDialogView_hasValidator_shouldBindToEditText() {
final EditText editText = spy(new EditText(RuntimeEnvironment.application));
when(mView.findViewById(android.R.id.edit)).thenReturn(editText);
mPreference.setValidator(mValidator);
mPreference.onBindDialogView(mView);
verify(editText).addTextChangedListener(any(TextWatcher.class));
}
@Test
public void bindDialogView_isPassword_shouldSetInputType() {
final EditText editText = spy(new EditText(RuntimeEnvironment.application));
when(mView.findViewById(android.R.id.edit)).thenReturn(editText);
mPreference.setValidator(mValidator);
mPreference.setIsPassword(true);
mPreference.onBindDialogView(mView);
assertThat(editText.getInputType()
& (InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_CLASS_TEXT))
.isNotEqualTo(0);
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2017 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 com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class WifiUtilsTest {
@Test
public void testSSID() {
assertThat(WifiUtils.isSSIDTooLong("123")).isFalse();
assertThat(WifiUtils.isSSIDTooLong("☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎☎")).isTrue();
assertThat(WifiUtils.isSSIDTooShort("123")).isFalse();
assertThat(WifiUtils.isSSIDTooShort("")).isTrue();
}
@Test
public void testPassword() {
final String longPassword = "123456789012345678901234567890"
+ "1234567890123456789012345678901234567890";
assertThat(WifiUtils.isPasswordValid("123")).isFalse();
assertThat(WifiUtils.isPasswordValid("12345678")).isTrue();
assertThat(WifiUtils.isPasswordValid("1234567890")).isTrue();
assertThat(WifiUtils.isPasswordValid(longPassword)).isFalse();
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class WifiTetherApBandPreferenceControllerTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@Mock
private ConnectivityManager mConnectivityManager;
@Mock
private WifiManager mWifiManager;
@Mock
private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
@Mock
private PreferenceScreen mScreen;
private WifiTetherApBandPreferenceController mController;
private ListPreference mListPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mListPreference = new ListPreference(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
.thenReturn(mConnectivityManager);
when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"1", "2"});
when(mContext.getResources()).thenReturn(RuntimeEnvironment.application.getResources());
when(mScreen.findPreference(anyString())).thenReturn(mListPreference);
mController = new WifiTetherApBandPreferenceController(mContext, mListener);
}
@Test
public void display_5GhzSupported_shouldDisplayFullList() {
when(mWifiManager.is5GHzBandSupported()).thenReturn(true);
mController.displayPreference(mScreen);
assertThat(mListPreference.getEntries().length).isEqualTo(2);
}
@Test
public void display_5GhzNotSupported_shouldDisable() {
when(mWifiManager.is5GHzBandSupported()).thenReturn(false);
mController.displayPreference(mScreen);
assertThat(mListPreference.getEntries()).isNull();
assertThat(mListPreference.isEnabled()).isFalse();
assertThat(mListPreference.getSummary())
.isEqualTo(RuntimeEnvironment.application.getString(R.string.wifi_ap_choose_2G));
}
@Test
public void changePreference_shouldUpdateValue() {
when(mWifiManager.is5GHzBandSupported()).thenReturn(true);
mController.displayPreference(mScreen);
mController.onPreferenceChange(mListPreference, "1");
assertThat(mController.getBandIndex()).isEqualTo(1);
mController.onPreferenceChange(mListPreference, "0");
assertThat(mController.getBandIndex()).isEqualTo(0);
verify(mListener, times(2)).onTetherConfigUpdated();
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.ValidatedEditTextPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class WifiTetherPasswordPreferenceControllerTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@Mock
private ConnectivityManager mConnectivityManager;
@Mock
private WifiManager mWifiManager;
@Mock
private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
@Mock
private PreferenceScreen mScreen;
private WifiTetherPasswordPreferenceController mController;
private ValidatedEditTextPreference mPreference;
private WifiConfiguration mConfig;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mPreference = new ValidatedEditTextPreference(RuntimeEnvironment.application);
mConfig = new WifiConfiguration();
mConfig.SSID = "test_1234";
mConfig.preSharedKey = "test_password";
when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
when(mWifiManager.getWifiApConfiguration()).thenReturn(mConfig);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
.thenReturn(mConnectivityManager);
when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"1", "2"});
when(mContext.getResources()).thenReturn(RuntimeEnvironment.application.getResources());
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
mController = new WifiTetherPasswordPreferenceController(mContext, mListener);
}
@Test
public void displayPreference_shouldStylePreference() {
mController.displayPreference(mScreen);
assertThat(mPreference.getText()).isEqualTo(mConfig.preSharedKey);
assertThat(mPreference.isPassword()).isTrue();
}
@Test
public void changePreference_shouldUpdateValue() {
mController.displayPreference(mScreen);
mController.onPreferenceChange(mPreference, "1");
assertThat(mController.getPassword()).isEqualTo("1");
mController.onPreferenceChange(mPreference, "0");
assertThat(mController.getPassword()).isEqualTo("0");
verify(mListener, times(2)).onTetherConfigUpdated();
}
}

View File

@@ -0,0 +1,186 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowSettings;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
shadows = {
WifiTetherPreferenceControllerTest.ShadowWifiTetherSettings.class
})
public class WifiTetherPreferenceControllerTest {
@Mock
private Context mContext;
@Mock
private ConnectivityManager mConnectivityManager;
@Mock
private WifiManager mWifiManager;
@Mock
private PreferenceScreen mScreen;
private WifiTetherPreferenceController mController;
private Lifecycle mLifecycle;
private Preference mPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mLifecycle = new Lifecycle();
mPreference = new Preference(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
.thenReturn(mConnectivityManager);
when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"1", "2"});
mController = new WifiTetherPreferenceController(mContext, mLifecycle);
}
@Test
public void isAvailable_noTetherRegex_shouldReturnFalse() {
when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{});
mController = new WifiTetherPreferenceController(mContext, mLifecycle);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_hasTetherRegex_shouldReturnTrue() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void resumeAndPause_shouldRegisterUnregisterReceiver() {
final BroadcastReceiver receiver = ReflectionHelpers.getField(mController, "mReceiver");
mController.displayPreference(mScreen);
mLifecycle.onResume();
mLifecycle.onPause();
verify(mContext).registerReceiver(eq(receiver), any(IntentFilter.class));
verify(mContext).unregisterReceiver(receiver);
}
@Test
public void testReceiver_apStateChangedToDisabled_shouldUpdatePreferenceSummary() {
mController.displayPreference(mScreen);
final BroadcastReceiver receiver = ReflectionHelpers.getField(mController, "mReceiver");
final Intent broadcast = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
broadcast.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_DISABLED);
receiver.onReceive(RuntimeEnvironment.application, broadcast);
assertThat(mPreference.getSummary().toString()).isEqualTo(
RuntimeEnvironment.application.getString(R.string.wifi_hotspot_off_subtext));
}
@Test
public void testReceiver_apStateChangedToDisabling_shouldUpdatePreferenceSummary() {
mController.displayPreference(mScreen);
final BroadcastReceiver receiver = ReflectionHelpers.getField(mController, "mReceiver");
final Intent broadcast = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
broadcast.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_DISABLING);
receiver.onReceive(RuntimeEnvironment.application, broadcast);
assertThat(mPreference.getSummary().toString()).isEqualTo(
RuntimeEnvironment.application.getString(R.string.wifi_tether_stopping));
}
@Test
public void testReceiver_goingToAirplaneMode_shouldClearPreferenceSummary() {
final ContentResolver cr = mock(ContentResolver.class);
when(mContext.getContentResolver()).thenReturn(cr);
ShadowSettings.ShadowGlobal.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, 1);
mController.displayPreference(mScreen);
final BroadcastReceiver receiver = ReflectionHelpers.getField(mController, "mReceiver");
final Intent broadcast = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
receiver.onReceive(RuntimeEnvironment.application, broadcast);
assertThat(mPreference.getSummary().toString()).isEqualTo(
RuntimeEnvironment.application.getString(R.string.summary_placeholder));
}
@Test
public void testReceiver_tetherEnabled_shouldUpdatePreferenceSummary() {
mController.displayPreference(mScreen);
final BroadcastReceiver receiver = ReflectionHelpers.getField(mController, "mReceiver");
final Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
final ArrayList<String> activeTethers = new ArrayList<>();
activeTethers.add("1");
broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeTethers);
broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
new ArrayList<>());
final WifiConfiguration configuration = new WifiConfiguration();
configuration.SSID = "test-ap";
when(mWifiManager.getWifiApConfiguration()).thenReturn(configuration);
receiver.onReceive(RuntimeEnvironment.application, broadcast);
verify(mContext).getString(eq(R.string.wifi_tether_enabled_subtext), any());
}
@Implements(WifiTetherSettings.class)
public static final class ShadowWifiTetherSettings {
@Implementation
public static boolean isTetherSettingPageEnabled() {
return true;
}
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.ValidatedEditTextPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class WifiTetherSSIDPreferenceControllerTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@Mock
private ConnectivityManager mConnectivityManager;
@Mock
private WifiManager mWifiManager;
@Mock
private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
@Mock
private PreferenceScreen mScreen;
private WifiTetherSSIDPreferenceController mController;
private ValidatedEditTextPreference mPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mPreference = new ValidatedEditTextPreference(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
.thenReturn(mConnectivityManager);
when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"1", "2"});
when(mContext.getResources()).thenReturn(RuntimeEnvironment.application.getResources());
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
mController = new WifiTetherSSIDPreferenceController(mContext, mListener);
}
@Test
public void displayPreference_noWifiConfig_shouldDisplayDefaultSSID() {
when(mWifiManager.getWifiApConfiguration()).thenReturn(null);
mController.displayPreference(mScreen);
assertThat(mController.getSSID())
.isEqualTo(WifiTetherSSIDPreferenceController.DEFAULT_SSID);
}
@Test
public void displayPreference_hasCustomWifiConfig_shouldDisplayCustomSSID() {
final WifiConfiguration config = new WifiConfiguration();
config.SSID = "test_1234";
when(mWifiManager.getWifiApConfiguration()).thenReturn(config);
mController.displayPreference(mScreen);
assertThat(mController.getSSID()).isEqualTo(config.SSID);
}
@Test
public void changePreference_shouldUpdateValue() {
mController.displayPreference(mScreen);
mController.onPreferenceChange(mPreference, "1");
assertThat(mController.getSSID()).isEqualTo("1");
mController.onPreferenceChange(mPreference, "0");
assertThat(mController.getSSID()).isEqualTo("0");
verify(mListener, times(2)).onTetherConfigUpdated();
}
}

View File

@@ -9,10 +9,12 @@ LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \ android-support-test \
mockito-target-minus-junit4 \
espresso-core \ espresso-core \
legacy-android-test \
mockito-target-minus-junit4 \
truth-prebuilt \ truth-prebuilt \
legacy-android-test ub-uiautomator \
# Include all test java files. # Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES := $(call all-java-files-under, src)

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2017 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.tether;
import android.app.Instrumentation;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import com.android.settings.Settings;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class WifiTetherSettingsTest {
private static final long TIMEOUT = 2000L;
private Instrumentation mInstrumentation;
private Intent mTetherActivityIntent;
private UiDevice mDevice;
@Before
public void setUp() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mDevice = UiDevice.getInstance(mInstrumentation);
mTetherActivityIntent = new Intent()
.setClassName(mInstrumentation.getTargetContext().getPackageName(),
Settings.TetherSettingsActivity.class.getName())
.setPackage(mInstrumentation.getTargetContext().getPackageName());
}
@After
public void tearDown() {
mDevice.pressHome();
}
@Test
public void launchTetherSettings_shouldHaveAllFields() {
launchWifiTetherActivity();
onView(withText("Network name")).check(matches(isDisplayed()));
onView(withText("Password")).check(matches(isDisplayed()));
onView(withText("Select AP Band")).check(matches(isDisplayed()));
}
private void launchWifiTetherActivity() {
mInstrumentation.startActivitySync(mTetherActivityIntent);
onView(withText("Portable WiFi hotspot")).perform();
UiObject2 item = mDevice.wait(Until.findObject(By.text("Portable WiFi hotspot")), TIMEOUT);
item.click();
}
}