diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index eed87ed49ef..0fb6dc81334 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3051,11 +3051,12 @@
android:exported="false"
android:authorities="${applicationId}.battery.usage.bugreport"/>
-
+
diff --git a/res/drawable-sw600dp/ic_settings_about_device.xml b/res/drawable-sw600dp/ic_settings_about_device.xml
new file mode 100644
index 00000000000..a7164823762
--- /dev/null
+++ b/res/drawable-sw600dp/ic_settings_about_device.xml
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/res/drawable/ic_homepage_about.xml b/res/drawable/ic_homepage_about.xml
index ef2136eed8f..459ec934265 100644
--- a/res/drawable/ic_homepage_about.xml
+++ b/res/drawable/ic_homepage_about.xml
@@ -29,5 +29,5 @@
android:height="@dimen/dashboard_tile_foreground_image_size"
android:start="@dimen/dashboard_tile_foreground_image_inset"
android:top="@dimen/dashboard_tile_foreground_image_inset"
- android:drawable="@drawable/ic_phone_info" />
+ android:drawable="@drawable/ic_settings_about_device" />
diff --git a/res/drawable/ic_phone_info.xml b/res/drawable/ic_settings_about_device.xml
similarity index 100%
rename from res/drawable/ic_phone_info.xml
rename to res/drawable/ic_settings_about_device.xml
diff --git a/res/layout/locale_drag_cell.xml b/res/layout/locale_drag_cell.xml
index 7b932f39a02..47bf70a473e 100644
--- a/res/layout/locale_drag_cell.xml
+++ b/res/layout/locale_drag_cell.xml
@@ -56,6 +56,17 @@
android:layout_toStartOf="@+id/dragHandle"
android:layout_below="@id/label"/>
+
+
+ android:clipChildren="false"
+ android:layout_marginTop="@dimen/sfps_enroll_find_sensor_lottie_margin">
- "나쁨"
- "매우 약함"
- - "양호"
+ - "약함"
- "좋음"
- "우수함"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b086c1c928c..33f35a8d10d 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -407,4 +407,7 @@
0dp
0dp
0dp
+
+
+ 0dp
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c861ed9c3c8..0dc78dc3d1f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -312,6 +312,12 @@
Languages
+
+ Preferred language order
+
+
+ System language
+
Remove
@@ -325,13 +331,13 @@
Preferred Language
- App Languages
+ App languages
Set the language for each app
- App Language
+ App language
Suggested languages
@@ -354,6 +360,18 @@
Only apps that support language selection are shown here.
+
+ Your system, apps, and websites use the first supported language from your preferred languages.
+
+
+ To select a language for each app, go to app language settings.
+
+
+ Learn more about languages
+
+
+ https://support.google.com/android?p=per_language_app_settings
+
Regional preferences
@@ -407,7 +425,7 @@
Keep at least one preferred language
- May not be available in some apps
+ Not available as system language
Move up
@@ -808,6 +826,12 @@
How to set up your fingerprint
It\u2019s on the back of your phone. Use your index finger.
+
+ The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.
+
+ The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.
+
+ The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.
The fingerprint sensor is on your screen. You\u2019ll capture your fingerprint on the next screen.
@@ -2398,6 +2422,13 @@
%1$s is the only SIM in your device. Do you want to use this SIM for mobile data, calls, and SMS messages?
+
+ Switch SIMs automatically?
+
+ Allow your phone to automatically switch to %1$s for mobile data when it has better availability.
+
+ \n\nCalls, messages, and network traffic may be visible to your organization.
+
Incorrect SIM PIN code you must now contact your carrier to unlock your device.
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 2bc1b87a50c..82d7e43e5d1 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -748,6 +748,7 @@
diff --git a/res/xml/languages.xml b/res/xml/languages.xml
new file mode 100644
index 00000000000..0f455407645
--- /dev/null
+++ b/res/xml/languages.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/network_provider_internet.xml b/res/xml/network_provider_internet.xml
index bbe5ace96df..ef6ed16f73f 100644
--- a/res/xml/network_provider_internet.xml
+++ b/res/xml/network_provider_internet.xml
@@ -52,7 +52,8 @@
settings:userRestriction="no_config_mobile_networks"
settings:isPreferenceVisible="@bool/config_show_sim_info"
settings:allowDividerAbove="true"
- settings:useAdminDisabledSummary="true" />
+ settings:useAdminDisabledSummary="true"
+ settings:searchable="@bool/config_show_sim_info"/>
profileList = userManager.getProfiles(UserHandle.getCallingUserId());
+ final List profileList = userManager.getProfiles(currentUser);
// Only add non-Shell app as normal preference
final List nonShellPackageList = bugreportAllowlistedPackages.stream()
.filter(pkg -> !SHELL_APP_PACKAGE.equals(pkg)).collect(Collectors.toList());
@@ -228,11 +230,11 @@ public class BugReportHandlerUtil {
private void setBugreportHandlerAppAndUser(Context context, String handlerApp,
int handlerUser) {
- Settings.Global.putString(context.getContentResolver(),
- Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP,
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.CUSTOM_BUGREPORT_HANDLER_APP,
handlerApp);
- Settings.Global.putInt(context.getContentResolver(),
- Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER, handlerUser);
+ Settings.Secure.putInt(context.getContentResolver(),
+ Settings.Secure.CUSTOM_BUGREPORT_HANDLER_USER, handlerUser);
}
/**
diff --git a/src/com/android/settings/development/BugReportInPowerPreferenceController.java b/src/com/android/settings/development/BugReportInPowerPreferenceController.java
index 99ced773255..5ad63e0ac96 100644
--- a/src/com/android/settings/development/BugReportInPowerPreferenceController.java
+++ b/src/com/android/settings/development/BugReportInPowerPreferenceController.java
@@ -59,7 +59,7 @@ public class BugReportInPowerPreferenceController extends
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean isEnabled = (Boolean) newValue;
Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU,
+ Settings.Secure.BUGREPORT_IN_POWER_MENU,
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
return true;
}
@@ -67,7 +67,7 @@ public class BugReportInPowerPreferenceController extends
@Override
public void updateState(Preference preference) {
final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, SETTING_VALUE_OFF);
+ Settings.Secure.BUGREPORT_IN_POWER_MENU, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(mode != SETTING_VALUE_OFF);
}
@@ -75,7 +75,7 @@ public class BugReportInPowerPreferenceController extends
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, SETTING_VALUE_OFF);
+ Settings.Secure.BUGREPORT_IN_POWER_MENU, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(false);
}
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index c151517d6b4..66e09a9cc3b 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -133,10 +133,15 @@ public interface PowerUsageFeatureProvider {
boolean delayHourlyJobWhenBooting();
/**
- * Gets a intent for one time bypass charge limited to resume charging.
+ * Gets an intent for one time bypass charge limited to resume charging.
*/
Intent getResumeChargeIntent(boolean isDockDefender);
+ /**
+ * Returns the intent action used to mark as the full charge start event.
+ */
+ String getFullChargeIntentAction();
+
/**
* Returns {@link Set} for the system component ids which are combined into others
*/
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 657e5c6018b..e0af88a694e 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -147,6 +147,11 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
return null;
}
+ @Override
+ public String getFullChargeIntentAction() {
+ return Intent.ACTION_BATTERY_LEVEL_CHANGED;
+ }
+
@Override
public boolean isExtraDefend() {
return false;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
index 817d367ca11..9c7ec35fb4a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
@@ -26,6 +26,7 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.fuelgauge.BatteryStatus;
import java.time.Duration;
@@ -36,6 +37,9 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver {
/** An intent action to request Settings to clear cache data. */
public static final String ACTION_CLEAR_BATTERY_CACHE_DATA =
"com.android.settings.battery.action.CLEAR_BATTERY_CACHE_DATA";
+ /** An intent action to request Settings to clear cache data. */
+ public static final String ACTION_BATTERY_UNPLUGGING =
+ "com.android.settings.battery.action.ACTION_BATTERY_UNPLUGGING";
@VisibleForTesting
static long sBroadcastDelayFromBoot = Duration.ofMinutes(40).toMillis();
@@ -51,9 +55,27 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver {
return;
}
Log.d(TAG, "onReceive:" + intent.getAction());
+ final String fullChargeIntentAction = FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getFullChargeIntentAction();
switch (intent.getAction()) {
case Intent.ACTION_BATTERY_LEVEL_CHANGED:
- tryToFetchUsageData(context);
+ // Only when fullChargeIntentAction is ACTION_BATTERY_LEVEL_CHANGED,
+ // ACTION_BATTERY_LEVEL_CHANGED will be considered as the full charge event and then
+ // start usage events fetching.
+ if (Intent.ACTION_BATTERY_LEVEL_CHANGED.equals(fullChargeIntentAction)) {
+ Log.d(TAG, "fetch data because of event: ACTION_BATTERY_LEVEL_CHANGED");
+ tryToFetchUsageData(context);
+ }
+ break;
+ case ACTION_BATTERY_UNPLUGGING:
+ // Only when fullChargeIntentAction is ACTION_POWER_DISCONNECTED,
+ // ACTION_BATTERY_UNPLUGGING will be considered as the full charge event and then
+ // start usage events fetching.
+ if (Intent.ACTION_POWER_DISCONNECTED.equals(fullChargeIntentAction)) {
+ Log.d(TAG, "fetch data because of event: ACTION_POWER_DISCONNECTED");
+ tryToFetchUsageData(context);
+ }
break;
case ACTION_CLEAR_BATTERY_CACHE_DATA:
if (sIsDebugMode) {
@@ -74,7 +96,7 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver {
final long broadcastDelay = sBroadcastDelayFromBoot - SystemClock.elapsedRealtime();
// If current boot time is smaller than expected delay, cancel sending the broadcast.
if (broadcastDelay > 0) {
- Log.d(TAG, "cancel sendBroadcastToFetchUsageData when broadcastDelay is"
+ Log.d(TAG, "cancel sendBroadcastToFetchUsageData when broadcastDelay is "
+ broadcastDelay + "ms.");
return;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
index eaac00a2588..800dc1426e6 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
@@ -56,6 +56,10 @@ public class SpinnerPreference extends Preference {
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
+ if (mSpinner != null) {
+ return;
+ }
+
mSpinner = (Spinner) view.findViewById(R.id.spinner);
mSpinner.setAdapter(new SpinnerAdapter(getContext(), mItems));
mSpinner.setSelection(mSavedSpinnerPosition);
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index ab9110d01ab..b3c2e3071af 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -43,7 +43,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-
class LocaleDragAndDropAdapter
extends RecyclerView.Adapter {
@@ -154,8 +153,10 @@ class LocaleDragAndDropAdapter
final LocaleDragCell dragCell = holder.getLocaleDragCell();
final String label = feedItem.getFullNameNative();
final String description = feedItem.getFullNameInUiLanguage();
+
dragCell.setLabelAndDescription(label, description);
dragCell.setLocalized(feedItem.isTranslated());
+ dragCell.setCurrentDefault(feedItem.getLocale().equals(Locale.getDefault()));
dragCell.setMiniLabel(mNumberFormatter.format(i + 1));
dragCell.setShowCheckbox(mRemoveMode);
dragCell.setShowMiniLabel(!mRemoveMode);
diff --git a/src/com/android/settings/localepicker/LocaleDragCell.java b/src/com/android/settings/localepicker/LocaleDragCell.java
index ea86189b018..2f4cfefefb1 100644
--- a/src/com/android/settings/localepicker/LocaleDragCell.java
+++ b/src/com/android/settings/localepicker/LocaleDragCell.java
@@ -33,6 +33,7 @@ class LocaleDragCell extends RelativeLayout {
private CheckBox mCheckbox;
private TextView mMiniLabel;
private TextView mLocalized;
+ private TextView mCurrentDefault;
private ImageView mDragHandle;
public LocaleDragCell(Context context, AttributeSet attrs) {
@@ -44,6 +45,7 @@ class LocaleDragCell extends RelativeLayout {
super.onFinishInflate();
mLabel = (TextView) findViewById(R.id.label);
mLocalized = (TextView) findViewById(R.id.l10nWarn);
+ mCurrentDefault = (TextView) findViewById(R.id.default_locale);
mMiniLabel = (TextView) findViewById(R.id.miniLabel);
mCheckbox = (CheckBox) findViewById(R.id.checkbox);
mDragHandle = (ImageView) findViewById(R.id.dragHandle);
@@ -100,6 +102,14 @@ class LocaleDragCell extends RelativeLayout {
invalidate();
}
+ /**
+ * Indicate current locale is system default.
+ */
+ public void setCurrentDefault(boolean isCurrentDefault) {
+ mCurrentDefault.setVisibility(isCurrentDefault ? VISIBLE : GONE);
+ invalidate();
+ }
+
public ImageView getDragHandle() {
return mDragHandle;
}
diff --git a/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
new file mode 100644
index 00000000000..05c740139cc
--- /dev/null
+++ b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.localepicker;
+
+import android.content.Context;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.FooterPreference;
+
+/**
+ * A controller to update current locale information of application.
+ */
+public class LocaleHelperPreferenceController extends AbstractPreferenceController {
+ private static final String TAG = LocaleHelperPreferenceController.class.getSimpleName();
+
+ private static final String KEY_FOOTER_LANGUAGE_PICKER = "footer_languages_picker";
+
+ public LocaleHelperPreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_FOOTER_LANGUAGE_PICKER;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ FooterPreference footerPreference = screen.findPreference(getPreferenceKey());
+ updateFooterPreference(footerPreference);
+ }
+
+ @VisibleForTesting
+ void updateFooterPreference(FooterPreference footerPreference) {
+ if (footerPreference != null) {
+ footerPreference.setLearnMoreAction(v -> openLocaleLearnMoreLink());
+ footerPreference.setLearnMoreText(mContext.getString(
+ R.string.desc_locale_helper_footer_general));
+ }
+ }
+
+ private void openLocaleLearnMoreLink() {
+ mContext.startActivity(
+ HelpUtils.getHelpIntent(
+ mContext,
+ mContext.getString(R.string.link_locale_picker_footer_learn_more),
+ /*backupContext=*/""));
+ }
+}
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 1d6fb47d76a..75ea768e232 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -36,6 +36,7 @@ import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
+import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.app.LocalePicker;
@@ -47,6 +48,7 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.search.SearchIndexableRaw;
import com.android.settingslib.utils.StringUtil;
+import com.android.settingslib.widget.LayoutPreference;
import java.util.ArrayList;
import java.util.List;
@@ -65,6 +67,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
private static final int REQUEST_LOCALE_PICKER = 0;
private static final String INDEX_KEY_ADD_LANGUAGE = "add_language";
+ private static final String KEY_LANGUAGES_PICKER = "languages_picker";
private LocaleDragAndDropAdapter mAdapter;
private Menu mMenu;
@@ -73,6 +76,9 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
private boolean mShowingRemoveDialog;
private boolean mIsUiRestricted;
+ private LayoutPreference mLocalePickerPreference;
+ private LocaleHelperPreferenceController mLocaleHelperPreferenceController;
+
public LocaleListEditor() {
super(DISALLOW_CONFIG_LOCALE);
}
@@ -87,6 +93,14 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
+ addPreferencesFromResource(R.xml.languages);
+ final Activity activity = getActivity();
+ activity.setTitle(R.string.language_picker_title);
+ mLocaleHelperPreferenceController = new LocaleHelperPreferenceController(activity);
+ final PreferenceScreen screen = getPreferenceScreen();
+ mLocalePickerPreference = screen.findPreference(KEY_LANGUAGES_PICKER);
+ mLocaleHelperPreferenceController.displayPreference(screen);
+
LocaleStore.fillCache(this.getContext());
final List feedsList = getUserLocaleList();
mAdapter = new LocaleDragAndDropAdapter(this.getContext(), feedsList);
@@ -94,11 +108,8 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstState) {
- final View result = super.onCreateView(inflater, container, savedInstState);
- final View myLayout = inflater.inflate(R.layout.locale_order_list, (ViewGroup) result);
-
- configureDragAndDrop(myLayout);
- return result;
+ configureDragAndDrop(mLocalePickerPreference);
+ return super.onCreateView(inflater, container, savedInstState);
}
@Override
@@ -288,8 +299,8 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
return result;
}
- private void configureDragAndDrop(View view) {
- final RecyclerView list = view.findViewById(R.id.dragList);
+ private void configureDragAndDrop(LayoutPreference layout) {
+ final RecyclerView list = layout.findViewById(R.id.dragList);
final LocaleLinearLayoutManager llm = new LocaleLinearLayoutManager(getContext(), mAdapter);
llm.setAutoMeasureEnabled(true);
list.setLayoutManager(llm);
@@ -298,7 +309,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
mAdapter.setRecyclerView(list);
list.setAdapter(mAdapter);
- mAddLanguage = view.findViewById(R.id.add_language);
+ mAddLanguage = layout.findViewById(R.id.add_language);
mAddLanguage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragment.java b/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragment.java
new file mode 100644
index 00000000000..b1b5f8e69ed
--- /dev/null
+++ b/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragment.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 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.sim;
+
+import android.app.Dialog;
+import android.app.settings.SettingsEnums;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+import com.android.settings.network.SubscriptionUtil;
+
+import java.util.List;
+
+/**
+ * Show a dialog prompting the user to enable auto data switch following the dialog where user chose
+ * default data SIM.
+ */
+public class EnableAutoDataSwitchDialogFragment extends SimDialogFragment implements
+ DialogInterface.OnClickListener {
+ private static final String TAG = "EnableAutoDataSwitchDialogFragment";
+ /** Sub Id of the non-default data SIM */
+ private int mBackupDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+ /** @return a new instance of this fragment */
+ public static EnableAutoDataSwitchDialogFragment newInstance() {
+ final EnableAutoDataSwitchDialogFragment fragment =
+ new EnableAutoDataSwitchDialogFragment();
+ final Bundle args = initArguments(SimDialogActivity.ENABLE_AUTO_DATA_SWITCH,
+ R.string.enable_auto_data_switch_dialog_title);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ final AlertDialog dialog = new AlertDialog.Builder(getContext())
+ .setPositiveButton(R.string.yes, this)
+ .setNegativeButton(R.string.sim_action_no_thanks, null)
+ .create();
+ updateDialog(dialog);
+ return dialog;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.DIALOG_AUTO_DATA_SWITCH;
+ }
+
+ /** update dialog */
+ public void updateDialog(AlertDialog dialog) {
+ Log.d(TAG, "Dialog updated, dismiss status: " + mWasDismissed);
+
+ if (mWasDismissed) {
+ return;
+ }
+
+ if (dialog == null) {
+ Log.d(TAG, "Dialog is null.");
+ dismiss();
+ return;
+ }
+
+ // Set message
+ View content = LayoutInflater.from(getContext()).inflate(
+ R.layout.sim_confirm_dialog_multiple_enabled_profiles_supported, null);
+ TextView dialogMessage = content != null ? content.findViewById(R.id.msg) : null;
+ final String message = getMessage();
+ if (TextUtils.isEmpty(message) || dialogMessage == null) {
+ onDismiss(dialog);
+ return;
+ }
+ dialogMessage.setText(message);
+ dialogMessage.setVisibility(View.VISIBLE);
+ dialog.setView(content);
+
+ // Set title
+ View titleView = LayoutInflater.from(getContext()).inflate(
+ R.layout.sim_confirm_dialog_title_multiple_enabled_profiles_supported, null);
+ TextView titleTextView = titleView.findViewById(R.id.title);
+ titleTextView.setText(getContext().getString(getTitleResId()));
+ dialog.setCustomTitle(titleTextView);
+ }
+
+ /**
+ * @return The message of the dialog. {@code null} if the dialog shouldn't be displayed.
+ */
+ @VisibleForTesting
+ protected String getMessage() {
+ int ddsSubId = getDefaultDataSubId();
+ if (ddsSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return null;
+ Log.d(TAG, "DDS SubId: " + ddsSubId);
+
+ SubscriptionManager subscriptionManager = getSubscriptionManager();
+ List activeSubscriptions = subscriptionManager
+ .getActiveSubscriptionInfoList();
+ if (activeSubscriptions == null) return null;
+
+ // Find if a backup data sub exists.
+ SubscriptionInfo backupSubInfo = activeSubscriptions.stream()
+ .filter(subInfo -> subInfo.getSubscriptionId() != ddsSubId)
+ .findFirst()
+ .orElse(null);
+ if (backupSubInfo == null) return null;
+ mBackupDataSubId = backupSubInfo.getSubscriptionId();
+
+ // Check if auto data switch is already enabled
+ final TelephonyManager telephonyManager = getTelephonyManagerForSub(mBackupDataSubId);
+ if (telephonyManager == null) {
+ Log.d(TAG, "telephonyManager for " + mBackupDataSubId + " is null");
+ return null;
+ }
+ if (telephonyManager.isMobileDataPolicyEnabled(
+ TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)) {
+ Log.d(TAG, "AUTO_DATA_SWITCH already enabled");
+ return null;
+ }
+
+ Log.d(TAG, "Backup data sub Id: " + mBackupDataSubId);
+ // The description of the feature
+ String message =
+ getContext().getString(
+ R.string.enable_auto_data_switch_dialog_message,
+ SubscriptionUtil.getUniqueSubscriptionDisplayName(
+ backupSubInfo, getContext()));
+ UserManager userManager = getUserManager();
+ if (userManager == null) return message;
+
+ // If one of the sub is dedicated to work profile(enterprise-managed), which means we might
+ // switching between personal & work profile, append a warning to the message.
+ UserHandle ddsUserHandle = subscriptionManager.getSubscriptionUserHandle(ddsSubId);
+ UserHandle nDdsUserHandle = subscriptionManager.getSubscriptionUserHandle(mBackupDataSubId);
+ boolean isDdsManaged = ddsUserHandle != null && userManager.isManagedProfile(
+ ddsUserHandle.getIdentifier());
+ boolean isNDdsManaged = nDdsUserHandle != null && userManager.isManagedProfile(
+ nDdsUserHandle.getIdentifier());
+ Log.d(TAG, "isDdsManaged= " + isDdsManaged + " isNDdsManaged=" + isNDdsManaged);
+ if (isDdsManaged ^ isNDdsManaged) {
+ message += getContext().getString(
+ R.string.auto_data_switch_dialog_managed_profile_warning);
+ }
+
+ return message;
+ }
+
+ @Override
+ public void updateDialog() {
+ updateDialog((AlertDialog) getDialog());
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int buttonClicked) {
+ if (buttonClicked != DialogInterface.BUTTON_POSITIVE) {
+ return;
+ }
+ final SimDialogActivity activity = (SimDialogActivity) getActivity();
+ if (mBackupDataSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ activity.onSubscriptionSelected(getDialogType(), mBackupDataSubId);
+ }
+ }
+
+ private TelephonyManager getTelephonyManagerForSub(int subId) {
+ return getContext().getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(subId);
+ }
+
+ private SubscriptionManager getSubscriptionManager() {
+ return getContext().getSystemService(SubscriptionManager.class);
+ }
+
+ @VisibleForTesting
+ protected int getDefaultDataSubId() {
+ return SubscriptionManager.getDefaultDataSubscriptionId();
+ }
+
+ private UserManager getUserManager() {
+ return getContext().getSystemService(UserManager.class);
+ }
+}
diff --git a/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java b/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java
index b2ca6210a86..6ac0067d382 100644
--- a/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java
+++ b/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java
@@ -72,14 +72,31 @@ public class SelectSpecificDataSimDialogFragment extends SimDialogFragment imple
}
@Override
- public void onClick(DialogInterface dialog, int buttonClicked) {
- if (buttonClicked != DialogInterface.BUTTON_POSITIVE) {
- return;
+ public void onDismiss(@NonNull DialogInterface dialog) {
+ Log.d(TAG, "Dialog onDismiss, dismiss status: " + mWasDismissed);
+ if (!mWasDismissed) {
+ // This dialog might be called onDismiss twice due to first time called by onDismiss()
+ // as a consequence of user action. We need this fragment alive so the activity
+ // doesn't end, which allows the following dialog to attach. Upon the second dialog
+ // dismiss, this fragment is removed from SimDialogActivity.onFragmentDismissed to
+ // end the activity.
+ mWasDismissed = true;
+ final SimDialogActivity activity = (SimDialogActivity) getActivity();
+ activity.showEnableAutoDataSwitchDialog();
+ // Not using super.onDismiss because it will result in an immediate end of the activity,
+ // before the second auto data switch dialog can attach.
+ if (getDialog() != null) getDialog().dismiss();
}
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int buttonClicked) {
final SimDialogActivity activity = (SimDialogActivity) getActivity();
- final SubscriptionInfo info = getTargetSubscriptionInfo();
- if (info != null) {
- activity.onSubscriptionSelected(getDialogType(), info.getSubscriptionId());
+ if (buttonClicked == DialogInterface.BUTTON_POSITIVE) {
+ final SubscriptionInfo info = getTargetSubscriptionInfo();
+ if (info != null) {
+ activity.onSubscriptionSelected(getDialogType(), info.getSubscriptionId());
+ }
}
}
diff --git a/src/com/android/settings/sim/SimDialogActivity.java b/src/com/android/settings/sim/SimDialogActivity.java
index 464ba9b4a51..a1258be64b0 100644
--- a/src/com/android/settings/sim/SimDialogActivity.java
+++ b/src/com/android/settings/sim/SimDialogActivity.java
@@ -16,8 +16,6 @@
package com.android.settings.sim;
-import static android.content.Context.MODE_PRIVATE;
-
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -61,6 +59,8 @@ public class SimDialogActivity extends FragmentActivity {
public static final int SMS_PICK_FOR_MESSAGE = 4;
// Dismiss the current dialog and finish the activity.
public static final int PICK_DISMISS = 5;
+ // Show auto data switch dialog(when user enables multi-SIM)
+ public static final int ENABLE_AUTO_DATA_SWITCH = 6;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -122,7 +122,7 @@ public class SimDialogActivity extends FragmentActivity {
private SimDialogFragment createFragment(int dialogType) {
switch (dialogType) {
case DATA_PICK:
- return getDataPickDialogFramgent();
+ return getDataPickDialogFragment();
case CALLS_PICK:
return CallsSimListDialogFragment.newInstance(dialogType,
R.string.select_sim_for_calls,
@@ -141,12 +141,14 @@ public class SimDialogActivity extends FragmentActivity {
return SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_sms,
false /* includeAskEveryTime */,
false /* isCancelItemShowed */);
+ case ENABLE_AUTO_DATA_SWITCH:
+ return EnableAutoDataSwitchDialogFragment.newInstance();
default:
throw new IllegalArgumentException("Invalid dialog type " + dialogType + " sent.");
}
}
- private SimDialogFragment getDataPickDialogFramgent() {
+ private SimDialogFragment getDataPickDialogFragment() {
if (SubscriptionManager.getDefaultDataSubscriptionId()
== SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
return SimListDialogFragment.newInstance(DATA_PICK, R.string.select_sim_for_data,
@@ -181,15 +183,40 @@ public class SimDialogActivity extends FragmentActivity {
intent.putExtra(RESULT_SUB_ID, subId);
setResult(Activity.RESULT_OK, intent);
break;
+ case ENABLE_AUTO_DATA_SWITCH:
+ onEnableAutoDataSwitch(subId);
+ break;
default:
throw new IllegalArgumentException(
"Invalid dialog type " + dialogType + " sent.");
}
}
+ /**
+ * Show dialog prompting the user to enable auto data switch
+ */
+ public void showEnableAutoDataSwitchDialog() {
+ final FragmentManager fragmentManager = getSupportFragmentManager();
+ SimDialogFragment fragment = createFragment(ENABLE_AUTO_DATA_SWITCH);
+ fragment.show(fragmentManager, Integer.toString(ENABLE_AUTO_DATA_SWITCH));
+ }
+
+ /**
+ * @param subId The sub Id to enable auto data switch
+ */
+ public void onEnableAutoDataSwitch(int subId) {
+ Log.d(TAG, "onEnableAutoDataSwitch subId:" + subId);
+ final TelephonyManager telephonyManager = getSystemService(
+ TelephonyManager.class).createForSubscriptionId(subId);
+ telephonyManager.setMobileDataPolicyEnabled(
+ TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true);
+ }
+
public void onFragmentDismissed(SimDialogFragment simDialogFragment) {
final List fragments = getSupportFragmentManager().getFragments();
- if (fragments.size() == 1 && fragments.get(0) == simDialogFragment) {
+ if (fragments.size() == 1 && fragments.get(0) == simDialogFragment
+ || simDialogFragment.getDialogType() == ENABLE_AUTO_DATA_SWITCH) {
+ Log.d(TAG, "onFragmentDismissed dialogType:" + simDialogFragment.getDialogType());
finishAndRemoveTask();
}
}
@@ -200,7 +227,8 @@ public class SimDialogActivity extends FragmentActivity {
TelephonyManager.class).createForSubscriptionId(subId);
subscriptionManager.setDefaultDataSubId(subId);
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- telephonyManager.setDataEnabled(true);
+ telephonyManager.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER,
+ true);
Toast.makeText(this, R.string.data_switch_started, Toast.LENGTH_LONG).show();
}
}
diff --git a/src/com/android/settings/sim/SimListDialogFragment.java b/src/com/android/settings/sim/SimListDialogFragment.java
index 245d31e8980..5b84d7b67c0 100644
--- a/src/com/android/settings/sim/SimListDialogFragment.java
+++ b/src/com/android/settings/sim/SimListDialogFragment.java
@@ -109,16 +109,18 @@ public class SimListDialogFragment extends SimDialogFragment {
* @param selectionIndex the index of item in the list.
*/
public void onClick(int selectionIndex) {
+ final SimDialogActivity activity = (SimDialogActivity) getActivity();
if (selectionIndex >= 0 && selectionIndex < mSubscriptions.size()) {
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
final SubscriptionInfo subscription = mSubscriptions.get(selectionIndex);
if (subscription != null) {
subId = subscription.getSubscriptionId();
}
- final SimDialogActivity activity = (SimDialogActivity) getActivity();
activity.onSubscriptionSelected(getDialogType(), subId);
}
- dismiss();
+ Log.d(TAG, "Start showing auto data switch dialog");
+ activity.showEnableAutoDataSwitchDialog();
+ if (getDialog() != null) getDialog().dismiss();
}
protected List getCurrentSubscriptions() {
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index b4b4d6e09b5..55ea0c95861 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -41,24 +41,27 @@ import com.android.settings.spa.system.SystemMainPageProvider
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
import com.android.settingslib.spa.framework.common.SpaEnvironment
+import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListTemplate
open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
+ open fun getTogglePermissionAppListProviders(): List {
+ return listOf(
+ AllFilesAccessAppListProvider,
+ DisplayOverOtherAppsAppListProvider,
+ MediaManagementAppsAppListProvider,
+ ModifySystemSettingsAppListProvider,
+ PictureInPictureListProvider,
+ InstallUnknownAppsListProvider,
+ AlarmsAndRemindersAppListProvider,
+ WifiControlAppListProvider,
+ )
+ }
+
override val pageProviderRepository = lazy {
- val togglePermissionAppListTemplate =
- TogglePermissionAppListTemplate(
- allProviders =
- listOf(
- AllFilesAccessAppListProvider,
- DisplayOverOtherAppsAppListProvider,
- MediaManagementAppsAppListProvider,
- ModifySystemSettingsAppListProvider,
- PictureInPictureListProvider,
- InstallUnknownAppsListProvider,
- AlarmsAndRemindersAppListProvider,
- WifiControlAppListProvider,
- ),
- )
+ val togglePermissionAppListTemplate = TogglePermissionAppListTemplate(
+ allProviders = getTogglePermissionAppListProviders()
+ )
SettingsPageProviderRepository(
allPageProviders = listOf(
HomePageProvider,
diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java
index f9b42209755..b84fc323edd 100644
--- a/src/com/android/settings/users/UserDetailsSettings.java
+++ b/src/com/android/settings/users/UserDetailsSettings.java
@@ -307,8 +307,9 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
mSwitchUserPref.setSelectable(true);
mSwitchUserPref.setOnPreferenceClickListener(this);
}
- //TODO(b/261700461): remove preference for supervised user
- if (mUserInfo.isMain() || mUserInfo.isGuest() || !UserManager.isMultipleAdminEnabled()) {
+ if (mUserInfo.isMain() || mUserInfo.isGuest() || !UserManager.isMultipleAdminEnabled()
+ || mUserManager.hasUserRestrictionForUser(UserManager.DISALLOW_GRANT_ADMIN,
+ mUserInfo.getUserHandle())) {
removePreference(KEY_GRANT_ADMIN);
}
if (!mUserManager.isAdminUser()) { // non admin users can't remove users and allow calls
diff --git a/tests/robotests/src/com/android/settings/development/BugReportInPowerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BugReportInPowerPreferenceControllerTest.java
index 604dcb7a783..462ed16074b 100644
--- a/tests/robotests/src/com/android/settings/development/BugReportInPowerPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/BugReportInPowerPreferenceControllerTest.java
@@ -99,7 +99,7 @@ public class BugReportInPowerPreferenceControllerTest {
mController.onPreferenceChange(mPreference, false /* new value */);
int mode = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, -1 /* default */);
+ Settings.Secure.BUGREPORT_IN_POWER_MENU, -1 /* default */);
assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
}
@@ -111,7 +111,7 @@ public class BugReportInPowerPreferenceControllerTest {
mController.onPreferenceChange(mPreference, true /* new value */);
int mode = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, -1 /* default */);
+ Settings.Secure.BUGREPORT_IN_POWER_MENU, -1 /* default */);
assertThat(mode).isEqualTo(SETTING_VALUE_ON);
}
@@ -121,7 +121,7 @@ public class BugReportInPowerPreferenceControllerTest {
public void updateState_settingsOn_preferenceShouldBeChecked() {
when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, SETTING_VALUE_ON);
+ Settings.Secure.BUGREPORT_IN_POWER_MENU, SETTING_VALUE_ON);
mController.displayPreference(mScreen);
mController.updateState(mPreference);
@@ -133,7 +133,7 @@ public class BugReportInPowerPreferenceControllerTest {
public void updateState_settingsOff_preferenceShouldNotBeChecked() {
when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, SETTING_VALUE_OFF);
+ Settings.Secure.BUGREPORT_IN_POWER_MENU, SETTING_VALUE_OFF);
mController.displayPreference(mScreen);
mController.updateState(mPreference);
@@ -148,7 +148,7 @@ public class BugReportInPowerPreferenceControllerTest {
mController.onDeveloperOptionsSwitchDisabled();
int mode = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, -1 /* default */);
+ Settings.Secure.BUGREPORT_IN_POWER_MENU, -1 /* default */);
assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
verify(mPreference).setChecked(false);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
index 104a6773f09..5f70a5e84ae 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
@@ -150,8 +151,9 @@ public class BatteryOptimizeUtilsTest {
@Test
public void testSetAppUsageState_Restricted_verifyAction() throws Exception {
// Sets the current mode as MODE_UNRESTRICTED.
- mBatteryOptimizeUtils.mAllowListed = false;
- mBatteryOptimizeUtils.mMode = AppOpsManager.MODE_ALLOWED;
+ when(mMockBackend.isAllowlisted(anyString())).thenReturn(true);
+ when(mMockAppOpsManager.checkOpNoThrow(anyInt(), anyInt(), anyString()))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
mBatteryOptimizeUtils.setAppUsageState(MODE_RESTRICTED, Action.UNKNOWN);
TimeUnit.SECONDS.sleep(1);
@@ -161,6 +163,12 @@ public class BatteryOptimizeUtilsTest {
@Test
public void testSetAppUsageState_Unrestricted_verifyAction() throws Exception {
+ // Sets the current mode as MODE_RESTRICTED.
+ when(mMockBackend.isAllowlisted(anyString())).thenReturn(false);
+ when(mMockAppOpsManager.checkOpNoThrow(anyInt(), anyInt(), anyString()))
+ .thenReturn(AppOpsManager.MODE_IGNORED);
+
+
mBatteryOptimizeUtils.setAppUsageState(MODE_UNRESTRICTED, Action.UNKNOWN);
TimeUnit.SECONDS.sleep(1);
@@ -169,6 +177,11 @@ public class BatteryOptimizeUtilsTest {
@Test
public void testSetAppUsageState_Optimized_verifyAction() throws Exception {
+ // Sets the current mode as MODE_UNRESTRICTED.
+ when(mMockBackend.isAllowlisted(anyString())).thenReturn(true);
+ when(mMockAppOpsManager.checkOpNoThrow(anyInt(), anyInt(), anyString()))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
+
mBatteryOptimizeUtils.setAppUsageState(MODE_OPTIMIZED, Action.UNKNOWN);
TimeUnit.SECONDS.sleep(1);
@@ -178,14 +191,16 @@ public class BatteryOptimizeUtilsTest {
@Test
public void testSetAppUsageState_sameUnrestrictedMode_verifyNoAction() throws Exception {
// Sets the current mode as MODE_UNRESTRICTED.
- mBatteryOptimizeUtils.mAllowListed = true;
- mBatteryOptimizeUtils.mMode = AppOpsManager.MODE_ALLOWED;
+ when(mMockBackend.isAllowlisted(anyString())).thenReturn(true);
+ when(mMockAppOpsManager.checkOpNoThrow(anyInt(), anyInt(), anyString()))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
mBatteryOptimizeUtils.setAppUsageState(MODE_UNRESTRICTED, Action.UNKNOWN);
TimeUnit.SECONDS.sleep(1);
- verifyNoInteractions(mMockBackend);
- verifyNoInteractions(mMockBatteryUtils);
+ verify(mMockBatteryUtils, never()).setForceAppStandby(anyInt(), anyString(), anyInt());
+ verify(mMockBackend, never()).addApp(anyString());
+ verify(mMockBackend, never()).removeApp(anyString());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
index addfd9bfdb9..60481975429 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
@@ -29,6 +30,8 @@ import android.os.BatteryManager;
import android.os.SystemClock;
import android.text.format.DateUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,6 +45,8 @@ public final class BatteryUsageBroadcastReceiverTest {
private Context mContext;
private BatteryUsageBroadcastReceiver mBatteryUsageBroadcastReceiver;
+ private FakeFeatureFactory mFakeFeatureFactory;
+
@Mock
private PackageManager mPackageManager;
@@ -49,6 +54,7 @@ public final class BatteryUsageBroadcastReceiverTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mBatteryUsageBroadcastReceiver = new BatteryUsageBroadcastReceiver();
doReturn(mPackageManager).when(mContext).getPackageManager();
}
@@ -62,6 +68,8 @@ public final class BatteryUsageBroadcastReceiverTest {
@Test
public void onReceive_actionBatteryLevelChanged_notFetchUsageData_notFullCharged() {
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction())
+ .thenReturn(Intent.ACTION_BATTERY_LEVEL_CHANGED);
doReturn(getBatteryIntent(/*level=*/ 20, BatteryManager.BATTERY_STATUS_UNKNOWN))
.when(mContext).registerReceiver(any(), any());
@@ -72,7 +80,9 @@ public final class BatteryUsageBroadcastReceiverTest {
}
@Test
- public void onReceive_actionBatteryLevelChanged_cancelFetchUsageData() {
+ public void onReceive_actionBatteryLevelChanged_notFetchUsageData_nearBooting() {
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction())
+ .thenReturn(Intent.ACTION_BATTERY_LEVEL_CHANGED);
// Make sure isCharged returns true.
doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_FULL))
.when(mContext).registerReceiver(any(), any());
@@ -87,7 +97,25 @@ public final class BatteryUsageBroadcastReceiverTest {
}
@Test
- public void onReceive_actionBatteryLevelChanged_notFetchUsageData() {
+ public void onReceive_actionBatteryLevelChanged_notFetchUsageData_wrongAction() {
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction())
+ .thenReturn(Intent.ACTION_POWER_DISCONNECTED);
+ // Make sure isCharged returns true.
+ doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_UNKNOWN))
+ .when(mContext).registerReceiver(any(), any());
+ BatteryUsageBroadcastReceiver.sBroadcastDelayFromBoot =
+ SystemClock.elapsedRealtime() - 5 * DateUtils.MINUTE_IN_MILLIS;
+
+ mBatteryUsageBroadcastReceiver.onReceive(mContext,
+ new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED));
+
+ assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse();
+ }
+
+ @Test
+ public void onReceive_actionBatteryLevelChanged_fetchUsageData() {
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction())
+ .thenReturn(Intent.ACTION_BATTERY_LEVEL_CHANGED);
// Make sure isCharged returns true.
doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_UNKNOWN))
.when(mContext).registerReceiver(any(), any());
@@ -100,6 +128,67 @@ public final class BatteryUsageBroadcastReceiverTest {
assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isTrue();
}
+ @Test
+ public void onReceive_actionBatteryUnplugging_notFetchUsageData_notFullCharged() {
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction())
+ .thenReturn(Intent.ACTION_POWER_DISCONNECTED);
+ doReturn(getBatteryIntent(/*level=*/ 20, BatteryManager.BATTERY_STATUS_UNKNOWN))
+ .when(mContext).registerReceiver(any(), any());
+
+ mBatteryUsageBroadcastReceiver.onReceive(mContext,
+ new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
+
+ assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse();
+ }
+
+ @Test
+ public void onReceive_actionBatteryUnplugging_notFetchUsageData_nearBooting() {
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction())
+ .thenReturn(Intent.ACTION_POWER_DISCONNECTED);
+ // Make sure isCharged returns true.
+ doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_FULL))
+ .when(mContext).registerReceiver(any(), any());
+ // Make sure broadcast will be sent with delay.
+ BatteryUsageBroadcastReceiver.sBroadcastDelayFromBoot =
+ SystemClock.elapsedRealtime() + 5 * DateUtils.MINUTE_IN_MILLIS;
+
+ mBatteryUsageBroadcastReceiver.onReceive(mContext,
+ new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
+
+ assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse();
+ }
+
+ @Test
+ public void onReceive_actionBatteryUnplugging_notFetchUsageData_wrongAction() {
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction())
+ .thenReturn(Intent.ACTION_BATTERY_LEVEL_CHANGED);
+ // Make sure isCharged returns true.
+ doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_UNKNOWN))
+ .when(mContext).registerReceiver(any(), any());
+ BatteryUsageBroadcastReceiver.sBroadcastDelayFromBoot =
+ SystemClock.elapsedRealtime() - 5 * DateUtils.MINUTE_IN_MILLIS;
+
+ mBatteryUsageBroadcastReceiver.onReceive(mContext,
+ new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
+
+ assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse();
+ }
+
+ @Test
+ public void onReceive_actionBatteryUnplugging_fetchUsageData() {
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction())
+ .thenReturn(Intent.ACTION_POWER_DISCONNECTED);
+ // Make sure isCharged returns true.
+ doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_UNKNOWN))
+ .when(mContext).registerReceiver(any(), any());
+ BatteryUsageBroadcastReceiver.sBroadcastDelayFromBoot =
+ SystemClock.elapsedRealtime() - 5 * DateUtils.MINUTE_IN_MILLIS;
+
+ mBatteryUsageBroadcastReceiver.onReceive(mContext,
+ new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
+
+ assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isTrue();
+ }
@Test
public void onReceive_clearCacheIntentInDebugMode_clearBatteryCacheData() {
diff --git a/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java
index 251b1d75c59..ed934733ea5 100644
--- a/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java
@@ -216,12 +216,12 @@ public class MediaVolumePreferenceControllerTest {
final Intent intent = new Intent(action);
intent.setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME);
return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
private PendingIntent getActivityIntent(String action) {
final Intent intent = new Intent(action);
return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
}
diff --git a/tests/robotests/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragmentTest.java b/tests/robotests/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragmentTest.java
new file mode 100644
index 00000000000..ad60d06dc04
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragmentTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2022 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.sim;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import com.android.settings.R;
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowAlertDialogCompat.class)
+public class EnableAutoDataSwitchDialogFragmentTest
+ extends SimDialogFragmentTestBase {
+ private static final String SUMMARY = "fake summary";
+ private static final String WARNING = "fake warning";
+
+ // Mock
+ @Mock
+ private Context mContext;
+ @Mock
+ private SubscriptionManager mSubscriptionManager;
+ @Mock
+ private TelephonyManager mTelephonyManager;
+ @Mock
+ private UserManager mUserManager;
+
+ @Before
+ public void setUp() {
+ super.setUp();
+ mFragment = spy(EnableAutoDataSwitchDialogFragment.newInstance());
+ doReturn(mContext).when(mFragment).getContext();
+
+ doReturn(mSubscriptionManager).when(mContext).getSystemService(SubscriptionManager.class);
+ doReturn(mTelephonyManager).when(mContext).getSystemService(TelephonyManager.class);
+ doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+
+ doReturn(SIM1_ID).when(mFragment).getDefaultDataSubId();
+ doReturn(Arrays.asList(mSim1, mSim2)).when(mSubscriptionManager)
+ .getActiveSubscriptionInfoList();
+ doReturn(true).when(mUserManager)
+ .isManagedProfile(UserHandle.MIN_SECONDARY_USER_ID);
+
+ doReturn(SUMMARY).when(mContext).getString(
+ eq(R.string.enable_auto_data_switch_dialog_message), any());
+ doReturn(WARNING).when(mContext).getString(
+ R.string.auto_data_switch_dialog_managed_profile_warning);
+ }
+
+ @After
+ public void tearDown() {
+ mFragment = null;
+ }
+
+ @Test
+ public void updateDialog_getMessage_noDdsExists() {
+ doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mFragment).getDefaultDataSubId();
+ String msg = mFragment.getMessage();
+ assertThat(msg).isEqualTo(null);
+ }
+
+ @Test
+ public void updateDialog_getMessage_noBackupSubExists() {
+ doReturn(Collections.singletonList(mSim1)).when(mSubscriptionManager)
+ .getActiveSubscriptionInfoList();
+ String msg = mFragment.getMessage();
+ assertThat(msg).isEqualTo(null);
+ }
+
+ @Test
+ public void updateDialog_getMessage_autoSwitchAlreadyEnabled() {
+ doReturn(true).when(mTelephonyManager).isMobileDataPolicyEnabled(
+ TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH);
+ String msg = mFragment.getMessage();
+ assertThat(msg).isEqualTo(null);
+ }
+
+ @Test
+ public void updateDialog_getMessage_noManagedProfile() {
+ UserHandle userHandle = UserHandle.of(UserHandle.USER_NULL);
+ UserHandle userHandle2 = UserHandle.of(UserHandle.USER_SYSTEM);
+ doReturn(userHandle).when(mSubscriptionManager).getSubscriptionUserHandle(SIM1_ID);
+ doReturn(userHandle2).when(mSubscriptionManager).getSubscriptionUserHandle(SIM2_ID);
+ String msg = mFragment.getMessage();
+ assertThat(msg).contains(SUMMARY);
+ assertThat(msg).doesNotContain(WARNING);
+ }
+
+ @Test
+ public void updateDialog_getMessage_hasManagedProfile() {
+ UserHandle userHandle = UserHandle.of(UserHandle.USER_NULL);
+ UserHandle userHandle2 = UserHandle.of(UserHandle.MIN_SECONDARY_USER_ID);
+ doReturn(userHandle).when(mSubscriptionManager).getSubscriptionUserHandle(SIM1_ID);
+ doReturn(userHandle2).when(mSubscriptionManager).getSubscriptionUserHandle(SIM2_ID);
+ String msg = mFragment.getMessage();
+ assertThat(msg).contains(SUMMARY);
+ assertThat(msg).contains(WARNING);
+ }
+
+ @Test
+ public void updateDialog_getMessage_BothManagedProfile() {
+ UserHandle userHandle = UserHandle.of(UserHandle.MIN_SECONDARY_USER_ID);
+ UserHandle userHandle2 = UserHandle.of(UserHandle.MIN_SECONDARY_USER_ID);
+ doReturn(userHandle).when(mSubscriptionManager).getSubscriptionUserHandle(SIM1_ID);
+ doReturn(userHandle2).when(mSubscriptionManager).getSubscriptionUserHandle(SIM2_ID);
+ String msg = mFragment.getMessage();
+ assertThat(msg).contains(SUMMARY);
+ assertThat(msg).doesNotContain(WARNING);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
index 62846c1c87d..42c1e9f98b4 100644
--- a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
@@ -699,6 +699,16 @@ public class UserDetailsSettingsTest {
verify(mFragment).removePreference(KEY_GRANT_ADMIN);
}
+ @Test
+ public void initialize_restrictUserSelected_shouldNotShowGrantAdminPref_MultipleAdminEnabled() {
+ setupSelectedUser();
+ ShadowUserManager.setIsMultipleAdminEnabled(true);
+ mUserManager.setUserRestriction(mUserInfo.getUserHandle(),
+ UserManager.DISALLOW_GRANT_ADMIN, true);
+ mFragment.initialize(mActivity, mArguments);
+ verify(mFragment).removePreference(KEY_GRANT_ADMIN);
+ }
+
@Test
public void initialize_mainUserSelected_shouldShowGrantAdminPref_MultipleAdminEnabled() {
setupSelectedMainUser();
diff --git a/tests/unit/src/com/android/settings/localepicker/LocaleHelperPreferenceControllerTest.java b/tests/unit/src/com/android/settings/localepicker/LocaleHelperPreferenceControllerTest.java
new file mode 100644
index 00000000000..31b8e794480
--- /dev/null
+++ b/tests/unit/src/com/android/settings/localepicker/LocaleHelperPreferenceControllerTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 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.localepicker;
+
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settingslib.widget.FooterPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class LocaleHelperPreferenceControllerTest {
+ private Context mContext;
+ private LocaleHelperPreferenceController mLocaleHelperPreferenceController;
+
+ @Mock
+ private FooterPreference mMockFooterPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mContext = ApplicationProvider.getApplicationContext();
+ mLocaleHelperPreferenceController = new LocaleHelperPreferenceController(mContext);
+ }
+
+ @Test
+ public void updateFooterPreference_setFooterPreference_hasClickAction() {
+ mLocaleHelperPreferenceController.updateFooterPreference(mMockFooterPreference);
+ verify(mMockFooterPreference).setLearnMoreText(anyString());
+ }
+}