Merge "Remove some dead code"
diff --git a/res/layout/nfc_payment_how_it_works.xml b/res/layout/nfc_payment_how_it_works.xml
index 565a16b..87a0095 100644
--- a/res/layout/nfc_payment_how_it_works.xml
+++ b/res/layout/nfc_payment_how_it_works.xml
@@ -15,44 +15,52 @@
android:background="#FFB2DFDB" >
</LinearLayout>
- <LinearLayout
- android:id="@+id/nfc_how_it_works_image_text"
+ <ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:paddingTop="72dp"
- android:orientation="vertical">
+ android:paddingBottom="48dp"
+ android:fillViewport="true">
- <ImageView
- android:id="@+id/nfc_how_it_works_image"
- android:layout_width="match_parent"
- android:layout_height="188dp"
- android:gravity="center"
- android:src="@drawable/nfc_how_it_works" />
+ <LinearLayout
+ android:id="@+id/nfc_how_it_works_image_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="72dp"
+ android:orientation="vertical">
- <TextView
- android:id="@+id/nfc_how_it_works_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/nfc_how_it_works_title"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:textColor="#FF263238"
- android:textSize="24sp" />
+ <ImageView
+ android:id="@+id/nfc_how_it_works_image"
+ android:layout_width="match_parent"
+ android:layout_height="188dp"
+ android:gravity="center"
+ android:src="@drawable/nfc_how_it_works" />
- <TextView
- android:id="@+id/nfc_how_it_works_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="10dp"
- android:paddingBottom="18dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:text="@string/nfc_how_it_works_content"
- android:textColor="#FF263238"
- android:textSize="16sp" />
- </LinearLayout>
+ <TextView
+ android:id="@+id/nfc_how_it_works_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/nfc_how_it_works_title"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:textColor="#FF263238"
+ android:textSize="24sp" />
+
+ <TextView
+ android:id="@+id/nfc_how_it_works_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="10dp"
+ android:paddingBottom="18dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/nfc_how_it_works_content"
+ android:textColor="#FF263238"
+ android:textSize="16sp" />
+ </LinearLayout>
+ </ScrollView>
+
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="48dp"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6e5f8f4..6130aec 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3091,11 +3091,11 @@
<!-- Title for a screen containing all device reset options [CHAR LIMIT=50] -->
- <string name="reset_dashboard_title">Reset</string>
+ <string name="reset_dashboard_title">Reset options</string>
<!-- Reset Network -->
- <!-- SD card & phone storage settings screen, setting option name under Backup & Restore heading -->
- <string name="reset_network_title">Network settings reset</string>
+ <!-- Button title to reset Wi-Fi settings, Mobile data setting, bluetooth settings -->
+ <string name="reset_network_title">Reset Wi-Fi, mobile & Bluetooth</string>
<!-- SD card & phone storage settings screen, message on screen after user selects Reset network settings [CHAR LIMIT=NONE] -->
<string name="reset_network_desc">This will reset all network settings, including:\n\n<li>Wi\u2011Fi</li>\n<li>Mobile data</li>\n<li>Bluetooth</li>"</string>
<!-- SD card & phone storage settings screen, button on screen after user selects Reset network settings -->
@@ -3112,8 +3112,8 @@
<string name="reset_network_complete_toast">Network settings have been reset</string>
<!-- Master Clear -->
- <!-- SD card & phone storage settings screen, setting option name under Internal phone storage heading -->
- <string name="master_clear_title">Factory data reset</string>
+ <!-- Button title to factory data reset the entire device -->
+ <string name="master_clear_title">Erase all data (Factory reset)</string>
<!-- Summary text for factory data reset describing what will be reset [CHAR_LIMIT=NONE]-->
<plurals name="master_clear_with_account_summary">
<item quantity="one">1 account will be reset</item>
diff --git a/res/xml/app_and_notification.xml b/res/xml/app_and_notification.xml
index 47fc378..4a5ee1d 100644
--- a/res/xml/app_and_notification.xml
+++ b/res/xml/app_and_notification.xml
@@ -40,6 +40,11 @@
</Preference>
</PreferenceCategory>
+ <!-- Empty category to draw divider -->
+ <PreferenceCategory
+ android:key="all_app_info_divider"
+ android:order="-190"/>
+
<Preference
android:key="manage_perms"
android:title="@string/app_permissions"
diff --git a/res/xml/assist_gesture_settings.xml b/res/xml/assist_gesture_settings.xml
index d941c80..cf84e8a 100644
--- a/res/xml/assist_gesture_settings.xml
+++ b/res/xml/assist_gesture_settings.xml
@@ -31,10 +31,4 @@
android:summary="@string/assist_gesture_summary"
app:keywords="@string/keywords_squeeze_to_launch_gesture"/>
- <com.android.settings.widget.SeekBarPreference
- android:key="gesture_assist_sensitivity"
- android:title="@string/assist_gesture_sensitivity_title"
- android:defaultValue="5"
- android:max="10" />
-
</PreferenceScreen>
diff --git a/res/xml/inapp_notification_settings.xml b/res/xml/inapp_notification_settings.xml
new file mode 100644
index 0000000..7547f3c
--- /dev/null
+++ b/res/xml/inapp_notification_settings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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"
+ xmlns:settings="http://schemas.android.com/apk/res-auto">
+
+ <Preference
+ android:key="app_link"
+ android:title="@string/app_settings_link"
+ android:order="500"
+ settings:allowDividerAbove="true"/>
+
+</PreferenceScreen>
diff --git a/res/xml/tether_prefs.xml b/res/xml/tether_prefs.xml
index a506291..709c425 100644
--- a/res/xml/tether_prefs.xml
+++ b/res/xml/tether_prefs.xml
@@ -17,10 +17,16 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
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
android:key="usb_tether_settings"
android:title="@string/usb_tethering_button_text"
- android:summary="@string/usb_tethering_subtext"/>
+ android:summary="@string/usb_tethering_subtext" />
<SwitchPreference
android:key="enable_wifi_ap"
@@ -35,7 +41,7 @@
<SwitchPreference
android:key="enable_bluetooth_tethering"
android:title="@string/bluetooth_tether_checkbox_text"
- android:summary="@string/bluetooth_tethering_subtext"/>
+ android:summary="@string/bluetooth_tethering_subtext" />
<Preference
android:key="disabled_on_data_saver"
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
new file mode 100644
index 0000000..b83f2f3
--- /dev/null
+++ b/res/xml/wifi_tether_settings.xml
@@ -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>
\ No newline at end of file
diff --git a/src/com/android/settings/ActivityPicker.java b/src/com/android/settings/ActivityPicker.java
index 2c3436f..ae61944 100644
--- a/src/com/android/settings/ActivityPicker.java
+++ b/src/com/android/settings/ActivityPicker.java
@@ -78,6 +78,10 @@
Parcelable parcel = intent.getParcelableExtra(Intent.EXTRA_INTENT);
if (parcel instanceof Intent) {
mBaseIntent = (Intent) parcel;
+ mBaseIntent.setFlags(mBaseIntent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
} else {
mBaseIntent = new Intent(Intent.ACTION_MAIN, null);
mBaseIntent.addCategory(Intent.CATEGORY_DEFAULT);
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
index 708e17f..664916a 100644
--- a/src/com/android/settings/TetherSettings.java
+++ b/src/com/android/settings/TetherSettings.java
@@ -43,6 +43,8 @@
import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.wifi.WifiApDialog;
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 java.lang.ref.WeakReference;
@@ -63,7 +65,6 @@
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_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 int DIALOG_AP_SETTINGS = 1;
@@ -100,17 +101,14 @@
private WifiConfiguration mWifiConfig = null;
private ConnectivityManager mCm;
+ private WifiTetherPreferenceController mWifiTetherPreferenceController;
+
private boolean mRestartWifiApAfterConfigChange;
private boolean mUsbConnected;
private boolean mMassStorageActive;
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 DataSaverBackend mDataSaverBackend;
@@ -127,6 +125,13 @@
}
@Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mWifiTetherPreferenceController =
+ new WifiTetherPreferenceController(context, getLifecycle());
+ }
+
+ @Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -154,6 +159,7 @@
mEnableWifiAp =
(SwitchPreference) findPreference(ENABLE_WIFI_AP);
+
Preference wifiApSettings = findPreference(WIFI_AP_SSID_AND_SECURITY);
mUsbTether = (SwitchPreference) findPreference(USB_TETHER_SETTINGS);
mBluetoothTether = (SwitchPreference) findPreference(ENABLE_BLUETOOTH_TETHERING);
@@ -175,12 +181,18 @@
getPreferenceScreen().removePreference(mUsbTether);
}
- if (wifiAvailable && !Utils.isMonkeyRunning()) {
- mWifiApEnabler = new WifiApEnabler(activity, mDataSaverBackend, mEnableWifiAp);
- initWifiTethering();
+ mWifiTetherPreferenceController.displayPreference(getPreferenceScreen());
+ if (WifiTetherSettings.isTetherSettingPageEnabled()) {
+ removePreference(ENABLE_WIFI_AP);
+ removePreference(WIFI_AP_SSID_AND_SECURITY);
} else {
- getPreferenceScreen().removePreference(mEnableWifiAp);
- getPreferenceScreen().removePreference(wifiApSettings);
+ if (wifiAvailable && !Utils.isMonkeyRunning()) {
+ mWifiApEnabler = new WifiApEnabler(activity, mDataSaverBackend, mEnableWifiAp);
+ initWifiTethering();
+ } else {
+ getPreferenceScreen().removePreference(mEnableWifiAp);
+ getPreferenceScreen().removePreference(wifiApSettings);
+ }
}
if (!bluetoothAvailable) {
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index 03a620b..adb0659 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -16,6 +16,12 @@
package com.android.settings.accounts;
+import static android.content.Intent.EXTRA_USER;
+import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
+import static android.os.UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
+import static android.provider.Settings.ACTION_ADD_ACCOUNT;
+import static android.provider.Settings.EXTRA_AUTHORITIES;
+
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.BroadcastReceiver;
@@ -48,8 +54,8 @@
import com.android.settings.core.PreferenceController;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.search.SearchFeatureProviderImpl;
+import com.android.settings.search.SearchIndexableRaw;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.accounts.AuthenticatorHelper;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -61,17 +67,11 @@
import java.util.Comparator;
import java.util.List;
-import static android.content.Intent.EXTRA_USER;
-import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
-import static android.os.UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
-import static android.provider.Settings.EXTRA_AUTHORITIES;
-
public class AccountPreferenceController extends PreferenceController
implements AuthenticatorHelper.OnAccountsUpdateListener,
OnPreferenceClickListener, LifecycleObserver, OnPause, OnResume {
private static final String TAG = "AccountPrefController";
- private static final String ADD_ACCOUNT_ACTION = "android.settings.ADD_ACCOUNT_SETTINGS";
private static final int ORDER_ACCOUNT_PROFILES = 1;
private static final int ORDER_LAST = 1002;
@@ -232,7 +232,7 @@
for (int i = 0; i < count; i++) {
ProfileData profileData = mProfiles.valueAt(i);
if (preference == profileData.addAccountPreference) {
- Intent intent = new Intent(ADD_ACCOUNT_ACTION);
+ Intent intent = new Intent(ACTION_ADD_ACCOUNT);
intent.putExtra(EXTRA_USER, profileData.userInfo.getUserHandle());
intent.putExtra(EXTRA_AUTHORITIES, mAuthorities);
mContext.startActivity(intent);
diff --git a/src/com/android/settings/accounts/UserAndAccountDashboardFragment.java b/src/com/android/settings/accounts/UserAndAccountDashboardFragment.java
index 792b77a..d8b19a1 100644
--- a/src/com/android/settings/accounts/UserAndAccountDashboardFragment.java
+++ b/src/com/android/settings/accounts/UserAndAccountDashboardFragment.java
@@ -81,15 +81,6 @@
return controllers;
}
- @Override
- protected boolean displayTile(Tile tile) {
- final Bundle metadata = tile.metaData;
- if (metadata != null) {
- return metadata.getString(METADATA_IA_ACCOUNT) == null;
- }
- return true;
- }
-
private static class SummaryProvider implements SummaryLoader.SummaryProvider {
private final Context mContext;
diff --git a/src/com/android/settings/applications/RecentAppsPreferenceController.java b/src/com/android/settings/applications/RecentAppsPreferenceController.java
index 7a99508..7eeda67 100644
--- a/src/com/android/settings/applications/RecentAppsPreferenceController.java
+++ b/src/com/android/settings/applications/RecentAppsPreferenceController.java
@@ -61,6 +61,8 @@
private static final String TAG = "RecentAppsCtrl";
private static final String KEY_PREF_CATEGORY = "recent_apps_category";
@VisibleForTesting
+ static final String KEY_DIVIDER = "all_app_info_divider";
+ @VisibleForTesting
static final String KEY_SEE_ALL = "all_app_info";
private static final int SHOW_RECENT_APP_COUNT = 5;
private static final Set<String> SKIP_SYSTEM_PACKAGES = new ArraySet<>();
@@ -77,6 +79,7 @@
private PreferenceCategory mCategory;
private Preference mSeeAllPref;
+ private Preference mDivider;
private boolean mHasRecentApps;
static {
@@ -121,12 +124,14 @@
super.updateNonIndexableKeys(keys);
// Don't index category name into search. It's not actionable.
keys.add(KEY_PREF_CATEGORY);
+ keys.add(KEY_DIVIDER);
}
@Override
public void displayPreference(PreferenceScreen screen) {
mCategory = (PreferenceCategory) screen.findPreference(getPreferenceKey());
mSeeAllPref = screen.findPreference(KEY_SEE_ALL);
+ mDivider = screen.findPreference(KEY_DIVIDER);
super.displayPreference(screen);
refreshUi(mCategory.getContext());
}
@@ -180,6 +185,7 @@
private void displayOnlyAppInfo() {
mCategory.setTitle(null);
+ mDivider.setVisible(false);
mSeeAllPref.setTitle(R.string.applications_settings);
mSeeAllPref.setIcon(null);
int prefCount = mCategory.getPreferenceCount();
@@ -193,6 +199,7 @@
private void displayRecentApps(Context prefContext, List<UsageStats> recentApps) {
mCategory.setTitle(R.string.recent_app_category_title);
+ mDivider.setVisible(true);
mSeeAllPref.setSummary(null);
mSeeAllPref.setIcon(R.drawable.ic_chevron_right_24dp);
diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
index dddfb1b..7c8c8f1 100644
--- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
+++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
@@ -32,6 +32,7 @@
import com.android.settings.network.NetworkDashboardFragment;
import com.android.settings.notification.ConfigureNotificationSettings;
import com.android.settings.notification.SoundSettings;
+import com.android.settings.security.LockscreenDashboardFragment;
import com.android.settings.system.SystemDashboardFragment;
import com.android.settingslib.drawer.CategoryKey;
@@ -75,7 +76,7 @@
PARENT_TO_CATEGORY_KEY_MAP.put(SecuritySettings.class.getName(),
CategoryKey.CATEGORY_SECURITY);
PARENT_TO_CATEGORY_KEY_MAP.put(AccountDetailDashboardFragment.class.getName(),
- CategoryKey.CATEGORY_ACCOUNT);
+ CategoryKey.CATEGORY_ACCOUNT_DETAIL);
PARENT_TO_CATEGORY_KEY_MAP.put(UserAndAccountDashboardFragment.class.getName(),
CategoryKey.CATEGORY_ACCOUNT);
PARENT_TO_CATEGORY_KEY_MAP.put(
@@ -86,6 +87,8 @@
CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
PARENT_TO_CATEGORY_KEY_MAP.put(ConfigureNotificationSettings.class.getName(),
CategoryKey.CATEGORY_NOTIFICATIONS);
+ PARENT_TO_CATEGORY_KEY_MAP.put(LockscreenDashboardFragment.class.getName(),
+ CategoryKey.CATEGORY_SECURITY_LOCKSCREEN);
CATEGORY_KEY_TO_PARENT_MAP = new ArrayMap<>(PARENT_TO_CATEGORY_KEY_MAP.size());
diff --git a/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroduction.java b/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroduction.java
index 26b3427..e668812 100644
--- a/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroduction.java
@@ -28,9 +28,9 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
-import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
import com.android.settings.password.SetupChooseLockGeneric;
+import com.android.settings.password.SetupSkipDialog;
public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntroduction {
@@ -98,9 +98,8 @@
setResult(RESULT_SKIP);
finish();
} else {
- SetupSkipDialog dialog = SetupSkipDialog.newInstance(
- getIntent().getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false));
- dialog.show(getFragmentManager());
+ setResult(SetupSkipDialog.RESULT_SKIP);
+ finish();
}
}
diff --git a/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragment.java b/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragment.java
index ef15d51..2d0030d 100644
--- a/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragment.java
+++ b/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragment.java
@@ -101,9 +101,17 @@
switch (anomalyAction.getActionType()) {
case Anomaly.AnomalyActionType.FORCE_STOP:
return new AlertDialog.Builder(context)
- .setTitle(R.string.force_stop_dlg_title)
- .setMessage(R.string.force_stop_dlg_text)
- .setPositiveButton(R.string.dlg_ok, this)
+ .setTitle(R.string.dialog_stop_title)
+ .setMessage(getString(R.string.dialog_stop_message, mAnomaly.displayName))
+ .setPositiveButton(R.string.dialog_stop_ok, this)
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case Anomaly.AnomalyActionType.BACKGROUND_CHECK:
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.dialog_background_check_title)
+ .setMessage(getString(R.string.dialog_background_check_message,
+ mAnomaly.displayName))
+ .setPositiveButton(R.string.dialog_background_check_ok, this)
.setNegativeButton(R.string.dlg_cancel, null)
.create();
default:
diff --git a/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java b/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java
index 4d4b136..3344eb6 100644
--- a/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java
+++ b/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java
@@ -24,11 +24,18 @@
public interface AnomalyAction {
/**
* handle the action when user clicks positive button
- * @param Anomaly about the app that we need to handle
+ * @param anomaly about the app that we need to handle
* @param metricsKey key for the page that invokes the action
*
* @see com.android.internal.logging.nano.MetricsProto
*/
- void handlePositiveAction(Anomaly Anomaly, int metricsKey);
+ void handlePositiveAction(Anomaly anomaly, int metricsKey);
+
+ /**
+ * Check whether the action is active for {@code anomaly}
+ * @param anomaly about the app that we need to handle
+ * @return {@code true} if action is active, otherwise return {@code false}
+ */
+ boolean isActionActive(Anomaly anomaly);
int getActionType();
}
diff --git a/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java b/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java
index 8c7e827..16fd0df 100644
--- a/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java
+++ b/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java
@@ -46,6 +46,14 @@
}
@Override
+ public boolean isActionActive(Anomaly anomaly) {
+ final int mode = mAppOpsManager
+ .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, anomaly.uid,
+ anomaly.packageName);
+ return mode != AppOpsManager.MODE_IGNORED && mode != AppOpsManager.MODE_ERRORED;
+ }
+
+ @Override
public int getActionType() {
return Anomaly.AnomalyActionType.BACKGROUND_CHECK;
}
diff --git a/src/com/android/settings/fuelgauge/anomaly/action/ForceStopAction.java b/src/com/android/settings/fuelgauge/anomaly/action/ForceStopAction.java
index c124c9e..557b2a9 100644
--- a/src/com/android/settings/fuelgauge/anomaly/action/ForceStopAction.java
+++ b/src/com/android/settings/fuelgauge/anomaly/action/ForceStopAction.java
@@ -18,6 +18,9 @@
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto;
@@ -25,20 +28,25 @@
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.overlay.FeatureFactory;
+import java.util.List;
+
/**
* Force stop action for anomaly app, which means to stop the app which causes anomaly
*/
public class ForceStopAction implements AnomalyAction {
+ private static final String TAG = "ForceStopAction";
private Context mContext;
private MetricsFeatureProvider mMetricsFeatureProvider;
private ActivityManager mActivityManager;
+ private PackageManager mPackageManager;
public ForceStopAction(Context context) {
mContext = context;
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
mActivityManager = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
+ mPackageManager = context.getPackageManager();
}
@Override
@@ -53,6 +61,18 @@
}
@Override
+ public boolean isActionActive(Anomaly anomaly) {
+ try {
+ ApplicationInfo info = mPackageManager.getApplicationInfo(anomaly.packageName,
+ PackageManager.GET_META_DATA);
+ return (info.flags & ApplicationInfo.FLAG_STOPPED) == 0;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Cannot find info for app: " + anomaly.packageName);
+ }
+ return false;
+ }
+
+ @Override
public int getActionType() {
return Anomaly.AnomalyActionType.FORCE_STOP;
}
diff --git a/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetector.java b/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetector.java
index 8568d37..74c43d0 100644
--- a/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetector.java
+++ b/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetector.java
@@ -17,14 +17,11 @@
package com.android.settings.fuelgauge.anomaly.checker;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.BatteryStats;
import android.os.SystemClock;
import android.support.annotation.VisibleForTesting;
-import android.text.format.DateUtils;
import android.util.ArrayMap;
-import android.util.Log;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
@@ -32,6 +29,8 @@
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy;
+import com.android.settings.fuelgauge.anomaly.AnomalyUtils;
+import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
import java.util.ArrayList;
import java.util.List;
@@ -47,6 +46,8 @@
BatteryUtils mBatteryUtils;
@VisibleForTesting
long mWakeLockThresholdMs;
+ @VisibleForTesting
+ AnomalyAction mAnomalyAction;
public WakeLockAnomalyDetector(Context context) {
this(context, new AnomalyDetectionPolicy(context));
@@ -57,6 +58,8 @@
mContext = context;
mPackageManager = context.getPackageManager();
mBatteryUtils = BatteryUtils.getInstance(context);
+ mAnomalyAction = AnomalyUtils.getInstance(context).getAnomalyAction(
+ Anomaly.AnomalyType.WAKE_LOCK);
mWakeLockThresholdMs = policy.wakeLockThreshold;
}
@@ -111,7 +114,10 @@
.setDisplayName(displayName)
.setPackageName(packageName)
.build();
- anomalies.add(anomaly);
+
+ if (mAnomalyAction.isActionActive(anomaly)) {
+ anomalies.add(anomaly);
+ }
}
}
diff --git a/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java b/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java
index 83b8d9a..3502e73 100644
--- a/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java
+++ b/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java
@@ -17,9 +17,7 @@
package com.android.settings.fuelgauge.anomaly.checker;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.BatteryStats;
-import android.os.SystemClock;
import android.support.annotation.VisibleForTesting;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -30,6 +28,8 @@
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy;
+import com.android.settings.fuelgauge.anomaly.AnomalyUtils;
+import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
import java.util.ArrayList;
import java.util.List;
@@ -41,6 +41,8 @@
private static final String TAG = "WakeupAlarmAnomalyDetector";
@VisibleForTesting
BatteryUtils mBatteryUtils;
+ @VisibleForTesting
+ AnomalyAction mAnomalyAction;
private long mWakeupAlarmThreshold;
private Context mContext;
@@ -52,6 +54,8 @@
WakeupAlarmAnomalyDetector(Context context, AnomalyDetectionPolicy policy) {
mContext = context;
mBatteryUtils = BatteryUtils.getInstance(context);
+ mAnomalyAction = AnomalyUtils.getInstance(context).getAnomalyAction(
+ Anomaly.AnomalyType.WAKEUP_ALARM);
mWakeupAlarmThreshold = policy.wakeupAlarmThreshold;
}
@@ -91,7 +95,10 @@
.setDisplayName(displayName)
.setPackageName(packageName)
.build();
- anomalies.add(anomaly);
+
+ if (mAnomalyAction.isActionActive(anomaly)) {
+ anomalies.add(anomaly);
+ }
}
}
}
diff --git a/src/com/android/settings/gestures/AssistGestureFeatureProvider.java b/src/com/android/settings/gestures/AssistGestureFeatureProvider.java
index f06f6c1..8902393 100644
--- a/src/com/android/settings/gestures/AssistGestureFeatureProvider.java
+++ b/src/com/android/settings/gestures/AssistGestureFeatureProvider.java
@@ -18,10 +18,24 @@
import android.content.Context;
+import com.android.settings.core.PreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.util.List;
+
/** Feature provider for the assist gesture. */
public interface AssistGestureFeatureProvider {
/** Returns true if the assist gesture is supported. */
boolean isSupported(Context context);
+ /** Returns true if the sensor is available. */
+ boolean isSensorAvailable(Context context);
+
+ /** Returns the resource */
+ int getPreferenceResourceId();
+
+ /** Returns a list of additional preference controllers */
+ List<PreferenceController> getControllers(Context context, Lifecycle lifecycle);
+
}
diff --git a/src/com/android/settings/gestures/AssistGestureFeatureProviderImpl.java b/src/com/android/settings/gestures/AssistGestureFeatureProviderImpl.java
index b17d892..a2579ac 100644
--- a/src/com/android/settings/gestures/AssistGestureFeatureProviderImpl.java
+++ b/src/com/android/settings/gestures/AssistGestureFeatureProviderImpl.java
@@ -18,6 +18,13 @@
import android.content.Context;
+import com.android.settings.R;
+import com.android.settings.core.PreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.util.ArrayList;
+import java.util.List;
+
public class AssistGestureFeatureProviderImpl implements AssistGestureFeatureProvider {
@Override
@@ -25,4 +32,19 @@
return false;
}
+ @Override
+ public boolean isSensorAvailable(Context context) {
+ return false;
+ }
+
+ @Override
+ public int getPreferenceResourceId() {
+ return R.xml.assist_gesture_settings;
+ }
+
+ @Override
+ public List<PreferenceController> getControllers(Context context, Lifecycle lifecycle) {
+ return new ArrayList<>();
+ }
+
}
diff --git a/src/com/android/settings/gestures/AssistGestureSensitivityPreferenceController.java b/src/com/android/settings/gestures/AssistGestureSensitivityPreferenceController.java
deleted file mode 100644
index 0f42803..0000000
--- a/src/com/android/settings/gestures/AssistGestureSensitivityPreferenceController.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.gestures;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.provider.Settings;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-
-import com.android.settings.widget.SeekBarPreference;
-import com.android.settings.core.PreferenceController;
-import com.android.settings.overlay.FeatureFactory;
-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;
-
-public class AssistGestureSensitivityPreferenceController extends PreferenceController
- implements Preference.OnPreferenceChangeListener, LifecycleObserver, OnPause, OnResume {
-
- private static final String PREF_KEY_ASSIST_GESTURE_SENSITIVITY = "gesture_assist_sensitivity";
-
- private final AssistGestureFeatureProvider mFeatureProvider;
- private final SettingObserver mSettingObserver;
-
- private PreferenceScreen mScreen;
- private SeekBarPreference mPreference;
-
- public AssistGestureSensitivityPreferenceController(Context context, Lifecycle lifecycle) {
- super(context);
- mFeatureProvider = FeatureFactory.getFactory(context).getAssistGestureFeatureProvider();
- mSettingObserver = new SettingObserver();
-
- if (lifecycle != null) {
- lifecycle.addObserver(this);
- }
- }
-
- @Override
- public void onResume() {
- mSettingObserver.register(mContext.getContentResolver(), true /* register */);
- updatePreference();
- }
-
- @Override
- public void onPause() {
- mSettingObserver.register(mContext.getContentResolver(), false /* register */);
- }
-
- @Override
- public boolean isAvailable() {
- // The sensitivity control is contingent on the assist gesture being supported and the
- // gesture being enabled.
- final int gestureEnabled = Settings.Secure.getInt(
- mContext.getContentResolver(),
- Settings.Secure.ASSIST_GESTURE_ENABLED,
- 1);
- return (gestureEnabled == 1) && mFeatureProvider.isSupported(mContext);
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- mScreen = screen;
- mPreference = (SeekBarPreference) screen.findPreference(getPreferenceKey());
- // Call super last or AbstractPreferenceController might remove the preference from the
- // screen (if !isAvailable()) before we can save a reference to it.
- super.displayPreference(screen);
- }
-
- @Override
- public void updateState(Preference preference) {
- super.updateState(preference);
- updatePreference();
- }
-
- private void updatePreference() {
- if (mPreference == null) {
- return;
- }
-
- if (isAvailable()) {
- if (mScreen.findPreference(getPreferenceKey()) == null) {
- mScreen.addPreference(mPreference);
- }
- } else {
- mScreen.removePreference(mPreference);
- }
-
- final int sensitivity = Settings.Secure.getInt(
- mContext.getContentResolver(),
- Settings.Secure.ASSIST_GESTURE_SENSITIVITY,
- mPreference.getProgress());
- mPreference.setProgress(sensitivity);
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final int sensitivity = (int) newValue;
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.ASSIST_GESTURE_SENSITIVITY, sensitivity);
- return true;
- }
-
- @Override
- public String getPreferenceKey() {
- return PREF_KEY_ASSIST_GESTURE_SENSITIVITY;
- }
-
- class SettingObserver extends ContentObserver {
-
- private final Uri ASSIST_GESTURE_ENABLED_URI =
- Settings.Secure.getUriFor(Settings.Secure.ASSIST_GESTURE_ENABLED);
- private final Uri ASSIST_GESTURE_SENSITIVITY_URI =
- Settings.Secure.getUriFor(Settings.Secure.ASSIST_GESTURE_SENSITIVITY);
-
- public SettingObserver() {
- super(null /* handler */);
- }
-
- public void register(ContentResolver cr, boolean register) {
- if (register) {
- cr.registerContentObserver(ASSIST_GESTURE_ENABLED_URI, false, this);
- cr.registerContentObserver(ASSIST_GESTURE_SENSITIVITY_URI, false, this);
- } else {
- cr.unregisterContentObserver(this);
- }
- }
-
- @Override
- public void onChange(boolean selfChange) {
- updatePreference();
- }
- }
-}
diff --git a/src/com/android/settings/gestures/AssistGestureSettings.java b/src/com/android/settings/gestures/AssistGestureSettings.java
index 64187a3..93d3a39 100644
--- a/src/com/android/settings/gestures/AssistGestureSettings.java
+++ b/src/com/android/settings/gestures/AssistGestureSettings.java
@@ -23,6 +23,7 @@
import com.android.settings.R;
import com.android.settings.core.PreferenceController;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -48,7 +49,8 @@
@Override
protected int getPreferenceScreenResId() {
- return R.xml.assist_gesture_settings;
+ return FeatureFactory.getFactory(getContext())
+ .getAssistGestureFeatureProvider().getPreferenceResourceId();
}
@Override
@@ -60,7 +62,9 @@
Lifecycle lifecycle) {
final List<PreferenceController> controllers = new ArrayList<>();
controllers.add(new AssistGesturePreferenceController(context, lifecycle, KEY_ASSIST));
- controllers.add(new AssistGestureSensitivityPreferenceController(context, lifecycle));
+ controllers.addAll(FeatureFactory.getFactory(context).getAssistGestureFeatureProvider()
+ .getControllers(context, lifecycle));
+
return controllers;
}
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 48ca207..78b763c 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -264,12 +264,9 @@
protected void addAppLinkPref() {
if (mAppRow.settingsIntent != null && mAppLink == null) {
- mAppLink = new Preference(getPrefContext());
- mAppLink.setKey(KEY_APP_LINK);
- mAppLink.setOrder(500);
+ addPreferencesFromResource(R.xml.inapp_notification_settings);
+ mAppLink = (Preference) findPreference(KEY_APP_LINK);
mAppLink.setIntent(mAppRow.settingsIntent);
- mAppLink.setTitle(mContext.getString(R.string.app_settings_link));
- getPreferenceScreen().addPreference(mAppLink);
}
}
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index d4bc076..b41a40f 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -201,7 +201,7 @@
private String mFirstPin;
private RecyclerView mPasswordRestrictionView;
protected boolean mIsAlphaMode;
- private Button mCancelButton;
+ protected Button mCancelButton;
private Button mNextButton;
private TextChangedHandler mTextChangedHandler;
diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java
index 9a494cb..69498a9 100644
--- a/src/com/android/settings/password/ConfirmLockPassword.java
+++ b/src/com/android/settings/password/ConfirmLockPassword.java
@@ -44,6 +44,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.settings.R;
+import com.android.settings.widget.ImeAwareEditText;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
@@ -93,7 +94,7 @@
CredentialCheckResultTracker.Listener {
private static final long ERROR_MESSAGE_TIMEOUT = 3000;
private static final String FRAGMENT_TAG_CHECK_LOCK_RESULT = "check_lock_result";
- private TextView mPasswordEntry;
+ private ImeAwareEditText mPasswordEntry;
private TextViewInputDisabler mPasswordEntryInputDisabler;
private AsyncTask<?, ?, ?> mPendingLockCheck;
private CredentialCheckResultTracker mCredentialCheckResultTracker;
@@ -132,7 +133,7 @@
container,
false);
- mPasswordEntry = (TextView) view.findViewById(R.id.password_entry);
+ mPasswordEntry = (ImeAwareEditText) view.findViewById(R.id.password_entry);
mPasswordEntry.setOnEditorActionListener(this);
// EditText inside ScrollView doesn't automatically get focus.
mPasswordEntry.requestFocus();
@@ -310,7 +311,7 @@
mPasswordEntry.setEnabled(true);
mPasswordEntryInputDisabler.setInputEnabled(true);
if (shouldAutoShowSoftKeyboard()) {
- mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+ mPasswordEntry.scheduleShowSoftInput();
}
}
diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java
index 4e73b87..179bd79 100644
--- a/src/com/android/settings/password/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/password/SetupChooseLockGeneric.java
@@ -35,7 +35,6 @@
import com.android.settings.SetupEncryptionInterstitial;
import com.android.settings.SetupWizardUtils;
import com.android.settings.fingerprint.SetupFingerprintEnrollFindSensor;
-import com.android.settings.fingerprint.SetupSkipDialog;
import com.android.settings.utils.SettingsDividerItemDecoration;
import com.android.setupwizardlib.GlifPreferenceLayout;
diff --git a/src/com/android/settings/password/SetupChooseLockPassword.java b/src/com/android/settings/password/SetupChooseLockPassword.java
index 0c62c7c..bd935a2 100644
--- a/src/com/android/settings/password/SetupChooseLockPassword.java
+++ b/src/com/android/settings/password/SetupChooseLockPassword.java
@@ -84,6 +84,9 @@
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+
+ mCancelButton.setText(R.string.skip_label);
+
boolean showOptionsButton = getActivity().getIntent().getBooleanExtra(
ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, false);
if (showOptionsButton) {
@@ -99,6 +102,12 @@
case R.id.screen_lock_options:
launchChooseLockGeneric();
break;
+ case R.id.cancel_button:
+ SetupSkipDialog dialog = SetupSkipDialog.newInstance(
+ getActivity().getIntent()
+ .getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false));
+ dialog.show(getFragmentManager());
+ break;
default:
super.onClick(v);
}
diff --git a/src/com/android/settings/fingerprint/SetupSkipDialog.java b/src/com/android/settings/password/SetupSkipDialog.java
similarity index 94%
rename from src/com/android/settings/fingerprint/SetupSkipDialog.java
rename to src/com/android/settings/password/SetupSkipDialog.java
index 842e69c..36646b7 100644
--- a/src/com/android/settings/fingerprint/SetupSkipDialog.java
+++ b/src/com/android/settings/password/SetupSkipDialog.java
@@ -14,12 +14,11 @@
* limitations under the License
*/
-package com.android.settings.fingerprint;
+package com.android.settings.password;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.os.Bundle;
@@ -36,7 +35,7 @@
private static final String ARG_FRP_SUPPORTED = "frp_supported";
private static final String TAG_SKIP_DIALOG = "skip_dialog";
- private static final int RESULT_SKIP = Activity.RESULT_FIRST_USER + 10;
+ public static final int RESULT_SKIP = Activity.RESULT_FIRST_USER + 10;
public static SetupSkipDialog newInstance(boolean isFrpSupported) {
SetupSkipDialog dialog = new SetupSkipDialog();
diff --git a/src/com/android/settings/search/AppSearchResult.java b/src/com/android/settings/search/AppSearchResult.java
index fcb83dc..b59e32e 100644
--- a/src/com/android/settings/search/AppSearchResult.java
+++ b/src/com/android/settings/search/AppSearchResult.java
@@ -18,6 +18,7 @@
package com.android.settings.search;
import android.content.pm.ApplicationInfo;
+import android.os.UserHandle;
public class AppSearchResult extends SearchResult {
/**
@@ -30,6 +31,10 @@
info = builder.mInfo;
}
+ public UserHandle getAppUserHandle() {
+ return new UserHandle(UserHandle.getUserId(info.uid));
+ }
+
public static class Builder extends SearchResult.Builder {
protected ApplicationInfo mInfo;
diff --git a/src/com/android/settings/search/InstalledAppResultLoader.java b/src/com/android/settings/search/InstalledAppResultLoader.java
index 81b96a1..70a39ee 100644
--- a/src/com/android/settings/search/InstalledAppResultLoader.java
+++ b/src/com/android/settings/search/InstalledAppResultLoader.java
@@ -40,6 +40,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -99,7 +100,7 @@
final AppSearchResult.Builder builder = new AppSearchResult.Builder();
builder.setAppInfo(info)
- .setStableId(info.packageName.hashCode())
+ .setStableId(Objects.hash(info.packageName, user.id))
.setTitle(info.loadLabel(pm))
.setRank(getRank(wordDiff))
.addBreadcrumbs(getBreadCrumb())
diff --git a/src/com/android/settings/search/IntentSearchViewHolder.java b/src/com/android/settings/search/IntentSearchViewHolder.java
index 11adaef..2722d56 100644
--- a/src/com/android/settings/search/IntentSearchViewHolder.java
+++ b/src/com/android/settings/search/IntentSearchViewHolder.java
@@ -16,9 +16,11 @@
*/
package com.android.settings.search;
+import android.content.Intent;
+import android.os.UserHandle;
import android.view.View;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto;
/**
* ViewHolder for intent based search results.
@@ -32,7 +34,7 @@
@Override
public int getClickActionMetricName() {
- return MetricsEvent.ACTION_CLICK_SETTINGS_SEARCH_RESULT;
+ return MetricsProto.MetricsEvent.ACTION_CLICK_SETTINGS_SEARCH_RESULT;
}
@Override
@@ -41,7 +43,15 @@
itemView.setOnClickListener(v -> {
fragment.onSearchResultClicked(this, result);
- fragment.startActivity(result.payload.getIntent());
+ final Intent intent = result.payload.getIntent();
+ // Use app user id to support work profile use case.
+ if (result instanceof AppSearchResult) {
+ AppSearchResult appResult = (AppSearchResult) result;
+ UserHandle userHandle = appResult.getAppUserHandle();
+ fragment.getActivity().startActivityAsUser(intent, userHandle);
+ } else {
+ fragment.startActivity(intent);
+ }
});
}
}
diff --git a/src/com/android/settings/search/SearchViewHolder.java b/src/com/android/settings/search/SearchViewHolder.java
index 72fd02320..ed72940 100644
--- a/src/com/android/settings/search/SearchViewHolder.java
+++ b/src/com/android/settings/search/SearchViewHolder.java
@@ -18,8 +18,11 @@
import android.content.Context;
import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
+import android.util.IconDrawableFactory;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@@ -46,6 +49,7 @@
protected final MetricsFeatureProvider mMetricsFeatureProvider;
protected final SearchFeatureProvider mSearchFeatureProvider;
+ private final IconDrawableFactory mIconDrawableFactory;
public SearchViewHolder(View view) {
super(view);
@@ -59,6 +63,7 @@
breadcrumbView = view.findViewById(R.id.breadcrumb);
mPlaceholderSummary = view.getContext().getString(R.string.summary_placeholder);
+ mIconDrawableFactory = IconDrawableFactory.newInstance(view.getContext());
}
public abstract int getClickActionMetricName();
@@ -78,7 +83,12 @@
if (result instanceof AppSearchResult) {
AppSearchResult appResult = (AppSearchResult) result;
PackageManager pm = fragment.getActivity().getPackageManager();
- iconView.setImageDrawable(appResult.info.loadIcon(pm));
+ UserHandle userHandle = appResult.getAppUserHandle();
+ Drawable badgedIcon =
+ mIconDrawableFactory.getBadgedIcon(appResult.info, userHandle.getIdentifier());
+ iconView.setImageDrawable(badgedIcon);
+ titleView.setContentDescription(
+ pm.getUserBadgedLabel(appResult.info.loadLabel(pm), userHandle));
} else {
// Valid even when result.icon is null.
iconView.setImageDrawable(result.icon);
diff --git a/src/com/android/settings/widget/ScrollToParentEditText.java b/src/com/android/settings/widget/ScrollToParentEditText.java
index 97602af..705e918 100644
--- a/src/com/android/settings/widget/ScrollToParentEditText.java
+++ b/src/com/android/settings/widget/ScrollToParentEditText.java
@@ -23,12 +23,14 @@
import android.view.ViewParent;
import android.widget.EditText;
+import com.android.settings.widget.ImeAwareEditText;
+
/**
* An EditText that, instead of scrolling to itself when focused, will request scrolling to its
* parent. This is used in ChooseLockPassword to do make a best effort for not hiding the error
* messages for why the password is invalid under the keyboard.
*/
-public class ScrollToParentEditText extends EditText {
+public class ScrollToParentEditText extends ImeAwareEditText {
private Rect mRect = new Rect();
diff --git a/src/com/android/settings/widget/ValidatedEditTextPreference.java b/src/com/android/settings/widget/ValidatedEditTextPreference.java
new file mode 100644
index 0000000..53ff37a
--- /dev/null
+++ b/src/com/android/settings/widget/ValidatedEditTextPreference.java
@@ -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);
+ }
+ }
+ }
+
+}
diff --git a/src/com/android/settings/wifi/WifiApEnabler.java b/src/com/android/settings/wifi/WifiApEnabler.java
index 5d725d8..675bf28 100644
--- a/src/com/android/settings/wifi/WifiApEnabler.java
+++ b/src/com/android/settings/wifi/WifiApEnabler.java
@@ -32,6 +32,10 @@
import java.util.ArrayList;
+/**
+ * @deprecated in favor of WifiTetherPreferenceController and WifiTetherSettings
+ */
+@Deprecated
public class WifiApEnabler {
private final Context mContext;
private final SwitchPreference mSwitch;
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 2a17dfc..6f87342 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -110,7 +110,6 @@
public static final int WIFI_PEAP_PHASE2_AKA = 4;
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 */
private final ArrayAdapter<String> mPhase2PeapAdapter;
@@ -463,7 +462,7 @@
if (mSsidView != null) {
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);
}
}
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 6d575d8..3cfb17d 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -43,7 +43,6 @@
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
-import android.support.v7.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
@@ -321,7 +320,6 @@
if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) {
mOpenSsid = intent.getStringExtra(EXTRA_START_CONNECT_SSID);
- updateAccessPointsDelayed();
}
}
@@ -354,13 +352,28 @@
onWifiStateChanged(mWifiManager.getWifiState());
}
- private void forceUpdateAPs() {
+ /**
+ * Only update the AP list if there are not any APs currently shown.
+ *
+ * <p>Thus forceUpdate will only be called during cold start or when toggling between wifi on
+ * and off. In other use cases, the previous APs will remain until the next update is received
+ * from {@link WifiTracker}.
+ */
+ private void conditionallyForceUpdateAPs() {
+ if (mAccessPointsPreferenceCategory.getPreferenceCount() > 0
+ && mAccessPointsPreferenceCategory.getPreference(0) instanceof
+ AccessPointPreference) {
+ // Make sure we don't update due to callbacks initiated by sticky broadcasts in
+ // WifiTracker.
+ Log.d(TAG, "Did not force update APs due to existing APs displayed");
+ getView().removeCallbacks(mUpdateAccessPointsRunnable);
+ return;
+ }
setProgressBarVisible(true);
mWifiTracker.forceUpdate();
if (DEBUG) {
Log.d(TAG, "WifiSettings force update APs: " + mWifiTracker.getAccessPoints());
}
-
getView().removeCallbacks(mUpdateAccessPointsRunnable);
updateAccessPointPreferences();
}
@@ -654,6 +667,7 @@
*/
@Override
public void onAccessPointsChanged() {
+ Log.d(TAG, "onAccessPointsChanged (WifiTracker) callback initiated");
updateAccessPointsDelayed();
}
@@ -679,7 +693,7 @@
final int wifiState = mWifiManager.getWifiState();
switch (wifiState) {
case WifiManager.WIFI_STATE_ENABLED:
- forceUpdateAPs();
+ conditionallyForceUpdateAPs();
break;
case WifiManager.WIFI_STATE_ENABLING:
@@ -720,6 +734,9 @@
}
// AccessPoints are sorted by the WifiTracker
final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
+ if (DEBUG) {
+ Log.d(TAG, "updateAccessPoints called for: " + accessPoints);
+ }
boolean hasAvailableAccessPoints = false;
mAccessPointsPreferenceCategory.removePreference(mStatusMessagePreference);
@@ -1015,6 +1032,7 @@
@Override
public void onAccessPointChanged(final AccessPoint accessPoint) {
+ Log.d(TAG, "onAccessPointChanged (singular) callback initiated");
View view = getView();
if (view != null) {
view.post(new Runnable() {
diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java
new file mode 100644
index 0000000..7bd69db
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiUtils.java
@@ -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;
+ }
+}
diff --git a/src/com/android/settings/wifi/tether/NoOpOnStartTetheringCallback.java b/src/com/android/settings/wifi/tether/NoOpOnStartTetheringCallback.java
new file mode 100644
index 0000000..fc1719c
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/NoOpOnStartTetheringCallback.java
@@ -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 {
+
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java
new file mode 100644
index 0000000..37da38e
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java
@@ -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;
+ }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherBasePreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherBasePreferenceController.java
new file mode 100644
index 0000000..eb21175
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherBasePreferenceController.java
@@ -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());
+ }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
new file mode 100644
index 0000000..a929b86
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
@@ -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);
+ }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
new file mode 100644
index 0000000..46fb7a9
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
@@ -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
+ //
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
new file mode 100644
index 0000000..a4c6c67
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
@@ -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);
+ }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
new file mode 100644
index 0000000..2584ed4
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -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();
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
new file mode 100644
index 0000000..e3c6098
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
@@ -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);
+ }
+ }
+}
diff --git a/tests/app/src/com/android/settings/password/SetupChooseLockPasswordAppTest.java b/tests/app/src/com/android/settings/password/SetupChooseLockPasswordAppTest.java
new file mode 100644
index 0000000..78acc3e
--- /dev/null
+++ b/tests/app/src/com/android/settings/password/SetupChooseLockPasswordAppTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.password;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+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.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.settings.R;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class SetupChooseLockPasswordAppTest {
+
+ @Rule
+ public ActivityTestRule<SetupChooseLockPassword> mActivityTestRule =
+ new ActivityTestRule<>(
+ SetupChooseLockPassword.class,
+ true /* enable touch at launch */,
+ false /* don't launch at every test */);
+
+ @Test
+ public void testSkipDialogIsShown() throws Throwable {
+ SetupChooseLockPassword activity = mActivityTestRule.launchActivity(null);
+
+ onView(withId(R.id.cancel_button))
+ .check(matches(withText(R.string.skip_label)))
+ .check(matches(isDisplayed()))
+ .perform(click());
+ onView(withId(android.R.id.button1)).check(matches(isDisplayed())).perform(click());
+
+ assertThat(activity.isFinishing()).named("Is finishing").isTrue();
+ }
+}
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index b9e328c..d901a11 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -13,3 +13,4 @@
com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMicrophone
com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages
com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment
+com.android.settings.wifi.tether.WifiTetherSettings
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
index 81b563f..fb06917 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
@@ -74,16 +74,16 @@
}
@Test
- public void testCategory_isAccount() {
+ public void testCategory_isAccountDetail() {
assertThat(new AccountDetailDashboardFragment().getCategoryKey())
- .isEqualTo(CategoryKey.CATEGORY_ACCOUNT);
+ .isEqualTo(CategoryKey.CATEGORY_ACCOUNT_DETAIL);
}
@Test
public void refreshDashboardTiles_HasAccountType_shouldDisplay() {
final Tile tile = new Tile();
final Bundle metaData = new Bundle();
- metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
+ metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT_DETAIL);
metaData.putString(METADATA_ACCOUNT_TYPE, "com.abc");
tile.metaData = metaData;
@@ -94,7 +94,7 @@
public void refreshDashboardTiles_NoAccountType_shouldNotDisplay() {
final Tile tile = new Tile();
final Bundle metaData = new Bundle();
- metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
+ metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT_DETAIL);
tile.metaData = metaData;
assertThat(mFragment.displayTile(tile)).isFalse();
@@ -104,7 +104,7 @@
public void refreshDashboardTiles_OtherAccountType_shouldNotDisplay() {
final Tile tile = new Tile();
final Bundle metaData = new Bundle();
- metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
+ metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT_DETAIL);
metaData.putString(METADATA_ACCOUNT_TYPE, "com.other");
tile.metaData = metaData;
diff --git a/tests/robotests/src/com/android/settings/accounts/UserAndAccountDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/UserAndAccountDashboardFragmentTest.java
index d4a7a9d..8c13aab 100644
--- a/tests/robotests/src/com/android/settings/accounts/UserAndAccountDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/UserAndAccountDashboardFragmentTest.java
@@ -67,27 +67,6 @@
}
@Test
- public void refreshDashboardTiles_HasAccountType_shouldNotDisplay() {
- final Tile tile = new Tile();
- final Bundle metaData = new Bundle();
- metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
- metaData.putString(METADATA_ACCOUNT_TYPE, "com.abc");
- tile.metaData = metaData;
-
- assertThat(mFragment.displayTile(tile)).isFalse();
- }
-
- @Test
- public void refreshDashboardTiles_NoAccountType_shouldDisplay() {
- final Tile tile = new Tile();
- final Bundle metaData = new Bundle();
- metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
- tile.metaData = metaData;
-
- assertThat(mFragment.displayTile(tile)).isTrue();
- }
-
- @Test
public void updateSummary_shouldDisplaySignedInUser() {
final Activity activity = mock(Activity.class);
final SummaryLoader loader = mock(SummaryLoader.class);
diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
index bfc5cd3..2b18e05 100644
--- a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
@@ -68,6 +68,8 @@
private PreferenceCategory mCategory;
@Mock
private Preference mSeeAllPref;
+ @Mock
+ private PreferenceCategory mDivider;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mMockContext;
@Mock
@@ -94,6 +96,8 @@
when(mScreen.findPreference(RecentAppsPreferenceController.KEY_SEE_ALL))
.thenReturn(mSeeAllPref);
+ when(mScreen.findPreference(RecentAppsPreferenceController.KEY_DIVIDER))
+ .thenReturn(mDivider);
when(mCategory.getContext()).thenReturn(mContext);
}
@@ -108,7 +112,8 @@
mController.updateNonIndexableKeys(nonIndexable);
- assertThat(nonIndexable).containsExactly(mController.getPreferenceKey());
+ assertThat(nonIndexable).containsAllOf(mController.getPreferenceKey(),
+ RecentAppsPreferenceController.KEY_DIVIDER);
}
@Test
@@ -136,6 +141,7 @@
verify(mCategory).setTitle(null);
verify(mSeeAllPref).setTitle(R.string.applications_settings);
verify(mSeeAllPref).setIcon(null);
+ verify(mDivider).setVisible(false);
}
@Test
@@ -180,6 +186,7 @@
verify(mSeeAllPref).setSummary(null);
verify(mSeeAllPref).setIcon(R.drawable.ic_chevron_right_24dp);
+ verify(mDivider).setVisible(true);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/core/codeinspection/CodeInspectionTest.java b/tests/robotests/src/com/android/settings/core/codeinspection/CodeInspectionTest.java
index 23e1e2e..d05bee6 100644
--- a/tests/robotests/src/com/android/settings/core/codeinspection/CodeInspectionTest.java
+++ b/tests/robotests/src/com/android/settings/core/codeinspection/CodeInspectionTest.java
@@ -16,10 +16,10 @@
package com.android.settings.core.codeinspection;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.core.instrumentation.InstrumentableFragmentCodeInspector;
import com.android.settings.search.SearchIndexProviderCodeInspector;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java
new file mode 100644
index 0000000..9ee53ef
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java
@@ -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.fingerprint;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.RuntimeEnvironment.application;
+
+import android.app.KeyguardManager;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.view.View;
+import android.widget.Button;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.password.SetupSkipDialog;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowEventLogWriter;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowActivity;
+import org.robolectric.shadows.ShadowKeyguardManager;
+import org.robolectric.util.ActivityController;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(
+ manifest = TestConfig.MANIFEST_PATH,
+ sdk = TestConfig.SDK_VERSION,
+ shadows = {
+ ShadowEventLogWriter.class,
+ ShadowLockPatternUtils.class,
+ ShadowUserManager.class
+ })
+public class SetupFingerprintEnrollIntroductionTest {
+
+ @Mock
+ private UserInfo mUserInfo;
+
+ private ActivityController<SetupFingerprintEnrollIntroduction> mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ final Intent intent = new Intent();
+ mController = Robolectric.buildActivity(SetupFingerprintEnrollIntroduction.class, intent);
+
+ ShadowUserManager.getShadow().setUserInfo(0, mUserInfo);
+ }
+
+ @Test
+ public void testKeyguardNotSecure_shouldFinishWithSetupSkipDialogResultSkip() {
+ getShadowKeyguardManager().setIsKeyguardSecure(false);
+
+ mController.create().resume();
+
+ final Button skipButton = mController.get().findViewById(R.id.fingerprint_cancel_button);
+ assertThat(skipButton.getVisibility()).named("Skip visible").isEqualTo(View.VISIBLE);
+ skipButton.performClick();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(mController.get());
+ assertThat(mController.get().isFinishing()).named("Is finishing").isTrue();
+ assertThat(shadowActivity.getResultCode()).named("Result code")
+ .isEqualTo(SetupSkipDialog.RESULT_SKIP);
+ }
+
+ @Test
+ public void testKeyguardSecure_shouldFinishWithFingerprintResultSkip() {
+ getShadowKeyguardManager().setIsKeyguardSecure(true);
+
+ mController.create().resume();
+
+ final Button skipButton = mController.get().findViewById(R.id.fingerprint_cancel_button);
+ assertThat(skipButton.getVisibility()).named("Skip visible").isEqualTo(View.VISIBLE);
+ skipButton.performClick();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(mController.get());
+ assertThat(mController.get().isFinishing()).named("Is finishing").isTrue();
+ assertThat(shadowActivity.getResultCode()).named("Result code")
+ .isEqualTo(FingerprintEnrollBase.RESULT_SKIP);
+ }
+
+ private ShadowKeyguardManager getShadowKeyguardManager() {
+ return Shadows.shadowOf(application.getSystemService(KeyguardManager.class));
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragmentTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragmentTest.java
index 8f3d2db..365a14a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragmentTest.java
@@ -40,46 +40,77 @@
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AnomalyDialogFragmentTest {
- @Anomaly.AnomalyType
- private static final int ANOMALY_TYPE = Anomaly.AnomalyType.WAKE_LOCK;
private static final String PACKAGE_NAME = "com.android.app";
+ private static final String DISPLAY_NAME = "app";
private static final int UID = 111;
- private Anomaly mAnomaly;
+ private Anomaly mWakeLockAnomaly;
+ private Anomaly mWakeupAlarmAnomaly;
private AnomalyDialogFragment mAnomalyDialogFragment;
private Context mContext;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
- mAnomaly = new Anomaly.Builder()
- .setType(ANOMALY_TYPE)
+ mWakeLockAnomaly = new Anomaly.Builder()
+ .setType(Anomaly.AnomalyType.WAKE_LOCK)
.setUid(UID)
.setPackageName(PACKAGE_NAME)
+ .setDisplayName(DISPLAY_NAME)
.build();
-
- mAnomalyDialogFragment = AnomalyDialogFragment.newInstance(mAnomaly, 0 /* metricskey */);
+ mWakeupAlarmAnomaly = new Anomaly.Builder()
+ .setType(Anomaly.AnomalyType.WAKEUP_ALARM)
+ .setUid(UID)
+ .setPackageName(PACKAGE_NAME)
+ .setDisplayName(DISPLAY_NAME)
+ .build();
}
@Test
public void testOnCreateDialog_hasCorrectData() {
+ mAnomalyDialogFragment = AnomalyDialogFragment.newInstance(mWakeLockAnomaly,
+ 0 /* metricskey */);
FragmentTestUtil.startFragment(mAnomalyDialogFragment);
- assertThat(mAnomalyDialogFragment.mAnomaly).isEqualTo(mAnomaly);
+ assertThat(mAnomalyDialogFragment.mAnomaly).isEqualTo(mWakeLockAnomaly);
}
@Test
- public void testOnCreateDialog_hasCorrectDialog() {
+ public void testOnCreateDialog_wakelockAnomaly_fireForceStopDialog() {
+ mAnomalyDialogFragment = AnomalyDialogFragment.newInstance(mWakeLockAnomaly,
+ 0 /* metricskey */);
+
FragmentTestUtil.startFragment(mAnomalyDialogFragment);
final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog();
ShadowAlertDialog shadowDialog = shadowOf(dialog);
assertThat(shadowDialog.getMessage()).isEqualTo(
- mContext.getString(R.string.force_stop_dlg_text));
+ mContext.getString(R.string.dialog_stop_message, mWakeLockAnomaly.displayName));
assertThat(shadowDialog.getTitle()).isEqualTo(
- mContext.getString(R.string.force_stop_dlg_title));
+ mContext.getString(R.string.dialog_stop_title));
assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).getText()).isEqualTo(
- mContext.getString(R.string.dlg_ok));
+ mContext.getString(R.string.dialog_stop_ok));
+ assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText()).isEqualTo(
+ mContext.getString(R.string.dlg_cancel));
+ }
+
+ @Test
+ public void testOnCreateDialog_wakeupAlarmAnomaly_fireBackgroundCheckDialog() {
+ mAnomalyDialogFragment = AnomalyDialogFragment.newInstance(mWakeupAlarmAnomaly,
+ 0 /* metricskey */);
+
+ FragmentTestUtil.startFragment(mAnomalyDialogFragment);
+
+ final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog();
+ ShadowAlertDialog shadowDialog = shadowOf(dialog);
+
+ assertThat(shadowDialog.getMessage()).isEqualTo(
+ mContext.getString(R.string.dialog_background_check_message,
+ mWakeLockAnomaly.displayName));
+ assertThat(shadowDialog.getTitle()).isEqualTo(
+ mContext.getString(R.string.dialog_background_check_title));
+ assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).getText()).isEqualTo(
+ mContext.getString(R.string.dialog_background_check_ok));
assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText()).isEqualTo(
mContext.getString(R.string.dlg_cancel));
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckActionTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckActionTest.java
index 99f7c33..ae783ab 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckActionTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckActionTest.java
@@ -16,6 +16,8 @@
package com.android.settings.fuelgauge.anomaly.action;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
@@ -69,4 +71,20 @@
verify(mAppOpsManagerr).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME,
AppOpsManager.MODE_IGNORED);
}
+
+ @Test
+ public void testIsActionActive_modeAllowed_returnTrue() {
+ doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManagerr).checkOpNoThrow(
+ AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME);
+
+ assertThat(mBackgroundCheckAction.isActionActive(mAnomaly)).isTrue();
+ }
+
+ @Test
+ public void testIsActionActive_modeIgnored_returnFalse() {
+ doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManagerr).checkOpNoThrow(
+ AppOpsManager.OP_RUN_IN_BACKGROUND, UID, PACKAGE_NAME);
+
+ assertThat(mBackgroundCheckAction.isActionActive(mAnomaly)).isFalse();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/ForceStopActionTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/ForceStopActionTest.java
index 7bb6a04..89b1a16 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/ForceStopActionTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/ForceStopActionTest.java
@@ -16,11 +16,15 @@
package com.android.settings.fuelgauge.anomaly.action;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
@@ -44,15 +48,22 @@
private Context mContext;
@Mock
private ActivityManager mActivityManager;
+ @Mock
+ private ApplicationInfo mApplicationInfo;
+ @Mock
+ private PackageManager mPackageManager;
private Anomaly mAnomaly;
private ForceStopAction mForceStopAction;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest(mContext);
doReturn(mActivityManager).when(mContext).getSystemService(Context.ACTIVITY_SERVICE);
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME,
+ PackageManager.GET_META_DATA);
mAnomaly = new Anomaly.Builder()
.setPackageName(PACKAGE_NAME)
@@ -66,4 +77,18 @@
verify(mActivityManager).forceStopPackage(PACKAGE_NAME);
}
+
+ @Test
+ public void testIsActionActive_appStopped_returnFalse() {
+ mApplicationInfo.flags = ApplicationInfo.FLAG_STOPPED;
+
+ assertThat(mForceStopAction.isActionActive(mAnomaly)).isFalse();
+ }
+
+ @Test
+ public void testIsActionActive_appRunning_returnTrue() {
+ mApplicationInfo.flags = 0;
+
+ assertThat(mForceStopAction.isActionActive(mAnomaly)).isTrue();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetectorTest.java
index 64e3840..386e162 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeLockAnomalyDetectorTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
@@ -39,6 +40,7 @@
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy;
+import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
import org.junit.Before;
import org.junit.Test;
@@ -96,6 +98,8 @@
private ApplicationInfo mApplicationInfo;
@Mock
private AnomalyDetectionPolicy mPolicy;
+ @Mock
+ private AnomalyAction mAnomalyAction;
private ArrayMap<String, BatteryStats.Uid.Wakelock> mAnomalyWakelocks;
private ArrayMap<String, BatteryStats.Uid.Wakelock> mNormalWakelocks;
@@ -115,6 +119,7 @@
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mApplicationInfo).when(mPackageManager)
.getApplicationInfo(nullable(String.class), anyInt());
+ doReturn(true).when(mAnomalyAction).isActionActive(any());
mAnomalySipper.uidObj = mAnomalyUid;
mAnomalyWakelocks = new ArrayMap<>();
@@ -145,6 +150,7 @@
mWakelockAnomalyDetector = spy(new WakeLockAnomalyDetector(mContext, mPolicy));
mWakelockAnomalyDetector.mBatteryUtils = mBatteryUtils;
+ mWakelockAnomalyDetector.mAnomalyAction = mAnomalyAction;
doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector).getTotalDurationMs(
eq(mAnomalyTimer), anyLong());
doReturn(ANOMALY_WAKELOCK_TIME_MS).when(mWakelockAnomalyDetector).getTotalDurationMs(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java
index e6cdc4e..21b2e54 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java
@@ -38,6 +38,7 @@
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy;
+import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
import org.junit.Before;
import org.junit.Test;
@@ -85,6 +86,8 @@
private BatteryStats.Counter mCounter;
@Mock
private AnomalyDetectionPolicy mPolicy;
+ @Mock
+ private AnomalyAction mAnomalyAction;
private WakeupAlarmAnomalyDetector mWakeupAlarmAnomalyDetector;
private Context mContext;
@@ -100,6 +103,7 @@
doReturn(false).when(mBatteryUtils).shouldHideSipper(any());
doReturn(RUNNING_TIME_MS).when(mBatteryUtils).calculateRunningTimeBasedOnStatsType(any(),
anyInt());
+ doReturn(true).when(mAnomalyAction).isActionActive(any());
mAnomalySipper.uidObj = mAnomalyUid;
doReturn(ANOMALY_UID).when(mAnomalyUid).getUid();
@@ -116,6 +120,7 @@
mWakeupAlarmAnomalyDetector = spy(new WakeupAlarmAnomalyDetector(mContext, mPolicy));
mWakeupAlarmAnomalyDetector.mBatteryUtils = mBatteryUtils;
+ mWakeupAlarmAnomalyDetector.mAnomalyAction = mAnomalyAction;
}
@Test
diff --git a/tests/robotests/src/com/android/settings/gestures/AssistGestureSensitivityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/AssistGestureSensitivityPreferenceControllerTest.java
deleted file mode 100644
index 349ca4f..0000000
--- a/tests/robotests/src/com/android/settings/gestures/AssistGestureSensitivityPreferenceControllerTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.gestures;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.TestConfig;
-import com.android.settings.testutils.FakeFeatureFactory;
-
-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.annotation.Config;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class AssistGestureSensitivityPreferenceControllerTest {
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Context mContext;
- private FakeFeatureFactory mFactory;
- private AssistGestureSensitivityPreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- FakeFeatureFactory.setupForTest(mContext);
- mFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
- mController = new AssistGestureSensitivityPreferenceController(mContext, null);
- }
-
- @Test
- public void isAvailable_whenSupportedAndEnabled_shouldReturnTrue() {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.ASSIST_GESTURE_ENABLED, 1);
- when(mFactory.assistGestureFeatureProvider.isSupported(mContext)).thenReturn(true);
-
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Test
- public void isAvailable_whenSupportedAndDisabled_shouldReturnFalse() {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.ASSIST_GESTURE_ENABLED, 0);
- when(mFactory.assistGestureFeatureProvider.isSupported(mContext)).thenReturn(true);
-
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void isAvailable_whenUnsupportedAndEnabled_shouldReturnFalse() {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.ASSIST_GESTURE_ENABLED, 1);
- when(mFactory.assistGestureFeatureProvider.isSupported(mContext)).thenReturn(false);
-
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void isAvailable_whenUnsupportedAndDisabled_shouldReturnFalse() {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.ASSIST_GESTURE_ENABLED, 0);
- when(mFactory.assistGestureFeatureProvider.isSupported(mContext)).thenReturn(false);
-
- assertThat(mController.isAvailable()).isFalse();
- }
-}
-
diff --git a/tests/robotests/src/com/android/settings/gestures/AssistGestureSettingsTest.java b/tests/robotests/src/com/android/settings/gestures/AssistGestureSettingsTest.java
index ba0a90a..17fa17b 100644
--- a/tests/robotests/src/com/android/settings/gestures/AssistGestureSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/AssistGestureSettingsTest.java
@@ -20,6 +20,7 @@
import android.provider.SearchIndexableResource;
import com.android.settings.R;
+import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.core.PreferenceController;
@@ -35,22 +36,28 @@
import java.util.List;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AssistGestureSettingsTest {
@Mock
private Context mContext;
+ private FakeFeatureFactory mFakeFeatureFactory;
+ private AssistGestureFeatureProvider mFeatureProvider;
private AssistGestureSettings mSettings;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mFakeFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+ mFeatureProvider = mFakeFeatureFactory.getAssistGestureFeatureProvider();
mSettings = new AssistGestureSettings();
}
@Test
public void testGetPreferenceScreenResId() {
+ when(mFeatureProvider.getPreferenceResourceId()).thenReturn(R.xml.assist_gesture_settings);
assertThat(mSettings.getPreferenceScreenResId())
.isEqualTo(R.xml.assist_gesture_settings);
}
@@ -69,6 +76,7 @@
ShadowApplication.getInstance().getApplicationContext(),
true /* enabled */);
+ when(mFeatureProvider.getPreferenceResourceId()).thenReturn(R.xml.assist_gesture_settings);
assertThat(indexRes).isNotNull();
assertThat(indexRes.get(0).xmlResId).isEqualTo(mSettings.getPreferenceScreenResId());
}
diff --git a/tests/robotests/src/com/android/settings/search/InstalledAppResultLoaderTest.java b/tests/robotests/src/com/android/settings/search/InstalledAppResultLoaderTest.java
index 645b986..d0a200d 100644
--- a/tests/robotests/src/com/android/settings/search/InstalledAppResultLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/search/InstalledAppResultLoaderTest.java
@@ -22,6 +22,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.os.UserHandle;
import android.os.UserManager;
import com.android.settings.R;
@@ -47,6 +48,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
@@ -387,4 +389,41 @@
assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
}
+
+ @Test
+ public void query_appExistsInBothProfiles() {
+ final String query = "carrot";
+ final String packageName = "carrot";
+ final int user1 = 0;
+ final int user2 = 10;
+ final int uid = 67672;
+ List<UserInfo> infos = new ArrayList<>();
+ infos.add(new UserInfo(user1, "user 1", 0));
+ infos.add(new UserInfo(user2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
+
+ when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
+
+ when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), eq(user1)))
+ .thenReturn(Arrays.asList(
+ ApplicationTestUtils.buildInfo(UserHandle.getUid(user1, uid) /* uid */,
+ packageName, 0 /* flags */,
+ 0 /* targetSdkVersion */)));
+ when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), eq(user2)))
+ .thenReturn(Arrays.asList(
+ ApplicationTestUtils.buildInfo(UserHandle.getUid(user2, uid) /* uid */,
+ packageName, 0 /* flags */,
+ 0 /* targetSdkVersion */)));
+
+ mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
+ mSiteMapManager);
+
+ Set<AppSearchResult> searchResults = (Set<AppSearchResult>) mLoader.loadInBackground();
+ assertThat(searchResults).hasSize(2);
+
+ Set<Integer> uidResults = searchResults.stream().map(result -> result.info.uid).collect(
+ Collectors.toSet());
+ assertThat(uidResults).containsExactly(
+ UserHandle.getUid(user1, uid),
+ UserHandle.getUid(user2, uid));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/search/IntentSearchViewHolderTest.java b/tests/robotests/src/com/android/settings/search/IntentSearchViewHolderTest.java
index 574e4f7..cee3c78 100644
--- a/tests/robotests/src/com/android/settings/search/IntentSearchViewHolderTest.java
+++ b/tests/robotests/src/com/android/settings/search/IntentSearchViewHolderTest.java
@@ -17,18 +17,30 @@
package com.android.settings.search;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
import android.view.LayoutInflater;
import android.view.View;
import com.android.settings.R;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.search.SearchResult.Builder;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
@@ -43,25 +55,25 @@
import java.util.List;
import java.util.Objects;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.verify;
-
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class IntentSearchViewHolderTest {
private static final String TITLE = "title";
private static final String SUMMARY = "summary";
+ private static final int USER_ID = 10;
+ private static final String BADGED_LABEL = "work title";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
- @Mock
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private SearchFragment mFragment;
+ @Mock
+ private PackageManager mPackageManager;
private FakeFeatureFactory mFeatureFactory;
private IntentSearchViewHolder mHolder;
private Drawable mIcon;
+ private Drawable mBadgedIcon;
@Before
public void setUp() {
@@ -74,6 +86,8 @@
mHolder = new IntentSearchViewHolder(view);
mIcon = context.getDrawable(R.drawable.ic_search_history);
+ mBadgedIcon = context.getDrawable(R.drawable.ic_add);
+ when(mFragment.getActivity().getPackageManager()).thenReturn(mPackageManager);
}
@Test
@@ -172,6 +186,27 @@
assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.GONE);
}
+ @Test
+ public void testBindViewElements_appSearchResult() {
+ when(mPackageManager.getUserBadgedLabel(any(CharSequence.class),
+ eq(new UserHandle(USER_ID)))).thenReturn(BADGED_LABEL);
+
+ SearchResult result = getAppSearchResult(
+ TITLE, SUMMARY, mIcon, getApplicationInfo(USER_ID, TITLE, mIcon));
+ mHolder.onBind(mFragment, result);
+ mHolder.itemView.performClick();
+
+ assertThat(mHolder.titleView.getText()).isEqualTo(TITLE);
+ assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY);
+ assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mHolder.breadcrumbView.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mHolder.titleView.getContentDescription()).isEqualTo(BADGED_LABEL);
+
+ verify(mFragment).onSearchResultClicked(eq(mHolder), any(SearchResult.class));
+ verify(mFragment.getActivity()).startActivityAsUser(
+ any(Intent.class), eq(new UserHandle(USER_ID)));
+ }
+
private SearchResult getSearchResult(String title, String summary, Drawable icon) {
Builder builder = new Builder();
builder.setStableId(Objects.hash(title, summary, icon))
@@ -186,4 +221,26 @@
return builder.build();
}
+
+ private SearchResult getAppSearchResult(
+ String title, String summary, Drawable icon, ApplicationInfo applicationInfo) {
+ AppSearchResult.Builder builder = new AppSearchResult.Builder();
+ builder.setTitle(title)
+ .setSummary(summary)
+ .setRank(1)
+ .setPayload(new ResultPayload(
+ new Intent().setComponent(new ComponentName("pkg", "class"))))
+ .addBreadcrumbs(new ArrayList<>())
+ .setIcon(icon);
+ builder.setAppInfo(applicationInfo);
+ return builder.build();
+ }
+
+ private ApplicationInfo getApplicationInfo(int userId, CharSequence appLabel, Drawable icon) {
+ ApplicationInfo applicationInfo = spy(new ApplicationInfo());
+ applicationInfo.uid = UserHandle.getUid(userId, 12345);
+ doReturn(icon).when(applicationInfo).loadIcon(any(PackageManager.class));
+ doReturn(appLabel).when(applicationInfo).loadLabel(any(PackageManager.class));
+ return applicationInfo;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
index b1419ba..7c56dc6 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
@@ -16,6 +16,8 @@
package com.android.settings.testutils.shadow;
+import android.app.admin.DevicePolicyManager;
+
import com.android.internal.widget.LockPatternUtils;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -27,4 +29,9 @@
public boolean isSecure(int id) {
return true;
}
+
+ @Implementation
+ public int getActivePasswordQuality(int userId) {
+ return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
index c67ad36..61346bc 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
@@ -16,11 +16,19 @@
package com.android.settings.testutils.shadow;
+import android.annotation.UserIdInt;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.os.UserManager;
+import android.util.SparseArray;
+import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
+import org.robolectric.internal.ShadowExtractor;
+
+import java.util.Collections;
+import java.util.List;
/**
* This class provides the API 24 implementation of UserManager.get(Context).
@@ -28,8 +36,34 @@
@Implements(UserManager.class)
public class ShadowUserManager {
+ private SparseArray<UserInfo> mUserInfos = new SparseArray<>();
+
+ public void setUserInfo(int userHandle, UserInfo userInfo) {
+ mUserInfos.put(userHandle, userInfo);
+ }
+
+ @Implementation
+ public UserInfo getUserInfo(int userHandle) {
+ return mUserInfos.get(userHandle);
+ }
+
+ @Implementation
+ public List<UserInfo> getProfiles(@UserIdInt int userHandle) {
+ return Collections.emptyList();
+ }
+
+ @Implementation
+ public int getCredentialOwnerProfile(@UserIdInt int userHandle) {
+ return userHandle;
+ }
+
@Implementation
public static UserManager get(Context context) {
return (UserManager) context.getSystemService(Context.USER_SERVICE);
}
+
+ public static ShadowUserManager getShadow() {
+ return (ShadowUserManager) ShadowExtractor.extract(
+ RuntimeEnvironment.application.getSystemService(UserManager.class));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
new file mode 100644
index 0000000..88a5147
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
@@ -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);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java b/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java
new file mode 100644
index 0000000..1ccdb1f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/WifiUtilsTest.java
@@ -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();
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceControllerTest.java
new file mode 100644
index 0000000..a7e00ab
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceControllerTest.java
@@ -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();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java
new file mode 100644
index 0000000..7ea2ea9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java
@@ -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();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
new file mode 100644
index 0000000..c3bc1eb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
@@ -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;
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java
new file mode 100644
index 0000000..f43e3a7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java
@@ -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();
+ }
+}
diff --git a/tests/unit/Android.mk b/tests/unit/Android.mk
index f9c0489..060c3e1 100644
--- a/tests/unit/Android.mk
+++ b/tests/unit/Android.mk
@@ -9,10 +9,12 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- mockito-target-minus-junit4 \
espresso-core \
+ legacy-android-test \
+ mockito-target-minus-junit4 \
truth-prebuilt \
- legacy-android-test
+ ub-uiautomator \
+
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/unit/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java b/tests/unit/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java
deleted file mode 100644
index 8afed18..0000000
--- a/tests/unit/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.fingerprint;
-
-
-import static org.mockito.Mockito.doReturn;
-
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.test.ActivityUnitTestCase;
-import android.view.View;
-import android.widget.Button;
-
-import com.android.settings.R;
-
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-public class SetupFingerprintEnrollIntroductionTest
- extends ActivityUnitTestCase<SetupFingerprintEnrollIntroduction> {
-
- private TestContext mContext;
-
- @Mock
- private KeyguardManager mKeyguardManager;
-
- private SetupFingerprintEnrollIntroduction mActivity;
-
- public SetupFingerprintEnrollIntroductionTest() {
- super(SetupFingerprintEnrollIntroduction.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- MockitoAnnotations.initMocks(this);
- mContext = new TestContext(getInstrumentation().getTargetContext());
- setActivityContext(mContext);
-
- getInstrumentation().runOnMainSync(() -> {
- final Intent intent = new Intent();
- mActivity = startActivity(intent,
- null /* savedInstanceState */, null /* lastNonConfigurationInstance */);
- });
- }
-
- public void testKeyguardNotSecure_shouldShowSkipDialog() {
- doReturn(false).when(mKeyguardManager).isKeyguardSecure();
-
- getInstrumentation().runOnMainSync(() -> {
- getInstrumentation().callActivityOnCreate(mActivity, null);
- getInstrumentation().callActivityOnResume(mActivity);
-
- final Button skipButton =
- (Button) mActivity.findViewById(R.id.fingerprint_cancel_button);
- assertEquals(View.VISIBLE, skipButton.getVisibility());
- skipButton.performClick();
- });
-
- assertFalse(isFinishCalled());
- }
-
- public void testKeyguardSecure_shouldNotShowSkipDialog() {
- doReturn(true).when(mKeyguardManager).isKeyguardSecure();
-
- getInstrumentation().runOnMainSync(() -> {
- getInstrumentation().callActivityOnCreate(mActivity, null);
- getInstrumentation().callActivityOnResume(mActivity);
-
- final Button skipButton =
- (Button) mActivity.findViewById(R.id.fingerprint_cancel_button);
- assertEquals(View.VISIBLE, skipButton.getVisibility());
- skipButton.performClick();
- });
-
- assertTrue(isFinishCalled());
- }
-
- public class TestContext extends ContextWrapper {
-
- public TestContext(Context base) {
- super(base);
- }
-
- @Override
- public Object getSystemService(String name) {
- if (Context.KEYGUARD_SERVICE.equals(name)) {
- return mKeyguardManager;
- }
- return super.getSystemService(name);
- }
- }
-}
diff --git a/tests/unit/src/com/android/settings/wifi/WifiSettingsUiTest.java b/tests/unit/src/com/android/settings/wifi/WifiSettingsUiTest.java
index c418d45..640c884 100644
--- a/tests/unit/src/com/android/settings/wifi/WifiSettingsUiTest.java
+++ b/tests/unit/src/com/android/settings/wifi/WifiSettingsUiTest.java
@@ -15,6 +15,7 @@
*/
package com.android.settings.wifi;
+import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
@@ -45,6 +46,7 @@
import java.util.List;
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
@@ -52,10 +54,14 @@
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
+
+import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -217,4 +223,23 @@
onView(withText(CONNECTED)).check(matches(isDisplayed()));
}
+
+ @Test
+ public void resumingAp_shouldNotForceUpdateWhenExistingAPsAreListed() {
+ setWifiState(WifiManager.WIFI_STATE_ENABLED);
+ setupConnectedAccessPoint();
+ when(mWifiTracker.isConnected()).thenReturn(true);
+
+ launchActivity();
+
+ onView(withText(CONNECTED)).check(matches(isDisplayed()));
+ verify(mWifiTracker).forceUpdate();
+
+ Activity activity = mActivityRule.getActivity();
+ activity.finish();
+ getInstrumentation().waitForIdleSync();
+
+ getInstrumentation().callActivityOnStart(activity);
+ verify(mWifiTracker, atMost(1)).forceUpdate();
+ }
}
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
new file mode 100644
index 0000000..26a711b
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -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 Wi‑Fi hotspot")).perform();
+ UiObject2 item = mDevice.wait(Until.findObject(By.text("Portable Wi‑Fi hotspot")), TIMEOUT);
+ item.click();
+ }
+}