diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 92819d86ccd..6d8e408235f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -742,6 +742,28 @@
android:value="true" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:height="24dp"
+ android:width="24dp" >
+ android:fillColor="?android:attr/colorControlActivated"
+ android:pathData="M 12 2 C 6.48 2 2 6.48 2 12 s 4.48 10 10 10 10 -4.48 10 -10 S 17.52 2 12 2 z m 4 11 H 8 c -.55 0 -1 -.45 -1 -1 s .45 -1 1 -1 h 8c.55 0 1 .45 1 1 s -.45 1 -1 1z" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 252a601c794..9e5db226670 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -402,11 +402,6 @@
Allow your phone to communicate with nearby Bluetooth devices
-
- Disable in-band ringing
-
- Don’t play custom phone ringtones on Bluetooth headsets
-
Available media devices
@@ -1696,15 +1691,10 @@
Remember settings
-
Maximum connected Bluetooth audio devices
Select maximum number of connected Bluetooth audio devices
-
- Disable Bluetooth AVDTP delay reports
-
- Disallow receiving Bluetooth AVDTP delay reports
Cast
@@ -2355,6 +2345,17 @@
Learn more about Private DNS features
+
+ Setting managed by carrier
+
+ Activate Wi\u2011Fi Calling
+
+ Turn on Wi\u2011Fi calling
+
+ Wi\u2011Fi calling is not supported for %1$s
+
+ Carrier
Display
@@ -4922,6 +4923,8 @@
Limit background activity?
If you limit background activity for an app, it may misbehave
+
+ Since this app is not set to optimize battery, you can\u2019t restrict it.\n\nTo restrict the app, first turn on battery optimization.
Screen usage since full charge
@@ -7930,6 +7933,9 @@
Calls
+
+ Allow calls
+
When Do Not Disturb is on, incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.
@@ -7945,6 +7951,9 @@
Messages
+
+ Allow messages
+
Messages
@@ -7984,9 +7993,15 @@
Reminders
+
+ Allow reminders
+
Events
+
+ Allow events
+
anyone
@@ -7999,8 +8014,11 @@
Repeat callers
+
+ Allow repeat callers
+
- From %1$s only
+ From %1$s
From %1$s and %2$s
@@ -9882,6 +9900,12 @@
+
+ Update Do Not Disturb
+
+
+ Hide notifications to stay focused
+
What\'s new and exciting?
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 52d8969241f..2e549046be1 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -254,16 +254,6 @@
android:title="@string/bluetooth_disable_absolute_volume"
android:summary="@string/bluetooth_disable_absolute_volume_summary" />
-
-
-
-
+ android:summary="@string/summary_placeholder"
+ settings:controller="com.android.settings.deviceinfo.DeviceModelPreferenceController" />
+ android:summary="@string/summary_placeholder"
+ settings:controller=
+ "com.android.settings.deviceinfo.DeviceModelPreferenceController" />
+ android:positiveButtonText="@string/save"
+ android:negativeButtonText="@android:string/cancel" />
diff --git a/res/xml/tether_prefs.xml b/res/xml/tether_prefs.xml
index 2a841d71608..70a57d7c98a 100644
--- a/res/xml/tether_prefs.xml
+++ b/res/xml/tether_prefs.xml
@@ -17,6 +17,7 @@
+ android:summary="@string/usb_tethering_subtext"
+ settings:keywords="@string/keywords_hotspot_tethering" />
+ android:summary="@string/bluetooth_tethering_subtext"
+ settings:keywords="@string/keywords_hotspot_tethering" />
@@ -43,4 +44,4 @@
android:dialogTitle="@string/wifi_hotspot_ap_band_title"
android:negativeButtonText="@string/cancel"
android:positiveButtonText="@string/apply"/>
-
\ No newline at end of file
+
diff --git a/res/xml/zen_mode_calls_settings.xml b/res/xml/zen_mode_calls_settings.xml
index dd6fcc50c0b..2da022c56a1 100644
--- a/res/xml/zen_mode_calls_settings.xml
+++ b/res/xml/zen_mode_calls_settings.xml
@@ -26,7 +26,7 @@
@@ -37,7 +37,7 @@
+ android:title="@string/zen_mode_repeat_callers_title" />
diff --git a/res/xml/zen_mode_msg_event_reminder_settings.xml b/res/xml/zen_mode_msg_event_reminder_settings.xml
index d12fc624461..8fc6b4717be 100644
--- a/res/xml/zen_mode_msg_event_reminder_settings.xml
+++ b/res/xml/zen_mode_msg_event_reminder_settings.xml
@@ -26,7 +26,7 @@
@@ -37,12 +37,12 @@
+ android:title="@string/zen_mode_reminders_title"/>
+ android:title="@string/zen_mode_events_title"/>
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
index 8cb8efc27df..0be2cfd5e78 100644
--- a/src/com/android/settings/TetherSettings.java
+++ b/src/com/android/settings/TetherSettings.java
@@ -34,27 +34,41 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.UserManager;
-import androidx.preference.SwitchPreference;
+import android.provider.SearchIndexableResource;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.datausage.DataSaverBackend;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
import com.android.settings.wifi.tether.WifiTetherPreferenceController;
import com.android.settingslib.TetherUtil;
+import com.android.settingslib.search.SearchIndexable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/*
* Displays preferences for Tethering.
*/
+@SearchIndexable
public class TetherSettings extends RestrictedSettingsFragment
implements DataSaverBackend.Listener {
- private static final String USB_TETHER_SETTINGS = "usb_tether_settings";
- private static final String ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering";
- private static final String DATA_SAVER_FOOTER = "disabled_on_data_saver";
+ @VisibleForTesting
+ static final String KEY_TETHER_PREFS_SCREEN = "tether_prefs_screen";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER = "wifi_tether";
+ @VisibleForTesting
+ static final String KEY_USB_TETHER_SETTINGS = "usb_tether_settings";
+ @VisibleForTesting
+ static final String KEY_ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering";
+ private static final String KEY_DATA_SAVER_FOOTER = "disabled_on_data_saver";
private static final String TAG = "TetheringSettings";
@@ -110,7 +124,7 @@ public class TetherSettings extends RestrictedSettingsFragment
mDataSaverBackend = new DataSaverBackend(getContext());
mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled();
- mDataSaverFooter = findPreference(DATA_SAVER_FOOTER);
+ mDataSaverFooter = findPreference(KEY_DATA_SAVER_FOOTER);
setIfOnlyAvailableForAdmins(true);
if (isUiRestricted()) {
@@ -126,8 +140,8 @@ public class TetherSettings extends RestrictedSettingsFragment
BluetoothProfile.PAN);
}
- mUsbTether = (SwitchPreference) findPreference(USB_TETHER_SETTINGS);
- mBluetoothTether = (SwitchPreference) findPreference(ENABLE_BLUETOOTH_TETHERING);
+ mUsbTether = (SwitchPreference) findPreference(KEY_USB_TETHER_SETTINGS);
+ mBluetoothTether = (SwitchPreference) findPreference(KEY_ENABLE_BLUETOOTH_TETHERING);
mDataSaverBackend.addListener(this);
@@ -387,7 +401,6 @@ public class TetherSettings extends RestrictedSettingsFragment
if (adapter.getState() == BluetoothAdapter.STATE_OFF) {
mBluetoothEnableForTether = true;
adapter.enable();
- mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
mBluetoothTether.setEnabled(false);
return;
}
@@ -433,6 +446,42 @@ public class TetherSettings extends RestrictedSettingsFragment
}
};
+ public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.tether_prefs;
+ return Arrays.asList(sir);
+ }
+
+ @Override
+ public List getNonIndexableKeys(Context context) {
+ final List keys = super.getNonIndexableKeys(context);
+ final ConnectivityManager cm =
+ context.getSystemService(ConnectivityManager.class);
+
+ if (!TetherUtil.isTetherAvailable(context)) {
+ keys.add(KEY_TETHER_PREFS_SCREEN);
+ keys.add(KEY_WIFI_TETHER);
+ }
+
+ final boolean usbAvailable =
+ cm.getTetherableUsbRegexs().length != 0;
+ if (!usbAvailable || Utils.isMonkeyRunning()) {
+ keys.add(KEY_USB_TETHER_SETTINGS);
+ }
+
+ final boolean bluetoothAvailable =
+ cm.getTetherableBluetoothRegexs().length != 0;
+ if (!bluetoothAvailable) {
+ keys.add(KEY_ENABLE_BLUETOOTH_TETHERING);
+ }
+ return keys;
+ }
+ };
+
private static final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
final WeakReference mTetherSettings;
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java
index a9c7713e4d8..e4c99cd87ed 100644
--- a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java
@@ -21,6 +21,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.service.settings.suggestions.Suggestion;
+
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import android.util.Log;
@@ -32,6 +33,8 @@ import com.android.settings.Settings.NightDisplaySuggestionActivity;
import com.android.settings.display.NightDisplayPreferenceController;
import com.android.settings.fingerprint.FingerprintEnrollSuggestionActivity;
import com.android.settings.fingerprint.FingerprintSuggestionActivity;
+import com.android.settings.notification.ZenOnboardingActivity;
+import com.android.settings.notification.ZenSuggestionActivity;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ScreenLockSuggestionActivity;
import com.android.settings.support.NewDeviceIntroSuggestionActivity;
@@ -88,6 +91,8 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider
return NightDisplayPreferenceController.isSuggestionComplete(context);
} else if (className.equals(NewDeviceIntroSuggestionActivity.class.getName())) {
return NewDeviceIntroSuggestionActivity.isSuggestionComplete(context);
+ } else if (className.equals(ZenSuggestionActivity.class.getName())) {
+ return ZenOnboardingActivity.isSuggestionComplete(context);
}
return false;
}
diff --git a/src/com/android/settings/development/BluetoothDelayReportsPreferenceController.java b/src/com/android/settings/development/BluetoothDelayReportsPreferenceController.java
deleted file mode 100644
index 3556424e144..00000000000
--- a/src/com/android/settings/development/BluetoothDelayReportsPreferenceController.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2018 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.development;
-
-import android.content.Context;
-import android.os.SystemProperties;
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.SwitchPreference;
-import androidx.preference.Preference;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.development.DeveloperOptionsPreferenceController;
-
-public class BluetoothDelayReportsPreferenceController extends DeveloperOptionsPreferenceController
- implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
-
- private static final String BLUETOOTH_DISABLE_AVDTP_DELAY_REPORT_KEY =
- "bluetooth_disable_avdtp_delay_reports";
- @VisibleForTesting
- static final String BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY =
- "persist.bluetooth.disabledelayreports";
-
- public BluetoothDelayReportsPreferenceController(Context context) {
- super(context);
- }
-
- @Override
- public String getPreferenceKey() {
- return BLUETOOTH_DISABLE_AVDTP_DELAY_REPORT_KEY;
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final boolean isDisabled = (Boolean) newValue;
- SystemProperties.set(BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY,
- isDisabled ? "true" : "false");
- return true;
- }
-
- @Override
- public void updateState(Preference preference) {
- final boolean isDisabled = SystemProperties.getBoolean(
- BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY, false /* default */);
- ((SwitchPreference) mPreference).setChecked(isDisabled);
- }
-
- @Override
- protected void onDeveloperOptionsSwitchDisabled() {
- super.onDeveloperOptionsSwitchDisabled();
- // the default setting for this preference is the disabled state
- ((SwitchPreference) mPreference).setChecked(false);
- SystemProperties.set(BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY, "false");
- }
-
-}
diff --git a/src/com/android/settings/development/BluetoothInbandRingingPreferenceController.java b/src/com/android/settings/development/BluetoothInbandRingingPreferenceController.java
deleted file mode 100644
index ec5124f5692..00000000000
--- a/src/com/android/settings/development/BluetoothInbandRingingPreferenceController.java
+++ /dev/null
@@ -1,78 +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.development;
-
-import android.bluetooth.BluetoothHeadset;
-import android.content.Context;
-import android.os.SystemProperties;
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.SwitchPreference;
-import androidx.preference.Preference;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.development.DeveloperOptionsPreferenceController;
-
-public class BluetoothInbandRingingPreferenceController extends DeveloperOptionsPreferenceController
- implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
-
- private static final String BLUETOOTH_DISABLE_INBAND_RINGING_KEY =
- "bluetooth_disable_inband_ringing";
- @VisibleForTesting
- static final String BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY =
- "persist.bluetooth.disableinbandringing";
-
- public BluetoothInbandRingingPreferenceController(Context context) {
- super(context);
- }
-
- @Override
- public boolean isAvailable() {
- return isInbandRingingSupported();
- }
-
- @Override
- public String getPreferenceKey() {
- return BLUETOOTH_DISABLE_INBAND_RINGING_KEY;
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final boolean isChecked = (Boolean) newValue;
- SystemProperties.set(BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY,
- isChecked ? "true" : "false");
- return true;
- }
-
- @Override
- public void updateState(Preference preference) {
- final boolean isEnabled = SystemProperties.getBoolean(
- BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY, false /* default */);
- ((SwitchPreference) mPreference).setChecked(isEnabled);
- }
-
- @Override
- protected void onDeveloperOptionsSwitchDisabled() {
- super.onDeveloperOptionsSwitchDisabled();
- ((SwitchPreference) mPreference).setChecked(false);
- SystemProperties.set(BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY, "false");
- }
-
- @VisibleForTesting
- boolean isInbandRingingSupported() {
- return BluetoothHeadset.isInbandRingingSupported(mContext);
- }
-}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index c3b62e244f8..ba3653a9328 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -406,8 +406,6 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new TetheringHardwareAccelPreferenceController(context));
controllers.add(new BluetoothDeviceNoNamePreferenceController(context));
controllers.add(new BluetoothAbsoluteVolumePreferenceController(context));
- controllers.add(new BluetoothInbandRingingPreferenceController(context));
- controllers.add(new BluetoothDelayReportsPreferenceController(context));
controllers.add(new BluetoothAvrcpVersionPreferenceController(context));
controllers.add(new BluetoothAudioCodecPreferenceController(context, lifecycle,
bluetoothA2dpConfigStore));
diff --git a/src/com/android/settings/deviceinfo/DeviceInfoSettings.java b/src/com/android/settings/deviceinfo/DeviceInfoSettings.java
index 44655f0d08a..e2df2c1f92c 100644
--- a/src/com/android/settings/deviceinfo/DeviceInfoSettings.java
+++ b/src/com/android/settings/deviceinfo/DeviceInfoSettings.java
@@ -21,7 +21,6 @@ import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.provider.SearchIndexableResource;
-import androidx.annotation.VisibleForTesting;
import android.telephony.TelephonyManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -41,6 +40,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import androidx.annotation.VisibleForTesting;
+
@SearchIndexable
public class DeviceInfoSettings extends DashboardFragment implements Indexable {
@@ -57,6 +58,7 @@ public class DeviceInfoSettings extends DashboardFragment implements Indexable {
public void onAttach(Context context) {
super.onAttach(context);
use(FirmwareVersionPreferenceController.class).setHost(this /*parent*/);
+ use(DeviceModelPreferenceController.class).setHost(this /* parent */);
}
@Override
@@ -134,7 +136,6 @@ public class DeviceInfoSettings extends DashboardFragment implements Indexable {
final List controllers = new ArrayList<>();
controllers.add(new PhoneNumberPreferenceController(context));
controllers.add(new SimStatusPreferenceController(context, fragment));
- controllers.add(new DeviceModelPreferenceController(context, fragment));
controllers.add(new ImeiInfoPreferenceController(context, fragment));
controllers.add(new IpAddressPreferenceController(context, lifecycle));
controllers.add(new WifiMacAddressPreferenceController(context, lifecycle));
diff --git a/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java b/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
index 1fc54cd6755..4fa7afc0a15 100644
--- a/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
@@ -18,50 +18,54 @@ package com.android.settings.deviceinfo;
import android.app.Fragment;
import android.content.Context;
import android.os.Build;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
import android.text.TextUtils;
+import android.util.Log;
import com.android.settings.R;
-import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.DeviceInfoUtils;
-import com.android.settingslib.core.AbstractPreferenceController;
-public class DeviceModelPreferenceController extends AbstractPreferenceController implements
- PreferenceControllerMixin {
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
- private static final String KEY_DEVICE_MODEL = "device_model";
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
- private final Fragment mHost;
- public DeviceModelPreferenceController(Context context, Fragment host) {
- super(context);
- mHost = host;
+public class DeviceModelPreferenceController extends BasePreferenceController {
+
+ private static final String TAG = "DeviceModelPrefCtrl";
+
+ private Fragment mHost;
+
+ public DeviceModelPreferenceController(Context context, String key) {
+ super(context, key);
}
- @Override
- public boolean isAvailable() {
- return mContext.getResources().getBoolean(R.bool.config_show_device_model);
+ public void setHost(Fragment fragment) {
+ mHost = fragment;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- final Preference pref = screen.findPreference(KEY_DEVICE_MODEL);
- if (pref != null) {
- pref.setSummary(mContext.getResources().getString(R.string.model_summary,
- getDeviceModel()));
- }
}
@Override
- public String getPreferenceKey() {
- return KEY_DEVICE_MODEL;
+ public int getAvailabilityStatus() {
+ return mContext.getResources().getBoolean(R.bool.config_show_device_model)
+ ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mContext.getResources().getString(R.string.model_summary, getDeviceModel());
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
- if (!TextUtils.equals(preference.getKey(), KEY_DEVICE_MODEL)) {
+ if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
return false;
}
final HardwareInfoDialogFragment fragment = HardwareInfoDialogFragment.newInstance();
@@ -70,6 +74,25 @@ public class DeviceModelPreferenceController extends AbstractPreferenceControlle
}
public static String getDeviceModel() {
- return Build.MODEL + DeviceInfoUtils.getMsvSuffix();
+ FutureTask msvSuffixTask = new FutureTask(new Callable() {
+ @Override
+ public String call() {
+ return DeviceInfoUtils.getMsvSuffix();
+ }
+ });
+
+ msvSuffixTask.run();
+ try {
+ // Wait for msv suffix value.
+ final String msvSuffix = msvSuffixTask.get();
+ return Build.MODEL + msvSuffix;
+ } catch (ExecutionException e) {
+ Log.e(TAG, "Execution error, so we only show model name");
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interruption error, so we only show model name");
+ }
+ // If we can't get an msv suffix value successfully,
+ // it's better to return model name.
+ return Build.MODEL;
}
}
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index bdafa82c95d..00be8be0a01 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -82,6 +82,7 @@ public class MyDeviceInfoFragment extends DashboardFragment
public void onAttach(Context context) {
super.onAttach(context);
use(FirmwareVersionPreferenceController.class).setHost(this /*parent*/);
+ use(DeviceModelPreferenceController.class).setHost(this /* parent */);
}
@Override
@@ -122,7 +123,6 @@ public class MyDeviceInfoFragment extends DashboardFragment
}
controllers.add(deviceNamePreferenceController);
controllers.add(new SimStatusPreferenceController(context, fragment));
- controllers.add(new DeviceModelPreferenceController(context, fragment));
controllers.add(new ImeiInfoPreferenceController(context, fragment));
controllers.add(new IpAddressPreferenceController(context, lifecycle));
controllers.add(new WifiMacAddressPreferenceController(context, lifecycle));
diff --git a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java
index 598d5a820b6..8c41f192ccf 100644
--- a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java
+++ b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java
@@ -156,16 +156,18 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreference imple
@Override
public void onClick(DialogInterface dialog, int which) {
- final Context context = getContext();
- if (mMode.equals(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
- // Only clickable if hostname is valid, so we could save it safely
- Settings.Global.putString(context.getContentResolver(), HOSTNAME_KEY,
- mEditText.getText().toString());
- }
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ final Context context = getContext();
+ if (mMode.equals(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+ // Only clickable if hostname is valid, so we could save it safely
+ Settings.Global.putString(context.getContentResolver(), HOSTNAME_KEY,
+ mEditText.getText().toString());
+ }
- FeatureFactory.getFactory(context).getMetricsFeatureProvider().action(context,
- MetricsProto.MetricsEvent.ACTION_PRIVATE_DNS_MODE, mMode);
- Settings.Global.putString(context.getContentResolver(), MODE_KEY, mMode);
+ FeatureFactory.getFactory(context).getMetricsFeatureProvider().action(context,
+ MetricsProto.MetricsEvent.ACTION_PRIVATE_DNS_MODE, mMode);
+ Settings.Global.putString(context.getContentResolver(), MODE_KEY, mMode);
+ }
}
@Override
diff --git a/src/com/android/settings/network/TetherPreferenceController.java b/src/com/android/settings/network/TetherPreferenceController.java
index 636fe0cee07..3ab83cda0b5 100644
--- a/src/com/android/settings/network/TetherPreferenceController.java
+++ b/src/com/android/settings/network/TetherPreferenceController.java
@@ -17,7 +17,6 @@ package com.android.settings.network;
import static android.os.UserManager.DISALLOW_CONFIG_TETHERING;
import static com.android.settingslib.RestrictedLockUtils.checkIfRestrictionEnforced;
-import static com.android.settingslib.RestrictedLockUtils.hasBaseUserRestriction;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
@@ -40,6 +39,7 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.TetherSettings;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.TetherUtil;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -112,11 +112,7 @@ public class TetherPreferenceController extends AbstractPreferenceController imp
@Override
public boolean isAvailable() {
- final boolean isBlocked =
- (!mConnectivityManager.isTetheringSupported() && !mAdminDisallowedTetherConfig)
- || hasBaseUserRestriction(mContext, DISALLOW_CONFIG_TETHERING,
- UserHandle.myUserId());
- return !isBlocked;
+ return TetherUtil.isTetherAvailable(mContext);
}
@Override
diff --git a/src/com/android/settings/notification/ZenModeBackend.java b/src/com/android/settings/notification/ZenModeBackend.java
index cb8a048c90c..8c8f14df671 100644
--- a/src/com/android/settings/notification/ZenModeBackend.java
+++ b/src/com/android/settings/notification/ZenModeBackend.java
@@ -135,6 +135,9 @@ public class ZenModeBackend {
}
protected void saveVisualEffectsPolicy(int category, boolean suppress) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.ZEN_SETTINGS_UPDATED, 1);
+
int suppressedEffects = getNewSuppressedEffects(suppress, category);
savePolicy(mPolicy.priorityCategories, mPolicy.priorityCallSenders,
mPolicy.priorityMessageSenders, suppressedEffects);
diff --git a/src/com/android/settings/notification/ZenModeRestrictNotificationsSettings.java b/src/com/android/settings/notification/ZenModeRestrictNotificationsSettings.java
index a2a0ba7f008..737c646f929 100644
--- a/src/com/android/settings/notification/ZenModeRestrictNotificationsSettings.java
+++ b/src/com/android/settings/notification/ZenModeRestrictNotificationsSettings.java
@@ -16,22 +16,15 @@
package com.android.settings.notification;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ZEN_SHOW_CUSTOM;
-
import android.content.Context;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
-import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.widget.FooterPreference;
@@ -42,67 +35,21 @@ import java.util.List;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ZenModeRestrictNotificationsSettings extends ZenModeSettingsBase implements Indexable {
- protected static final int APP_MENU_SHOW_CUSTOM = 1;
- protected boolean mShowMenuSelected;
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
}
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- menu.add(0, APP_MENU_SHOW_CUSTOM, 0, R.string.zen_mode_restrict_notifications_enable_custom)
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- if (menuItem.getItemId() == APP_MENU_SHOW_CUSTOM) {
- final FeatureFactory featureFactory = FeatureFactory.getFactory(mContext);
- MetricsFeatureProvider metrics = featureFactory.getMetricsFeatureProvider();
-
- mShowMenuSelected = !mShowMenuSelected;
-
- ZenModeVisEffectsCustomPreferenceController custom =
- use(ZenModeVisEffectsCustomPreferenceController.class);
- custom.setShownByMenu(mShowMenuSelected);
- custom.displayPreference(getPreferenceScreen());
-
- if (mShowMenuSelected) {
- metrics.action(mContext, ACTION_ZEN_SHOW_CUSTOM, true);
- } else {
- metrics.action(mContext, ACTION_ZEN_SHOW_CUSTOM, false);
- }
-
- return true;
- }
- return false;
- }
-
- @Override
- public void onPrepareOptionsMenu(Menu menu) {
- if (mShowMenuSelected) {
- menu.findItem(APP_MENU_SHOW_CUSTOM)
- .setTitle(R.string.zen_mode_restrict_notifications_disable_custom);
- } else {
- menu.findItem(APP_MENU_SHOW_CUSTOM)
- .setTitle(R.string.zen_mode_restrict_notifications_enable_custom);
- }
-
- if (mShowMenuSelected && use(ZenModeVisEffectsCustomPreferenceController.class)
- .areCustomOptionsSelected()) {
- menu.findItem(APP_MENU_SHOW_CUSTOM).setEnabled(false);
- } else {
- menu.findItem(APP_MENU_SHOW_CUSTOM).setEnabled(true);
- }
- }
-
@Override
protected List createPreferenceControllers(Context context) {
return buildPreferenceControllers(context, getLifecycle());
}
+ @Override
+ public int getHelpResource() {
+ return R.string.help_uri_interruptions;
+ }
+
private static List buildPreferenceControllers(Context context,
Lifecycle lifecycle) {
List controllers = new ArrayList<>();
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index 3fb5a4b9be6..240ab68c93a 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -170,7 +170,7 @@ public class ZenModeSettings extends ZenModeSettingsBase {
} else if (numCategories == 2) {
return mContext.getString(R.string.join_two_items, enabledCategories.get(0),
enabledCategories.get(1).toLowerCase());
- } else if (numCategories == 3) {
+ } else if (numCategories == 3){
final List summaries = new ArrayList<>();
summaries.add(enabledCategories.get(0));
summaries.add(enabledCategories.get(1).toLowerCase());
diff --git a/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java b/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java
index 5baf0fac11d..5dd99f61568 100644
--- a/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java
@@ -30,7 +30,6 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeVisEffectsCustomPreferenceController
extends AbstractZenModePreferenceController {
- protected boolean mShowMenuSelected;
protected static final int INTERRUPTIVE_EFFECTS = Policy.SUPPRESSED_EFFECT_AMBIENT
| Policy.SUPPRESSED_EFFECT_PEEK
| Policy.SUPPRESSED_EFFECT_LIGHTS
@@ -43,11 +42,7 @@ public class ZenModeVisEffectsCustomPreferenceController
@Override
public boolean isAvailable() {
- if (mShowMenuSelected) {
- return true;
- }
-
- return areCustomOptionsSelected();
+ return true;
}
@Override
@@ -67,10 +62,6 @@ public class ZenModeVisEffectsCustomPreferenceController
});
}
- protected void setShownByMenu(boolean shown) {
- mShowMenuSelected = shown;
- }
-
protected boolean areCustomOptionsSelected() {
boolean allEffectsSuppressed =
Policy.areAllVisualEffectsSuppressed(mBackend.mPolicy.suppressedVisualEffects);
diff --git a/src/com/android/settings/notification/ZenOnboardingActivity.java b/src/com/android/settings/notification/ZenOnboardingActivity.java
index 2215a1d9d7c..c4cc355c95a 100644
--- a/src/com/android/settings/notification/ZenOnboardingActivity.java
+++ b/src/com/android/settings/notification/ZenOnboardingActivity.java
@@ -19,17 +19,34 @@ package com.android.settings.notification;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
+import android.content.Context;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.provider.Settings;
-import androidx.annotation.VisibleForTesting;
+import android.text.format.DateUtils;
+import android.util.Log;
import android.view.View;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+
+import androidx.annotation.VisibleForTesting;
public class ZenOnboardingActivity extends Activity {
+ private static final String TAG = "ZenOnboardingActivity";
+
+ @VisibleForTesting
+ static final String PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME =
+ "pref_zen_suggestion_first_display_time_ms";
+ @VisibleForTesting
+ static final String PREF_KEY_SUGGESTION_VIEWED = "pref_zen_suggestion_viewed";
+ @VisibleForTesting
+ static final long ALWAYS_SHOW_THRESHOLD = DateUtils.DAY_IN_MILLIS * 14;
+
private NotificationManager mNm;
private MetricsLogger mMetrics;
@@ -39,6 +56,10 @@ public class ZenOnboardingActivity extends Activity {
setNotificationManager(getSystemService(NotificationManager.class));
setMetricsLogger(new MetricsLogger());
+ Context context = getApplicationContext();
+ Settings.Global.putInt(context.getContentResolver(),
+ Settings.Global.ZEN_SETTINGS_SUGGESTION_VIEWED, 1);
+
setupUI();
}
@@ -61,20 +82,80 @@ public class ZenOnboardingActivity extends Activity {
public void close(View button) {
mMetrics.action(MetricsEvent.ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS);
+
+ Settings.Global.putInt(getApplicationContext().getContentResolver(),
+ Settings.Global.ZEN_SETTINGS_UPDATED, 1);
+
finishAndRemoveTask();
}
public void save(View button) {
mMetrics.action(MetricsEvent.ACTION_ZEN_ONBOARDING_OK);
- Policy policy = mNm.getNotificationPolicy();
+ NotificationManager.Policy policy = mNm.getNotificationPolicy();
- Policy newPolicy = new NotificationManager.Policy(
+ NotificationManager.Policy newPolicy = new NotificationManager.Policy(
Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | policy.priorityCategories,
Policy.PRIORITY_SENDERS_STARRED,
policy.priorityMessageSenders,
- Policy.getAllSuppressedVisualEffects());
+ NotificationManager.Policy.getAllSuppressedVisualEffects());
mNm.setNotificationPolicy(newPolicy);
+ Settings.Global.putInt(getApplicationContext().getContentResolver(),
+ Settings.Global.ZEN_SETTINGS_UPDATED, 1);
+
finishAndRemoveTask();
}
+
+ public static boolean isSuggestionComplete(Context context) {
+ if (wasZenUpdated(context)) {
+ return true;
+ }
+
+ if (showSuggestion(context) || withinShowTimeThreshold(context)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private static boolean wasZenUpdated(Context context) {
+ // ZEN_SETTINGS_UPDATED is true for:
+ // - fresh P+ device
+ // - if zen visual effects values were changed by the user in Settings
+ return Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.ZEN_SETTINGS_UPDATED, 0) != 0;
+ }
+
+ private static boolean showSuggestion(Context context) {
+ // SHOW_ZEN_SETTINGS_SUGGESTION is by default true, but false when:
+ // - user manually turns on dnd
+
+ // SHOW_ZEN_SETTINGS_SUGGESTION is also true when:
+ // - automatic rule has started DND and user has not seen the first use dialog
+ return Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.SHOW_ZEN_SETTINGS_SUGGESTION, 0) != 0;
+
+ }
+
+ private static boolean withinShowTimeThreshold(Context context) {
+ final SuggestionFeatureProvider featureProvider = FeatureFactory.getFactory(context)
+ .getSuggestionFeatureProvider(context);
+ final SharedPreferences prefs = featureProvider.getSharedPrefs(context);
+ final long currentTimeMs = System.currentTimeMillis();
+ final long firstDisplayTimeMs;
+
+ if (!prefs.contains(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME)) {
+ firstDisplayTimeMs = currentTimeMs;
+ prefs.edit().putLong(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME, currentTimeMs).commit();
+ } else {
+ firstDisplayTimeMs = prefs.getLong(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME, -1);
+ }
+
+ final long showTimeMs = firstDisplayTimeMs + ALWAYS_SHOW_THRESHOLD;
+ final boolean stillShow = currentTimeMs < showTimeMs;
+
+ Log.d(TAG, "still show zen suggestion based on time: " + stillShow + " showTimeMs="
+ + showTimeMs);
+ return stillShow;
+ }
}
diff --git a/src/com/android/settings/notification/ZenSuggestionActivity.java b/src/com/android/settings/notification/ZenSuggestionActivity.java
new file mode 100644
index 00000000000..9d2148c7e50
--- /dev/null
+++ b/src/com/android/settings/notification/ZenSuggestionActivity.java
@@ -0,0 +1,24 @@
+package com.android.settings.notification;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+
+public class ZenSuggestionActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // start up zen settings activity
+ Intent settingsIntent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+ startActivity(settingsIntent);
+
+ // start up onboarding activity
+ Intent onboardingActivity = new Intent(Settings.ZEN_MODE_ONBOARDING);
+ startActivity(onboardingActivity);
+
+ finish();
+ }
+}
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index add05e4e4a5..4d0165e1524 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -38,7 +38,6 @@ import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
-import android.security.KeyStore;
import androidx.annotation.StringRes;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -97,7 +96,6 @@ public class ChooseLockGeneric extends SettingsActivity {
public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
private static final String TAG = "ChooseLockGenericFragment";
- private static final int MIN_PASSWORD_LENGTH = 4;
private static final String KEY_SKIP_FINGERPRINT = "unlock_skip_fingerprint";
private static final String PASSWORD_CONFIRMED = "password_confirmed";
private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
@@ -136,7 +134,6 @@ public class ChooseLockGeneric extends SettingsActivity {
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
private DevicePolicyManager mDPM;
- private KeyStore mKeyStore;
private boolean mHasChallenge = false;
private long mChallenge;
private boolean mPasswordConfirmed = false;
@@ -168,7 +165,6 @@ public class ChooseLockGeneric extends SettingsActivity {
String chooseLockAction = getActivity().getIntent().getAction();
mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity());
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
- mKeyStore = KeyStore.getInstance();
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
mLockPatternUtils = new LockPatternUtils(getActivity());
mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction)
@@ -585,11 +581,10 @@ public class ChooseLockGeneric extends SettingsActivity {
return mManagedPasswordProvider.createIntent(false, password);
}
- protected Intent getLockPasswordIntent(int quality, int minLength, int maxLength) {
+ protected Intent getLockPasswordIntent(int quality) {
ChooseLockPassword.IntentBuilder builder =
new ChooseLockPassword.IntentBuilder(getContext())
.setPasswordQuality(quality)
- .setPasswordLengthRange(minLength, maxLength)
.setForFingerprint(mForFingerprint)
.setUserId(mUserId);
if (mHasChallenge) {
@@ -668,12 +663,7 @@ public class ChooseLockGeneric extends SettingsActivity {
if (quality >= DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
intent = getLockManagedPasswordIntent(mUserPassword);
} else if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
- int minLength = mDPM.getPasswordMinimumLength(null, mUserId);
- if (minLength < MIN_PASSWORD_LENGTH) {
- minLength = MIN_PASSWORD_LENGTH;
- }
- final int maxLength = mDPM.getPasswordMaximumLength(quality);
- intent = getLockPasswordIntent(quality, minLength, maxLength);
+ intent = getLockPasswordIntent(quality);
} else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
intent = getLockPatternIntent();
}
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 23c50226be9..1013c44700e 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -73,15 +73,6 @@ import java.util.ArrayList;
import java.util.List;
public class ChooseLockPassword extends SettingsActivity {
- public static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
- public static final String PASSWORD_MAX_KEY = "lockscreen.password_max";
- public static final String PASSWORD_MIN_LETTERS_KEY = "lockscreen.password_min_letters";
- public static final String PASSWORD_MIN_LOWERCASE_KEY = "lockscreen.password_min_lowercase";
- public static final String PASSWORD_MIN_UPPERCASE_KEY = "lockscreen.password_min_uppercase";
- public static final String PASSWORD_MIN_NUMERIC_KEY = "lockscreen.password_min_numeric";
- public static final String PASSWORD_MIN_SYMBOLS_KEY = "lockscreen.password_min_symbols";
- public static final String PASSWORD_MIN_NONLETTER_KEY = "lockscreen.password_min_nonletter";
-
private static final String TAG = "ChooseLockPassword";
@Override
@@ -113,12 +104,6 @@ public class ChooseLockPassword extends SettingsActivity {
return this;
}
- public IntentBuilder setPasswordLengthRange(int min, int max) {
- mIntent.putExtra(PASSWORD_MIN_KEY, min);
- mIntent.putExtra(PASSWORD_MAX_KEY, max);
- return this;
- }
-
public IntentBuilder setUserId(int userId) {
mIntent.putExtra(Intent.EXTRA_USER_ID, userId);
return this;
@@ -454,54 +439,32 @@ public class ChooseLockPassword extends SettingsActivity {
}
private void setupPasswordRequirementsView(View view) {
- // Construct passwordRequirements and requirementDescriptions.
- List passwordRequirements = new ArrayList<>();
- List requirementDescriptions = new ArrayList<>();
+ final List passwordRequirements = new ArrayList<>();
if (mPasswordMinUpperCase > 0) {
passwordRequirements.add(MIN_UPPER_LETTERS_IN_PASSWORD);
- requirementDescriptions.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_uppercase, mPasswordMinUpperCase,
- mPasswordMinUpperCase));
}
if (mPasswordMinLowerCase > 0) {
passwordRequirements.add(MIN_LOWER_LETTERS_IN_PASSWORD);
- requirementDescriptions.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_lowercase, mPasswordMinLowerCase,
- mPasswordMinLowerCase));
}
if (mPasswordMinLetters > 0) {
if (mPasswordMinLetters > mPasswordMinUpperCase + mPasswordMinLowerCase) {
passwordRequirements.add(MIN_LETTER_IN_PASSWORD);
- requirementDescriptions.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_letters, mPasswordMinLetters,
- mPasswordMinLetters));
}
}
if (mPasswordMinNumeric > 0) {
passwordRequirements.add(MIN_NUMBER_IN_PASSWORD);
- requirementDescriptions.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_numeric, mPasswordMinNumeric,
- mPasswordMinNumeric));
}
if (mPasswordMinSymbols > 0) {
passwordRequirements.add(MIN_SYMBOLS_IN_PASSWORD);
- requirementDescriptions.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_symbols, mPasswordMinSymbols,
- mPasswordMinSymbols));
}
if (mPasswordMinNonLetter > 0) {
if (mPasswordMinNonLetter > mPasswordMinNumeric + mPasswordMinSymbols) {
passwordRequirements.add(MIN_NON_LETTER_IN_PASSWORD);
- requirementDescriptions.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_nonletter, mPasswordMinNonLetter,
-
- mPasswordMinNonLetter));
}
}
// Convert list to array.
mPasswordRequirements = passwordRequirements.stream().mapToInt(i -> i).toArray();
- mPasswordRestrictionView =
- (RecyclerView) view.findViewById(R.id.password_requirements_view);
+ mPasswordRestrictionView = view.findViewById(R.id.password_requirements_view);
mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity()));
mPasswordRequirementAdapter = new PasswordRequirementAdapter();
mPasswordRestrictionView.setAdapter(mPasswordRequirementAdapter);
@@ -582,29 +545,15 @@ public class ChooseLockPassword extends SettingsActivity {
final int dpmPasswordQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
mRequestedQuality = Math.max(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY,
mRequestedQuality), dpmPasswordQuality);
- mPasswordMinLength = Math.max(Math.max(
- LockPatternUtils.MIN_LOCK_PASSWORD_SIZE,
- intent.getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength)),
+ mPasswordMinLength = Math.max(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE,
mLockPatternUtils.getRequestedMinimumPasswordLength(mUserId));
- mPasswordMaxLength = intent.getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength);
- mPasswordMinLetters = Math.max(intent.getIntExtra(PASSWORD_MIN_LETTERS_KEY,
- mPasswordMinLetters), mLockPatternUtils.getRequestedPasswordMinimumLetters(
- mUserId));
- mPasswordMinUpperCase = Math.max(intent.getIntExtra(PASSWORD_MIN_UPPERCASE_KEY,
- mPasswordMinUpperCase), mLockPatternUtils.getRequestedPasswordMinimumUpperCase(
- mUserId));
- mPasswordMinLowerCase = Math.max(intent.getIntExtra(PASSWORD_MIN_LOWERCASE_KEY,
- mPasswordMinLowerCase), mLockPatternUtils.getRequestedPasswordMinimumLowerCase(
- mUserId));
- mPasswordMinNumeric = Math.max(intent.getIntExtra(PASSWORD_MIN_NUMERIC_KEY,
- mPasswordMinNumeric), mLockPatternUtils.getRequestedPasswordMinimumNumeric(
- mUserId));
- mPasswordMinSymbols = Math.max(intent.getIntExtra(PASSWORD_MIN_SYMBOLS_KEY,
- mPasswordMinSymbols), mLockPatternUtils.getRequestedPasswordMinimumSymbols(
- mUserId));
- mPasswordMinNonLetter = Math.max(intent.getIntExtra(PASSWORD_MIN_NONLETTER_KEY,
- mPasswordMinNonLetter), mLockPatternUtils.getRequestedPasswordMinimumNonLetter(
- mUserId));
+ mPasswordMaxLength = mLockPatternUtils.getMaximumPasswordLength(mRequestedQuality);
+ mPasswordMinLetters = mLockPatternUtils.getRequestedPasswordMinimumLetters(mUserId);
+ mPasswordMinUpperCase = mLockPatternUtils.getRequestedPasswordMinimumUpperCase(mUserId);
+ mPasswordMinLowerCase = mLockPatternUtils.getRequestedPasswordMinimumLowerCase(mUserId);
+ mPasswordMinNumeric = mLockPatternUtils.getRequestedPasswordMinimumNumeric(mUserId);
+ mPasswordMinSymbols = mLockPatternUtils.getRequestedPasswordMinimumSymbols(mUserId);
+ mPasswordMinNonLetter = mLockPatternUtils.getRequestedPasswordMinimumNonLetter(mUserId);
// Modify the value based on dpm policy.
switch (dpmPasswordQuality) {
diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java
index a72047308c2..3edb08301b3 100644
--- a/src/com/android/settings/password/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/password/SetupChooseLockGeneric.java
@@ -170,9 +170,9 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
}
@Override
- protected Intent getLockPasswordIntent(int quality, int minLength, int maxLength) {
+ protected Intent getLockPasswordIntent(int quality) {
final Intent intent = SetupChooseLockPassword.modifyIntentForSetup(
- getContext(), super.getLockPasswordIntent(quality, minLength, maxLength));
+ getContext(), super.getLockPasswordIntent(quality));
SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
return intent;
}
diff --git a/src/com/android/settings/search/DeviceIndexUpdateJobService.java b/src/com/android/settings/search/DeviceIndexUpdateJobService.java
index 12a9cf00fcb..19b7d5e60b6 100644
--- a/src/com/android/settings/search/DeviceIndexUpdateJobService.java
+++ b/src/com/android/settings/search/DeviceIndexUpdateJobService.java
@@ -53,10 +53,12 @@ public class DeviceIndexUpdateJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
if (DEBUG) Log.d(TAG, "onStartJob");
- mRunningJob = true;
- Thread thread = new Thread(() -> updateIndex(params));
- thread.setPriority(Thread.MIN_PRIORITY);
- thread.start();
+ if (!mRunningJob) {
+ mRunningJob = true;
+ Thread thread = new Thread(() -> updateIndex(params));
+ thread.setPriority(Thread.MIN_PRIORITY);
+ thread.start();
+ }
return true;
}
@@ -122,7 +124,7 @@ public class DeviceIndexUpdateJobService extends JobService {
}
protected CharSequence findTitle(Slice loadedSlice, SliceMetadata metaData) {
- ListContent content = new ListContent(this, loadedSlice);
+ ListContent content = new ListContent(null, loadedSlice);
SliceItem headerItem = content.getHeaderItem();
if (headerItem == null) {
if (content.getRowItems().size() != 0) {
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index edeb2b5f28c..7eecee92cb7 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -18,6 +18,8 @@ package com.android.settings.slices;
import static android.Manifest.permission.READ_SEARCH_INDEXABLES;
+import static com.android.settings.wifi.calling.WifiCallingSliceHelper.PATH_WIFI_CALLING;
+
import android.app.PendingIntent;
import android.app.slice.SliceManager;
import android.content.ContentResolver;
@@ -32,7 +34,13 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+
import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.ThreadUtils;
import java.net.URISyntaxException;
@@ -160,6 +168,11 @@ public class SettingsSliceProvider extends SliceProvider {
switch (path) {
case "/" + PATH_WIFI:
return createWifiSlice(sliceUri);
+ case "/" + PATH_WIFI_CALLING:
+ return FeatureFactory.getFactory(getContext())
+ .getSlicesFeatureProvider()
+ .getNewWifiCallingSliceHelper(getContext())
+ .createWifiCallingSlice(sliceUri);
}
SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 47a7f5a45bd..04097340ed3 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -21,6 +21,7 @@ import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CH
import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED;
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED;
+import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED;
import android.app.slice.Slice;
import android.content.BroadcastReceiver;
@@ -79,6 +80,12 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
context.getContentResolver().notifyChange(uri, null);
}, 1000);
break;
+ case ACTION_WIFI_CALLING_CHANGED:
+ FeatureFactory.getFactory(context)
+ .getSlicesFeatureProvider()
+ .getNewWifiCallingSliceHelper(context)
+ .handleWifiCallingChanged(intent);
+ break;
}
}
diff --git a/src/com/android/settings/slices/SlicesFeatureProvider.java b/src/com/android/settings/slices/SlicesFeatureProvider.java
index e5bba617e48..8dd6547b398 100644
--- a/src/com/android/settings/slices/SlicesFeatureProvider.java
+++ b/src/com/android/settings/slices/SlicesFeatureProvider.java
@@ -2,6 +2,8 @@ package com.android.settings.slices;
import android.content.Context;
+import com.android.settings.wifi.calling.WifiCallingSliceHelper;
+
/**
* Manages Slices in Settings.
*/
@@ -24,4 +26,9 @@ public interface SlicesFeatureProvider {
* If the data is already indexed, the data will not change.
*/
void indexSliceData(Context context);
-}
\ No newline at end of file
+
+ /**
+ * Gets new WifiCallingSliceHelper object
+ */
+ WifiCallingSliceHelper getNewWifiCallingSliceHelper(Context context);
+}
diff --git a/src/com/android/settings/slices/SlicesFeatureProviderImpl.java b/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
index 8e5bc067150..16684bfb022 100644
--- a/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
+++ b/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
@@ -2,6 +2,7 @@ package com.android.settings.slices;
import android.content.Context;
+import com.android.settings.wifi.calling.WifiCallingSliceHelper;
import com.android.settingslib.utils.ThreadUtils;
/**
@@ -39,4 +40,9 @@ public class SlicesFeatureProviderImpl implements SlicesFeatureProvider {
SlicesIndexer indexer = getSliceIndexer(context);
indexer.indexSliceData();
}
-}
\ No newline at end of file
+
+ @Override
+ public WifiCallingSliceHelper getNewWifiCallingSliceHelper(Context context) {
+ return new WifiCallingSliceHelper(context);
+ }
+}
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
new file mode 100644
index 00000000000..3452af777b0
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2018 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.calling;
+
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.PersistableBundle;
+import androidx.core.graphics.drawable.IconCompat;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+
+import com.android.ims.ImsManager;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settings.slices.SliceBuilderUtils;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+
+/**
+ * Helper class to control slices for wifi calling settings.
+ */
+public class WifiCallingSliceHelper {
+
+ private static final String TAG = "WifiCallingSliceHelper";
+
+ /**
+ * Settings slice path to wifi calling setting.
+ */
+ public static final String PATH_WIFI_CALLING = "wifi_calling";
+
+ /**
+ * Action passed for changes to wifi calling slice (toggle).
+ */
+ public static final String ACTION_WIFI_CALLING_CHANGED =
+ "com.android.settings.wifi.calling.action.WIFI_CALLING_CHANGED";
+
+ /**
+ * Action for Wifi calling Settings activity which
+ * allows setting configuration for Wifi calling
+ * related settings
+ */
+ public static final String ACTION_WIFI_CALLING_SETTINGS_ACTIVITY =
+ "android.settings.WIFI_CALLING_SETTINGS";
+
+ /**
+ * Timeout for querying wifi calling setting from ims manager.
+ */
+ private static final int TIMEOUT_MILLIS = 2000;
+
+ /**
+ * Time for which data contained in the slice can remain fresh.
+ */
+ private static final int SLICE_TTL_MILLIS = 60000;
+
+ protected SubscriptionManager mSubscriptionManager;
+ private final Context mContext;
+
+ @VisibleForTesting
+ public WifiCallingSliceHelper(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Returns Slice object for wifi calling settings.
+ *
+ * If wifi calling is being turned on and if wifi calling activation is needed for the current
+ * carrier, this method will return Slice with instructions to go to Settings App.
+ *
+ * If wifi calling is not supported for the current carrier, this method will return slice with
+ * not supported message.
+ *
+ * If wifi calling setting can be changed, this method will return the slice to toggle wifi
+ * calling option with ACTION_WIFI_CALLING_CHANGED as endItem.
+ */
+ public Slice createWifiCallingSlice(Uri sliceUri) {
+ final int subId = getDefaultVoiceSubId();
+ final String carrierName = getSimCarrierName();
+
+ if (subId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ Log.d(TAG, "Invalid subscription Id");
+ return getNonActionableWifiCallingSlice(
+ mContext.getString(R.string.wifi_calling_settings_title),
+ mContext.getString(R.string.wifi_calling_not_supported, carrierName),
+ sliceUri, SliceBuilderUtils.getSettingsIntent(mContext));
+ }
+
+ final ImsManager imsManager = getImsManager(subId);
+
+ if (!imsManager.isWfcEnabledByPlatform()
+ || !imsManager.isWfcProvisionedOnDevice()) {
+ Log.d(TAG, "Wifi calling is either not provisioned or not enabled by Platform");
+ return getNonActionableWifiCallingSlice(
+ mContext.getString(R.string.wifi_calling_settings_title),
+ mContext.getString(R.string.wifi_calling_not_supported, carrierName),
+ sliceUri, SliceBuilderUtils.getSettingsIntent(mContext));
+ }
+
+ try {
+ final boolean isWifiCallingEnabled = isWifiCallingEnabled(imsManager);
+ final Intent activationAppIntent =
+ getWifiCallingCarrierActivityIntent(subId);
+
+ // Send this actionable wifi calling slice to toggle the setting
+ // only when there is no need for wifi calling activation with the server
+ if (activationAppIntent != null && !isWifiCallingEnabled) {
+ Log.d(TAG, "Needs Activation");
+ // Activation needed for the next action of the user
+ // Give instructions to go to settings app
+ return getNonActionableWifiCallingSlice(
+ mContext.getString(R.string.wifi_calling_settings_title),
+ mContext.getString(
+ R.string.wifi_calling_settings_activation_instructions),
+ sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
+ }
+ return getWifiCallingSlice(sliceUri, mContext, isWifiCallingEnabled);
+ } catch (InterruptedException | TimeoutException | ExecutionException e) {
+ Log.e(TAG, "Unable to read the current WiFi calling status", e);
+ return getNonActionableWifiCallingSlice(
+ mContext.getString(R.string.wifi_calling_settings_title),
+ mContext.getString(R.string.wifi_calling_turn_on),
+ sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
+ }
+ }
+
+ private boolean isWifiCallingEnabled(ImsManager imsManager)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ final FutureTask isWifiOnTask = new FutureTask<>(new Callable() {
+ @Override
+ public Boolean call() {
+ return imsManager.isWfcEnabledByUser();
+ }
+ });
+ final ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(isWifiOnTask);
+
+ Boolean isWifiEnabledByUser = false;
+ isWifiEnabledByUser = isWifiOnTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+
+ return isWifiEnabledByUser && imsManager.isNonTtyOrTtyOnVolteEnabled();
+ }
+
+ /**
+ * Builds a toggle slice where the intent takes you to the wifi calling page and the toggle
+ * enables/disables wifi calling.
+ */
+ private Slice getWifiCallingSlice(Uri sliceUri, Context mContext,
+ boolean isWifiCallingEnabled) {
+
+ final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
+ final String title = mContext.getString(R.string.wifi_calling_settings_title);
+ return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS)
+ .setColor(R.color.material_blue_500)
+ .addRow(b -> b
+ .setTitle(title)
+ .addEndItem(
+ new SliceAction(
+ getBroadcastIntent(ACTION_WIFI_CALLING_CHANGED),
+ null /* actionTitle */, isWifiCallingEnabled))
+ .setPrimaryAction(new SliceAction(
+ getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY),
+ icon,
+ title)))
+ .build();
+ }
+
+ protected ImsManager getImsManager(int subId) {
+ return ImsManager.getInstance(mContext, SubscriptionManager.getPhoneId(subId));
+ }
+
+ private Integer getWfcMode(ImsManager imsManager)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ FutureTask wfcModeTask = new FutureTask<>(new Callable() {
+ @Override
+ public Integer call() {
+ return imsManager.getWfcMode(false);
+ }
+ });
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(wfcModeTask);
+ return wfcModeTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Handles wifi calling setting change from wifi calling slice and posts notification. Should be
+ * called when intent action is ACTION_WIFI_CALLING_CHANGED. Executed in @WorkerThread
+ *
+ * @param intent action performed
+ */
+ public void handleWifiCallingChanged(Intent intent) {
+ final int subId = getDefaultVoiceSubId();
+
+ if (subId > SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ final ImsManager imsManager = getImsManager(subId);
+ if (imsManager.isWfcEnabledByPlatform()
+ || imsManager.isWfcProvisionedOnDevice()) {
+ final boolean currentValue = imsManager.isWfcEnabledByUser()
+ && imsManager.isNonTtyOrTtyOnVolteEnabled();
+ final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
+ currentValue);
+ final Intent activationAppIntent =
+ getWifiCallingCarrierActivityIntent(subId);
+ if (!newValue || activationAppIntent == null) {
+ // If either the action is to turn off wifi calling setting
+ // or there is no activation involved - Update the setting
+ if (newValue != currentValue) {
+ imsManager.setWfcSetting(newValue);
+ }
+ }
+ }
+ }
+ // notify change in slice in any case to get re-queried. This would result in displaying
+ // appropriate message with the updated setting.
+ final Uri uri = SliceBuilderUtils.getUri(PATH_WIFI_CALLING, false /*isPlatformSlice*/);
+ mContext.getContentResolver().notifyChange(uri, null);
+ }
+
+ /**
+ * Returns Slice with the title and subtitle provided as arguments with wifi signal Icon.
+ *
+ * @param title Title of the slice
+ * @param subtitle Subtitle of the slice
+ * @param sliceUri slice uri
+ * @return Slice with title and subtitle
+ */
+ // TODO(b/79548264) asses different scenarios and return null instead of non-actionable slice
+ private Slice getNonActionableWifiCallingSlice(String title, String subtitle, Uri sliceUri,
+ PendingIntent primaryActionIntent) {
+ final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
+ return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS)
+ .setColor(R.color.material_blue_500)
+ .addRow(b -> b
+ .setTitle(title)
+ .setSubtitle(subtitle)
+ .setPrimaryAction(new SliceAction(
+ primaryActionIntent, icon,
+ title)))
+ .build();
+ }
+
+ /**
+ * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise.
+ */
+ private boolean isCarrierConfigManagerKeyEnabled(Context mContext, String key,
+ int subId, boolean defaultValue) {
+ final CarrierConfigManager configManager = getCarrierConfigManager(mContext);
+ boolean ret = false;
+ if (configManager != null) {
+ final PersistableBundle bundle = configManager.getConfigForSubId(subId);
+ if (bundle != null) {
+ ret = bundle.getBoolean(key, defaultValue);
+ }
+ }
+ return ret;
+ }
+
+ protected CarrierConfigManager getCarrierConfigManager(Context mContext) {
+ return mContext.getSystemService(CarrierConfigManager.class);
+ }
+
+ /**
+ * Returns the current default voice subId obtained from SubscriptionManager
+ */
+ protected int getDefaultVoiceSubId() {
+ if (mSubscriptionManager == null) {
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ }
+ return SubscriptionManager.getDefaultVoiceSubscriptionId();
+ }
+
+ /**
+ * Returns Intent of the activation app required to activate wifi calling or null if there is no
+ * need for activation.
+ */
+ protected Intent getWifiCallingCarrierActivityIntent(int subId) {
+ final CarrierConfigManager configManager = getCarrierConfigManager(mContext);
+ if (configManager == null) {
+ return null;
+ }
+
+ final PersistableBundle bundle = configManager.getConfigForSubId(subId);
+ if (bundle == null) {
+ return null;
+ }
+
+ final String carrierApp = bundle.getString(
+ CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING);
+ if (TextUtils.isEmpty(carrierApp)) {
+ return null;
+ }
+
+ final ComponentName componentName = ComponentName.unflattenFromString(carrierApp);
+ if (componentName == null) {
+ return null;
+ }
+
+ final Intent intent = new Intent();
+ intent.setComponent(componentName);
+ return intent;
+ }
+
+ private PendingIntent getBroadcastIntent(String action) {
+ final Intent intent = new Intent(action);
+ intent.setClass(mContext, SliceBroadcastReceiver.class);
+ return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+ /**
+ * Returns PendingIntent to start activity specified by action
+ */
+ private PendingIntent getActivityIntent(String action) {
+ final Intent intent = new Intent(action);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
+ }
+
+ /**
+ * Returns carrier id name of the current Subscription
+ */
+ private String getSimCarrierName() {
+ final TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
+ final CharSequence carrierName = telephonyManager.getSimCarrierIdName();
+ if (carrierName == null) {
+ return mContext.getString(R.string.carrier);
+ }
+ return carrierName.toString();
+ }
+
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index 7c50f0c2cdb..5e202d63471 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -27,28 +27,42 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.UserManager;
-import androidx.annotation.VisibleForTesting;
+import android.provider.SearchIndexableResource;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.SwitchBarController;
+import com.android.settingslib.TetherUtil;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.UUID;
+@SearchIndexable
public class WifiTetherSettings extends RestrictedDashboardFragment
implements WifiTetherBasePreferenceController.OnTetherConfigUpdateListener {
private static final String TAG = "WifiTetherSettings";
private static final IntentFilter TETHER_STATE_CHANGE_FILTER;
- private static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
+ private static final String KEY_WIFI_TETHER_SCREEN = "wifi_tether_settings_screen";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER_NETWORK_NAME = "wifi_tether_network_name";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER_NETWORK_PASSWORD = "wifi_tether_network_password";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
+ @VisibleForTesting
+ static final String KEY_WIFI_TETHER_NETWORK_AP_BAND = "wifi_tether_network_ap_band";
private WifiTetherSwitchBarController mSwitchBarController;
private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
@@ -182,6 +196,33 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
.updateDisplay();
}
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.wifi_tether_settings;
+ return Arrays.asList(sir);
+ }
+
+ @Override
+ public List getNonIndexableKeys(Context context) {
+ final List keys = super.getNonIndexableKeys(context);
+
+ if (!TetherUtil.isTetherAvailable(context)) {
+ keys.add(KEY_WIFI_TETHER_NETWORK_NAME);
+ keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
+ keys.add(KEY_WIFI_TETHER_AUTO_OFF);
+ keys.add(KEY_WIFI_TETHER_NETWORK_AP_BAND);
+ }
+
+ // Remove duplicate
+ keys.add(KEY_WIFI_TETHER_SCREEN);
+ return keys;
+ }
+ };
+
@VisibleForTesting
class TetherChangeReceiver extends BroadcastReceiver {
@Override
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index 8bd4f823840..31e3a54ee26 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -21,7 +21,6 @@ com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMi
com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages
com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment
com.android.settings.inputmethod.KeyboardLayoutPickerFragment
-com.android.settings.wifi.tether.WifiTetherSettings
com.android.settings.wifi.SavedAccessPointsWifiSettings
com.android.settings.notification.ZenModeEventRuleSettings
com.android.settings.notification.ZenModeScheduleRuleSettings
diff --git a/tests/robotests/src/com/android/settings/TetherSettingsTest.java b/tests/robotests/src/com/android/settings/TetherSettingsTest.java
new file mode 100644
index 00000000000..1ccd958cfb3
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/TetherSettingsTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.net.ConnectivityManager;
+
+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 java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class TetherSettingsTest {
+
+ private Context mContext;
+
+ @Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
+ private UserManager mUserManager;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+
+ MockitoAnnotations.initMocks(this);
+ doReturn(mConnectivityManager)
+ .when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE);
+ doReturn(mUserManager)
+ .when(mContext).getSystemService(Context.USER_SERVICE);
+
+ setupIsTetherAvailable(true);
+
+ when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{});
+ when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[]{});
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_tetherAvailable_keysNotReturned() {
+ // To let TetherUtil.isTetherAvailable return true, select one of the combinations
+ setupIsTetherAvailable(true);
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).doesNotContain(TetherSettings.KEY_TETHER_PREFS_SCREEN);
+ assertThat(niks).doesNotContain(TetherSettings.KEY_WIFI_TETHER);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_tetherNotAvailable_keysReturned() {
+ // To let TetherUtil.isTetherAvailable return false, select one of the combinations
+ setupIsTetherAvailable(false);
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).contains(TetherSettings.KEY_TETHER_PREFS_SCREEN);
+ assertThat(niks).contains(TetherSettings.KEY_WIFI_TETHER);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_usbNotAvailable_usbKeyReturned() {
+ when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{});
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).contains(TetherSettings.KEY_USB_TETHER_SETTINGS);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_usbAvailable_usbKeyNotReturned() {
+ // We can ignore the condition of Utils.isMonkeyRunning()
+ // In normal case, monkey and robotest should not execute at the same time
+ when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{"dummyRegex"});
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).doesNotContain(TetherSettings.KEY_USB_TETHER_SETTINGS);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_bluetoothNotAvailable_bluetoothKeyReturned() {
+ when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[]{});
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).contains(TetherSettings.KEY_ENABLE_BLUETOOTH_TETHERING);
+ }
+
+ @Test
+ public void testTetherNonIndexableKeys_bluetoothAvailable_bluetoothKeyNotReturned() {
+ when(mConnectivityManager.getTetherableBluetoothRegexs())
+ .thenReturn(new String[]{"dummyRegex"});
+
+ final List niks =
+ TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).doesNotContain(TetherSettings.KEY_ENABLE_BLUETOOTH_TETHERING);
+ }
+
+ private void setupIsTetherAvailable(boolean returnValue) {
+ when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
+
+ // For RestrictedLockUtils.checkIfRestrictionEnforced
+ final int userId = UserHandle.myUserId();
+ List enforcingUsers = new ArrayList<>();
+ when(mUserManager.getUserRestrictionSources(
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
+ .thenReturn(enforcingUsers);
+
+ // For RestrictedLockUtils.hasBaseUserRestriction
+ when(mUserManager.hasBaseUserRestriction(
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
+ .thenReturn(!returnValue);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothDelayReportsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothDelayReportsPreferenceControllerTest.java
deleted file mode 100644
index cadb91e87e3..00000000000
--- a/tests/robotests/src/com/android/settings/development/BluetoothDelayReportsPreferenceControllerTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2018 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.development;
-
-import static com.android.settings.development.BluetoothDelayReportsPreferenceController
- .BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.SystemProperties;
-import androidx.preference.SwitchPreference;
-import androidx.preference.PreferenceScreen;
-
-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;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class BluetoothDelayReportsPreferenceControllerTest {
-
- @Mock
- private PreferenceScreen mPreferenceScreen;
-
- private Context mContext;
- private SwitchPreference mPreference;
- private BluetoothDelayReportsPreferenceController mController;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mPreference = new SwitchPreference(mContext);
- mController = spy(new BluetoothDelayReportsPreferenceController(mContext));
- when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
- .thenReturn(mPreference);
- mController.displayPreference(mPreferenceScreen);
- }
-
- @Test
- public void onPreferenceChanged_settingDisabled_turnOnDelayReports() {
- mController.onPreferenceChange(mPreference, true /* new value */);
-
- final boolean mode = SystemProperties.getBoolean(
- BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY, false /* default */);
-
- assertThat(mode).isTrue();
- }
-
- @Test
- public void onPreferenceChanged_settingDisabled_turnOffDelayReports() {
- mController.onPreferenceChange(mPreference, false /* new value */);
-
- final boolean mode = SystemProperties.getBoolean(
- BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY, false /* default */);
-
- assertThat(mode).isFalse();
- }
-
- @Test
- public void updateState_settingDisabled_preferenceShouldBeChecked() {
- SystemProperties.set(BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY,
- Boolean.toString(true));
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
- SystemProperties.set(BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY,
- Boolean.toString(false));
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isFalse();
- }
-
- @Test
- public void onDeveloperOptionsDisabled_shouldDisablePreference() {
- mController.onDeveloperOptionsDisabled();
-
- final boolean mode = SystemProperties.getBoolean(
- BLUETOOTH_DISABLE_AVDTP_DELAY_REPORTS_PROPERTY, false /* default */);
-
- assertThat(mode).isFalse();
- assertThat(mPreference.isEnabled()).isFalse();
- assertThat(mPreference.isChecked()).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothInbandRingingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothInbandRingingPreferenceControllerTest.java
deleted file mode 100644
index 9ac0cce88e9..00000000000
--- a/tests/robotests/src/com/android/settings/development/BluetoothInbandRingingPreferenceControllerTest.java
+++ /dev/null
@@ -1,120 +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.development;
-
-import static com.android.settings.development.BluetoothInbandRingingPreferenceController.BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY;
-import static com.google.common.truth.Truth.assertThat;
-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.Context;
-import android.os.SystemProperties;
-import androidx.preference.SwitchPreference;
-import androidx.preference.PreferenceScreen;
-
-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;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class BluetoothInbandRingingPreferenceControllerTest {
-
- @Mock
- private SwitchPreference mPreference;
- @Mock
- private PreferenceScreen mPreferenceScreen;
-
- private Context mContext;
- private BluetoothInbandRingingPreferenceController mController;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mController = spy(new BluetoothInbandRingingPreferenceController(mContext));
- doReturn(true).when(mController).isInbandRingingSupported();
- when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
- mPreference);
- mController.displayPreference(mPreferenceScreen);
- }
-
- @Test
- public void isAvailable_inbandRingingNotSupported_shouldReturnFalse() {
- doReturn(false).when(mController).isInbandRingingSupported();
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void isAvailable_inbandRingingSupported_shouldReturnTrue() {
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Test
- public void onPreferenceChanged_settingEnabled_turnOnBluetoothSnoopLog() {
- mController.onPreferenceChange(mPreference, true /* new value */);
-
- final boolean mode = SystemProperties
- .getBoolean(BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY, false /* default */);
-
- assertThat(mode).isTrue();
- }
-
- @Test
- public void onPreferenceChanged_settingDisabled_turnOffBluetoothSnoopLog() {
- mController.onPreferenceChange(mPreference, false /* new value */);
-
- final boolean mode = SystemProperties
- .getBoolean(BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY, false /* default */);
-
- assertThat(mode).isFalse();
- }
-
- @Test
- public void updateState_settingEnabled_preferenceShouldBeChecked() {
- SystemProperties.set(BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY, Boolean.toString(true));
- mController.updateState(mPreference);
-
- verify(mPreference).setChecked(true);
- }
-
- @Test
- public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
- SystemProperties.set(BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY, Boolean.toString(false));
- mController.updateState(mPreference);
-
- verify(mPreference).setChecked(false);
- }
-
- @Test
- public void onDeveloperOptionsDisabled_shouldDisablePreference() {
- mController.onDeveloperOptionsDisabled();
-
- final boolean mode = SystemProperties
- .getBoolean(BLUETOOTH_DISABLE_INBAND_RINGING_PROPERTY, false /* default */);
-
- assertThat(mode).isFalse();
- verify(mPreference).setEnabled(false);
- verify(mPreference).setChecked(false);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
index 9272b46b283..da32ce81909 100644
--- a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
@@ -131,7 +131,6 @@ public class DevelopmentSettingsDashboardFragmentTest {
@Config(shadows = {
ShadowPictureColorModePreferenceController.class,
ShadowAdbPreferenceController.class,
- ShadowBluetoothInbandRingingPreferenceController.class,
ShadowClearAdbKeysPreferenceController.class
})
public void searchIndex_pageEnabled_shouldNotAddKeysToNonIndexable() {
@@ -282,15 +281,6 @@ public class DevelopmentSettingsDashboardFragmentTest {
}
}
- @Implements(BluetoothInbandRingingPreferenceController.class)
- public static class ShadowBluetoothInbandRingingPreferenceController {
-
- @Implementation
- public boolean isAvailable() {
- return true;
- }
- }
-
@Implements(ClearAdbKeysPreferenceController.class)
public static class ShadowClearAdbKeysPreferenceController {
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java
index c91683e00d4..dbffc3182e1 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java
@@ -15,40 +15,44 @@
*/
package com.android.settings.deviceinfo;
-import static com.android.settings.deviceinfo.DeviceModelPreferenceController.getDeviceModel;
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.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
import android.content.Context;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
+import android.os.Build;
import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
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 androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+
@RunWith(SettingsRobolectricTestRunner.class)
public class DeviceModelPreferenceControllerTest {
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Fragment mFragment;
- @Mock
- private Preference mPreference;
- @Mock
- private PreferenceScreen mPreferenceScreen;
+ private final String KEY = "device_model_key";
+ @Mock
+ private Fragment mFragment;
+ private Preference mPreference;
+ private PreferenceScreen mPreferenceScreen;
private Context mContext;
private DeviceModelPreferenceController mController;
@@ -56,35 +60,49 @@ public class DeviceModelPreferenceControllerTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
- mController = new DeviceModelPreferenceController(mContext, mFragment);
- when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
- .thenReturn(mPreference);
- when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
+ mController = new DeviceModelPreferenceController(mContext, KEY);
+ mController.setHost(mFragment);
+ mPreference = new Preference(mContext);
+ mPreference.setKey(KEY);
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ mPreferenceScreen = preferenceManager.createPreferenceScreen(mContext);
+ mPreferenceScreen.addPreference(mPreference);
}
@Test
public void isAvailable_returnTrueIfVisible() {
- assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.AVAILABLE);
}
@Test
@Config(qualifiers = "mcc999")
public void isAvailable_returnFalseIfNotVisible() {
- assertThat(mController.isAvailable()).isFalse();
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.UNSUPPORTED_ON_DEVICE);
}
@Test
- public void displayPref_shouldSetSummary() {
- mController.displayPreference(mPreferenceScreen);
+ public void updatePreference_summaryShouldContainBuildModel() {
+ mController.updateState(mPreference);
- verify(mPreference).setSummary(mContext.getString(R.string.model_summary, getDeviceModel()));
+ assertThat(containBuildModel(mPreference.getSummary())).isTrue();
}
@Test
public void clickPreference_shouldLaunchHardwareInfoDialog() {
+ FragmentManager fragmentManager = mock(FragmentManager.class);
+ when(mFragment.getFragmentManager()).thenReturn(fragmentManager);
+ when(fragmentManager.beginTransaction()).thenReturn(mock(FragmentTransaction.class));
+
assertThat(mController.handlePreferenceTreeClick(mPreference)).isTrue();
- verify(mFragment).getFragmentManager();
- verify(mFragment.getFragmentManager().beginTransaction())
+ verify(fragmentManager.beginTransaction())
.add(any(HardwareInfoDialogFragment.class), eq(HardwareInfoDialogFragment.TAG));
}
+
+ private boolean containBuildModel(CharSequence result) {
+ final String oracle = mContext.getResources().getString(R.string.model_summary,
+ Build.MODEL);
+ return result.toString().contains(oracle);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogPreferenceTest.java b/tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogPreferenceTest.java
index e9ffa8ac4c6..dfea6fba515 100644
--- a/tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/network/PrivateDnsModeDialogPreferenceTest.java
@@ -28,7 +28,10 @@ import static org.mockito.Mockito.when;
import android.app.AlertDialog;
import android.app.Fragment;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
+import android.net.ConnectivityManager;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
@@ -150,4 +153,36 @@ public class PrivateDnsModeDialogPreferenceTest {
assertThat(mSaveButton.isEnabled()).named("provider: " + invalid).isFalse();
}
}
+
+ @Test
+ public void testOnClick_positiveButtonClicked_saveData() {
+ // Set the default settings to OFF
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ Settings.Global.putString(contentResolver, Settings.Global.PRIVATE_DNS_MODE,
+ ConnectivityManager.PRIVATE_DNS_MODE_OFF);
+
+ mPreference.mMode = ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ mPreference.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+ // Change to OPPORTUNISTIC
+ assertThat(Settings.Global.getString(contentResolver,
+ Settings.Global.PRIVATE_DNS_MODE)).isEqualTo(
+ ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC);
+ }
+
+ @Test
+ public void testOnClick_negativeButtonClicked_doNothing() {
+ // Set the default settings to OFF
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ Settings.Global.putString(contentResolver, Settings.Global.PRIVATE_DNS_MODE,
+ ConnectivityManager.PRIVATE_DNS_MODE_OFF);
+
+ mPreference.mMode = ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ mPreference.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+ // Still equal to OFF
+ assertThat(Settings.Global.getString(contentResolver,
+ Settings.Global.PRIVATE_DNS_MODE)).isEqualTo(
+ ConnectivityManager.PRIVATE_DNS_MODE_OFF);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java
index 5b2782fb6b7..39e9271fa2f 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java
@@ -134,13 +134,13 @@ public class ZenModeSettingsTest {
public void testGetCallsSettingSummary_contacts() {
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | Policy.PRIORITY_CATEGORY_CALLS,
Policy.PRIORITY_SENDERS_CONTACTS, 0, 0);
- assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From contacts only");
+ assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From contacts");
}
@Test
public void testGetCallsSettingSummary_repeatCallers() {
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0, 0);
- assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From repeat callers only");
+ assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From repeat callers");
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java
index f3d92d17d21..45446229930 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java
@@ -88,23 +88,14 @@ public class ZenModeVisEffectsCustomPreferenceControllerTest {
}
@Test
- public void isAvailable_menuOff_noVisEffects() {
+ public void isAvailable_noVisEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0);
- mController.mShowMenuSelected = false;
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void isAvailable_menuOn_noVisEffects() {
- mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0);
- mController.mShowMenuSelected = true;
assertThat(mController.isAvailable()).isTrue();
}
@Test
- public void isAvailable_menuOn_visEffects() {
+ public void isAvailable_visEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1);
- mController.mShowMenuSelected = false;
assertThat(mController.isAvailable()).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java b/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java
index 7bc93713977..7fb02a535cc 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java
@@ -29,6 +29,11 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OF
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static com.android.settings.notification.ZenOnboardingActivity.ALWAYS_SHOW_THRESHOLD;
+import static com.android.settings.notification.ZenOnboardingActivity
+ .PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME;
+import static com.android.settings.notification.ZenOnboardingActivity.isSuggestionComplete;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -39,20 +44,22 @@ import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.provider.Settings;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.R;
+import com.android.settings.testutils.FakeFeatureFactory;
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.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenOnboardingActivityTest {
@@ -64,6 +71,9 @@ public class ZenOnboardingActivityTest {
ZenOnboardingActivity mActivity;
+ private Context mContext;
+ private FakeFeatureFactory mFeatureFactory;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -75,6 +85,11 @@ public class ZenOnboardingActivityTest {
mActivity.setMetricsLogger(mMetricsLogger);
mActivity.setupUI();
+
+ mContext = RuntimeEnvironment.application;
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ when(mFeatureFactory.suggestionsFeatureProvider.getSharedPrefs(any(Context.class)))
+ .thenReturn(getSharedPreferences());
}
@Test
@@ -124,4 +139,73 @@ public class ZenOnboardingActivityTest {
verify(mNm, never()).setNotificationPolicy(any());
}
+
+ @Test
+ public void isSuggestionComplete_zenUpdated() {
+ setZenUpdated(true);
+ setShowSettingsSuggestion(false);
+ setWithinTimeThreshold(true);
+ assertThat(isSuggestionComplete(mContext)).isTrue();
+ }
+
+ @Test
+ public void isSuggestionComplete_withinTimeThreshold() {
+ setZenUpdated(false);
+ setShowSettingsSuggestion(false);
+ setWithinTimeThreshold(true);
+ assertThat(isSuggestionComplete(mContext)).isFalse();
+ }
+
+ @Test
+ public void isSuggestionComplete_showSettingsSuggestionTrue() {
+ setZenUpdated(false);
+ setShowSettingsSuggestion(true);
+ setWithinTimeThreshold(false);
+ assertThat(isSuggestionComplete(mContext)).isFalse();
+ }
+
+ @Test
+ public void isSuggestionComplete_showSettingsSuggestionFalse_notWithinTimeThreshold() {
+ setZenUpdated(false);
+ setShowSettingsSuggestion(false);
+ setWithinTimeThreshold(false);
+ assertThat(isSuggestionComplete(mContext)).isTrue();
+ }
+
+ private void setZenUpdated(boolean updated) {
+ int zenUpdated = 0;
+ if (updated) {
+ zenUpdated = 1;
+ }
+
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.ZEN_SETTINGS_UPDATED, zenUpdated);
+ }
+
+ private void setWithinTimeThreshold(boolean withinTime) {
+ long firstTime = System.currentTimeMillis();
+
+ if (withinTime) {
+ firstTime -= ALWAYS_SHOW_THRESHOLD / 2;
+ } else {
+ firstTime -= ALWAYS_SHOW_THRESHOLD * 2;
+ }
+
+ getSharedPreferences().edit().putLong(PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME,
+ firstTime).commit();
+ }
+
+ private void setShowSettingsSuggestion(boolean show) {
+ int showZenSuggestion = 0;
+ if (show) {
+ showZenSuggestion = 1;
+ }
+
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.SHOW_ZEN_SETTINGS_SUGGESTION, showZenSuggestion);
+ }
+
+ private SharedPreferences getSharedPreferences() {
+ return mContext.getSharedPreferences("test_zen_sugg", Context.MODE_PRIVATE);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
index 75b6bb4b14a..7ee9ea51c45 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -67,7 +67,6 @@ public class ChooseLockPasswordTest {
Intent intent = new IntentBuilder(application)
.setPassword("password")
.setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
- .setPasswordLengthRange(123, 456)
.setUserId(123)
.build();
@@ -77,12 +76,6 @@ public class ChooseLockPasswordTest {
assertThat(intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
.named("EXTRA_KEY_PASSWORD")
.isEqualTo("password");
- assertThat(intent.getIntExtra(ChooseLockPassword.PASSWORD_MIN_KEY, 0))
- .named("PASSWORD_MIN_KEY")
- .isEqualTo(123);
- assertThat(intent.getIntExtra(ChooseLockPassword.PASSWORD_MAX_KEY, 0))
- .named("PASSWORD_MAX_KEY")
- .isEqualTo(456);
assertThat(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, 0))
.named("PASSWORD_TYPE_KEY")
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
@@ -96,7 +89,6 @@ public class ChooseLockPasswordTest {
Intent intent = new IntentBuilder(application)
.setChallenge(12345L)
.setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC)
- .setPasswordLengthRange(123, 456)
.setUserId(123)
.build();
@@ -106,12 +98,6 @@ public class ChooseLockPasswordTest {
assertThat(intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0L))
.named("EXTRA_KEY_CHALLENGE")
.isEqualTo(12345L);
- assertThat(intent.getIntExtra(ChooseLockPassword.PASSWORD_MIN_KEY, 0))
- .named("PASSWORD_MIN_KEY")
- .isEqualTo(123);
- assertThat(intent.getIntExtra(ChooseLockPassword.PASSWORD_MAX_KEY, 0))
- .named("PASSWORD_MAX_KEY")
- .isEqualTo(456);
assertThat(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, 0))
.named("PASSWORD_TYPE_KEY")
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
diff --git a/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java b/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java
index bb14667fce8..c6583c7eb03 100644
--- a/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java
+++ b/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java
@@ -30,6 +30,8 @@ import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.fingerprint.FingerprintEnrollSuggestionActivity;
import com.android.settings.fingerprint.FingerprintSuggestionActivity;
+import com.android.settings.notification.ZenOnboardingActivity;
+import com.android.settings.notification.ZenSuggestionActivity;
import com.android.settings.support.NewDeviceIntroSuggestionActivity;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.wallpaper.WallpaperSuggestionActivity;
@@ -82,6 +84,14 @@ public class SettingsSuggestionsTest {
R.string.night_display_suggestion_summary);
}
+ @Test
+ public void zenSuggestion_isValid() {
+ assertSuggestionEquals(
+ ZenSuggestionActivity.class.getName(),
+ R.string.zen_suggestion_title,
+ R.string.zen_suggestion_summary);
+ }
+
@Test
public void newDeviceIntroSuggestion_isValid() {
assertSuggestionEquals(
diff --git a/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java b/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java
index 15975689c7e..286676dd0d0 100644
--- a/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java
+++ b/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java
@@ -78,7 +78,7 @@ public class NewDeviceIntroSuggestionActivityTest {
final long currentTime = System.currentTimeMillis();
getSharedPreferences().edit().putLong(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME,
- currentTime - 2 * PERMANENT_DISMISS_THRESHOLD);
+ currentTime - 2 * PERMANENT_DISMISS_THRESHOLD).commit();
assertThat(isSuggestionComplete(mContext)).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java
new file mode 100644
index 00000000000..ac3ff3ff635
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2018 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.calling;
+
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+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.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.telephony.CarrierConfigManager;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceMetadata;
+import androidx.slice.SliceProvider;
+import androidx.slice.core.SliceAction;
+import androidx.slice.core.SliceQuery;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.ims.ImsManager;
+import com.android.settings.R;
+import com.android.settings.slices.SettingsSliceProvider;
+import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settings.slices.SliceBuilderUtils;
+import com.android.settings.slices.SliceData;
+import com.android.settings.slices.SlicesFeatureProvider;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class WifiCallingSliceHelperTest {
+
+ private Context mContext;
+ @Mock
+ private CarrierConfigManager mMockCarrierConfigManager;
+
+ @Mock
+ private ImsManager mMockImsManager;
+
+ private final Uri mWfcURI = Uri.parse("content://com.android.settings.slices/wifi_calling");
+
+ private FakeWifiCallingSliceHelper mWfcSliceHelper;
+ private SettingsSliceProvider mProvider;
+ private SliceBroadcastReceiver mReceiver;
+ private FakeFeatureFactory mFeatureFactory;
+ private SlicesFeatureProvider mSlicesFeatureProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+
+ //setup for SettingsSliceProvider tests
+ mProvider = spy(new SettingsSliceProvider());
+ doReturn(mContext).when(mProvider).getContext();
+
+ //setup for SliceBroadcastReceiver test
+ mReceiver = spy(new SliceBroadcastReceiver());
+
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mSlicesFeatureProvider = mFeatureFactory.getSlicesFeatureProvider();
+
+ // Prevent crash in SliceMetadata.
+ Resources resources = spy(mContext.getResources());
+ doReturn(60).when(resources).getDimensionPixelSize(anyInt());
+ doReturn(resources).when(mContext).getResources();
+
+ mWfcSliceHelper = new FakeWifiCallingSliceHelper(mContext);
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ }
+
+ @Test
+ public void test_CreateWifiCallingSlice_invalidSubId() {
+ mWfcSliceHelper.setDefaultVoiceSubId(-1);
+
+ final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
+
+ testWifiCallingSettingsUnavailableSlice(slice, null,
+ SliceBuilderUtils.getSettingsIntent(mContext));
+ }
+
+ @Test
+ public void test_CreateWifiCallingSlice_wfcNotSupported() {
+ doReturn(false).when(mMockImsManager).isWfcEnabledByPlatform();
+
+ final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
+
+ assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
+ testWifiCallingSettingsUnavailableSlice(slice, null,
+ SliceBuilderUtils.getSettingsIntent(mContext));
+ }
+
+ @Test
+ public void test_CreateWifiCallingSlice_needsActivation() {
+ /* In cases where activation is needed and the user action
+ would be turning on the wifi calling (i.e. if wifi calling is
+ turned off) we need to guide the user to wifi calling settings
+ activity so the user can perform the activation there.(PrimaryAction)
+ */
+ doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
+ doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
+ doReturn(false).when(mMockImsManager).isWfcEnabledByUser();
+ doReturn(false).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
+ doReturn(null).when(mMockCarrierConfigManager).getConfigForSubId(1);
+ mWfcSliceHelper.setActivationAppIntent(new Intent()); // dummy Intent
+
+ final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
+
+ assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
+ testWifiCallingSettingsUnavailableSlice(slice, null,
+ getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
+ }
+
+ @Test
+ public void test_CreateWifiCallingSlice_success() {
+ doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
+ doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
+ doReturn(true).when(mMockImsManager).isWfcEnabledByUser();
+ doReturn(true).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
+ doReturn(null).when(mMockCarrierConfigManager).getConfigForSubId(1);
+
+ final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
+
+ assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
+ testWifiCallingSettingsToggleSlice(slice, null);
+ }
+
+ @Test
+ public void test_SettingSliceProvider_getsRightSliceWifiCalling() {
+ doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
+ doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
+ doReturn(true).when(mMockImsManager).isWfcEnabledByUser();
+ doReturn(true).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
+ doReturn(null).when(mMockCarrierConfigManager).getConfigForSubId(1);
+ doReturn(mWfcSliceHelper).when(mSlicesFeatureProvider)
+ .getNewWifiCallingSliceHelper(mContext);
+
+ final Slice slice = mProvider.onBindSlice(mWfcURI);
+
+ assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
+ testWifiCallingSettingsToggleSlice(slice, null);
+ }
+
+ @Test
+ public void test_SliceBroadcastReceiver_toggleOffWifiCalling() {
+ doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
+ doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
+ doReturn(false).when(mMockImsManager).isWfcEnabledByUser();
+ doReturn(true).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
+ doReturn(mWfcSliceHelper).when(mSlicesFeatureProvider)
+ .getNewWifiCallingSliceHelper(mContext);
+ mWfcSliceHelper.setActivationAppIntent(null);
+
+ ArgumentCaptor mWfcSettingCaptor = ArgumentCaptor.forClass(Boolean.class);
+
+ // turn on Wifi calling setting
+ Intent intent = new Intent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED);
+ intent.putExtra(EXTRA_TOGGLE_STATE, true);
+
+ // change the setting
+ mReceiver.onReceive(mContext, intent);
+
+ verify((mMockImsManager)).setWfcSetting(mWfcSettingCaptor.capture());
+
+ // assert the change
+ assertThat(mWfcSettingCaptor.getValue()).isTrue();
+ }
+
+ private void testWifiCallingSettingsUnavailableSlice(Slice slice,
+ SliceData sliceData, PendingIntent expectedPrimaryAction) {
+ final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+
+ //Check there is no toggle action
+ final List toggles = metadata.getToggles();
+ assertThat(toggles).isEmpty();
+
+ // Check whether the primary action is to open wifi calling settings activity
+ final PendingIntent primaryPendingIntent =
+ metadata.getPrimaryAction().getAction();
+ assertThat(primaryPendingIntent).isEqualTo(expectedPrimaryAction);
+
+ // Check the title
+ final List sliceItems = slice.getItems();
+ assertTitle(sliceItems, mContext.getString(R.string.wifi_calling_settings_title));
+ }
+
+ private void testWifiCallingSettingsToggleSlice(Slice slice,
+ SliceData sliceData) {
+ final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+
+ final List toggles = metadata.getToggles();
+ assertThat(toggles).hasSize(1);
+
+ final SliceAction mainToggleAction = toggles.get(0);
+
+ // Check intent in Toggle Action
+ final PendingIntent togglePendingIntent = mainToggleAction.getAction();
+ final PendingIntent expectedToggleIntent = getBroadcastIntent(
+ WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED);
+ assertThat(togglePendingIntent).isEqualTo(expectedToggleIntent);
+
+ // Check primary intent
+ final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction();
+ final PendingIntent expectedPendingIntent =
+ getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY);
+ assertThat(primaryPendingIntent).isEqualTo(expectedPendingIntent);
+
+ // Check the title
+ final List sliceItems = slice.getItems();
+ assertTitle(sliceItems, mContext.getString(R.string.wifi_calling_settings_title));
+ }
+
+ private PendingIntent getBroadcastIntent(String action) {
+ final Intent intent = new Intent(action);
+ intent.setClass(mContext, SliceBroadcastReceiver.class);
+ return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+ private PendingIntent getActivityIntent(String action) {
+ final Intent intent = new Intent(action);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
+ }
+
+ private void assertTitle(List sliceItems, String title) {
+ boolean hasTitle = false;
+ for (SliceItem item : sliceItems) {
+ List titleItems = SliceQuery.findAll(item, FORMAT_TEXT, HINT_TITLE,
+ null /* non-hints */);
+ if (titleItems == null) {
+ continue;
+ }
+
+ hasTitle = true;
+ for (SliceItem subTitleItem : titleItems) {
+ assertThat(subTitleItem.getText()).isEqualTo(title);
+ }
+ }
+ assertThat(hasTitle).isTrue();
+ }
+ private class FakeWifiCallingSliceHelper extends WifiCallingSliceHelper {
+ int mSubId = 1;
+
+ private Intent mActivationAppIntent;
+ FakeWifiCallingSliceHelper(Context context) {
+ super(context);
+ mActivationAppIntent = null;
+ }
+
+ @Override
+ protected CarrierConfigManager getCarrierConfigManager(Context mContext) {
+ return mMockCarrierConfigManager;
+ }
+
+ @Override
+ protected ImsManager getImsManager(int subId) {
+ return mMockImsManager;
+ }
+
+ protected int getDefaultVoiceSubId() {
+ return mSubId;
+ }
+
+ protected void setDefaultVoiceSubId(int id) {
+ mSubId = id;
+ }
+
+ @Override
+ protected Intent getWifiCallingCarrierActivityIntent(int subId) {
+ return mActivationAppIntent;
+ }
+
+ public void setActivationAppIntent(Intent intent) {
+ mActivationAppIntent = intent;
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
new file mode 100644
index 00000000000..58bb1989d98
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.net.ConnectivityManager;
+
+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 java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class WifiTetherSettingsTest {
+
+ private Context mContext;
+
+ @Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
+ private UserManager mUserManager;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+
+ MockitoAnnotations.initMocks(this);
+ doReturn(mConnectivityManager)
+ .when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE);
+ doReturn(mUserManager)
+ .when(mContext).getSystemService(Context.USER_SERVICE);
+ }
+
+ @Test
+ public void testWifiTetherNonIndexableKeys_tetherAvailable_keysNotReturned() {
+ // To let TetherUtil.isTetherAvailable return true, select one of the combinations
+ setupIsTetherAvailable(true);
+
+ final List niks =
+ WifiTetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
+ assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
+ assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
+ assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
+ }
+
+ @Test
+ public void testWifiTetherNonIndexableKeys_tetherNotAvailable_keysReturned() {
+ // To let TetherUtil.isTetherAvailable return false, select one of the combinations
+ setupIsTetherAvailable(false);
+
+ final List niks =
+ WifiTetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
+ assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
+ assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
+ assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
+ }
+
+ private void setupIsTetherAvailable(boolean returnValue) {
+ when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
+
+ // For RestrictedLockUtils.checkIfRestrictionEnforced
+ final int userId = UserHandle.myUserId();
+ List enforcingUsers = new ArrayList<>();
+ when(mUserManager.getUserRestrictionSources(
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
+ .thenReturn(enforcingUsers);
+
+ // For RestrictedLockUtils.hasBaseUserRestriction
+ when(mUserManager.hasBaseUserRestriction(
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
+ .thenReturn(!returnValue);
+ }
+}