Snap for 9505375 from 5054d8d405 to udc-release

Change-Id: Id3789d4fe4e7a0b07f62b7106762e08518da8682
This commit is contained in:
Android Build Coastguard Worker
2023-01-19 04:27:17 +00:00
37 changed files with 915 additions and 85 deletions

View File

@@ -3051,11 +3051,12 @@
android:exported="false"
android:authorities="${applicationId}.battery.usage.bugreport"/>
<receiver android:name=".fuelgauge.batteryusage.BatteryUsageBroadcastReceiver"
<receiver android:name="com.android.settings.fuelgauge.batteryusage.BatteryUsageBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BATTERY_LEVEL_CHANGED"/>
<action android:name="com.android.settings.battery.action.CLEAR_BATTERY_CACHE_DATA"/>
<action android:name="com.android.settings.battery.action.ACTION_BATTERY_UNPLUGGING"/>
</intent-filter>
</receiver>

View File

@@ -0,0 +1,25 @@
<!--
Copyright (C) 2023 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:pathData="M9,46q-1.25,0 -2.125,-0.875T6,43L6,5q0,-1.25 0.875,-2.125T9,2h30q1.25,0 2.125,0.875T42,5v38q0,1.25 -0.875,2.125T39,46ZM9,38.5L9,43h30v-4.5ZM19.9,41.75h8.2v-2h-8.2ZM9,35.5h30v-26L9,9.5ZM9,6.5h30L39,5L9,5ZM9,6.5L9,5v1.5ZM9,38.5L9,43Z"
android:fillType="evenOdd"
android:fillColor="?android:attr/colorPrimary"/>
</vector>

View File

@@ -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" />
</layer-list>

View File

@@ -56,6 +56,17 @@
android:layout_toStartOf="@+id/dragHandle"
android:layout_below="@id/label"/>
<TextView
android:id="@+id/default_locale"
style="@style/LanguageCheckboxAndLabel"
android:layout_marginTop="-28dp"
android:paddingStart="56dp"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:textColorSecondary"
android:text="@string/desc_current_default_language"
android:layout_toStartOf="@+id/dragHandle"
android:layout_below="@id/label"/>
<ImageView
android:id="@+id/dragHandle"
android:layout_width="wrap_content"

View File

@@ -29,7 +29,8 @@
android:gravity="center_vertical"
android:orientation="vertical"
android:clipToPadding="false"
android:clipChildren="false">
android:clipChildren="false"
android:layout_marginTop="@dimen/sfps_enroll_find_sensor_lottie_margin">
<!-- Animation res MUST be set in code because asset is dependent on device orientation -->
<com.airbnb.lottie.LottieAnimationView

View File

@@ -88,7 +88,7 @@
<string-array name="wifi_signal">
<item msgid="199360311367724149">"나쁨"</item>
<item msgid="2470925506985305429">"매우 약함"</item>
<item msgid="8545211062334016668">"양호"</item>
<item msgid="8545211062334016668">"약함"</item>
<item msgid="7468449584777730187">"좋음"</item>
<item msgid="202124107702016530">"우수함"</item>
</string-array>

View File

@@ -407,4 +407,7 @@
<dimen name="limited_vision_button_margin_top">0dp</dimen>
<dimen name="limited_vision_button_margin_bottom">0dp</dimen>
<dimen name="limited_vision_button_toggle_margin_top">0dp</dimen>
<!-- Default margin for side fps enroll find sensor lottie -->
<dimen name="sfps_enroll_find_sensor_lottie_margin">0dp</dimen>
</resources>

View File

@@ -312,6 +312,12 @@
<!-- Title for the locale picker activity. [CHAR LIMIT=30]-->
<string name="language_picker_title">Languages</string>
<!-- Title for category of the locale picker . [CHAR LIMIT=50]-->
<string name="language_picker_category_title">Preferred language order</string>
<!-- Description for indication of current system default language. [CHAR LIMIT=50]-->
<string name="desc_current_default_language">System language</string>
<!-- Menu item in the locale menu. Will remove the selected locales. [CHAR LIMIT=30] -->
<string name="locale_remove_menu">Remove</string>
@@ -325,13 +331,13 @@
<string name="locale_picker_category_title">Preferred Language</string>
<!-- Title for the Apps' locale menu entry [CHAR LIMIT=50]-->
<string name="app_locales_picker_menu_title">App Languages</string>
<string name="app_locales_picker_menu_title">App languages</string>
<!-- Summary for the app's locale picker activity. [CHAR LIMIT=50]-->
<string name="app_locale_picker_summary">Set the language for each app</string>
<!-- Title for the App's locale picker activity. [CHAR LIMIT=50]-->
<string name="app_locale_picker_title">App Language</string>
<string name="app_locale_picker_title">App language</string>
<!-- Category for the suggested app's locales. [CHAR LIMIT=50]-->
<string name="suggested_app_locales_title">Suggested languages</string>
@@ -354,6 +360,18 @@
<!-- Description for introduction of the locale selection supported of app list [CHAR LIMIT=NONE]-->
<string name="desc_app_locale_selection_supported">Only apps that support language selection are shown here.</string>
<!-- Description for the introduction to language picker activity. [CHAR LIMIT=NONE]-->
<string name="desc_introduction_of_language_picker">Your system, apps, and websites use the first supported language from your preferred languages.</string>
<!-- Description for the notice of language picker. [CHAR LIMIT=NONE]-->
<string name="desc_notice_of_language_picker">To select a language for each app, go to app language settings.</string>
<!-- Title for locale helper page [CHAR LIMIT=NONE] -->
<string name="desc_locale_helper_footer_general">Learn more about languages</string>
<!-- Link for Locale helper page. [CHAR LIMIT=NONE]-->
<string name="link_locale_picker_footer_learn_more" translatable="false">https://support.google.com/android?p=per_language_app_settings</string>
<!-- Regional Preferences begin -->
<!-- The title of the menu entry of regional preferences. [CHAR LIMIT=50] -->
<string name="regional_preferences_title">Regional preferences</string>
@@ -407,7 +425,7 @@
<string name="dlg_remove_locales_error_message">Keep at least one preferred language</string>
<!-- This text shows in the language picker when the system is not translated into that languages [CHAR LIMIT=80] -->
<string name="locale_not_translated">May not be available in some apps</string>
<string name="locale_not_translated">Not available as system language</string>
<!-- Label for an accessibility action that moves a language up in the ordered language list [CHAR LIMIT=20] -->
<string name="action_drag_label_move_up">Move up</string>
@@ -808,6 +826,12 @@
<string name="security_settings_udfps_enroll_find_sensor_title">How to set up your fingerprint</string>
<!-- Message shown in fingerprint enrollment dialog to locate the sensor -->
<string name="security_settings_fingerprint_enroll_find_sensor_message">It\u2019s on the back of your phone. Use your index finger.</string>
<!-- Message shown in SFPS enrollment dialog to locate the sensor (tablet) [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="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 tablet.</string>
<!-- Message shown in SFPS enrollment dialog to locate the sensor (device) [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="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 device.</string>
<!-- Message shown in SFPS enrollment dialog to locate the sensor (default) [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="default">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.</string>
<!-- Message shown in UDFPS enrollment dialog to locate the sensor [CHAR LIMIT=NONE]-->
<string name="security_settings_udfps_enroll_find_sensor_message">The fingerprint sensor is on your screen. You\u2019ll capture your fingerprint on the next screen.</string>
<!-- Button for starting fingerprint enrollment. [CHAR LIMIT=10]-->
@@ -2398,6 +2422,13 @@
<!-- Message for the dialog asking to user to change the preferred SIM [CHAR LIMIT=NONE] -->
<string name="sim_preferred_message"><xliff:g id="new_sim">%1$s</xliff:g> is the only SIM in your device. Do you want to use this SIM for mobile data, calls, and SMS messages?</string>
<!-- Title for the dialog asking to user to enable auto data switch upon enabling multi-SIM [CHAR LIMIT=30] -->
<string name="enable_auto_data_switch_dialog_title">Switch SIMs automatically?</string>
<!-- Message for the dialog asking to user to change the preferred SIM [CHAR LIMIT=NONE] -->
<string name="enable_auto_data_switch_dialog_message">Allow your phone to automatically switch to <xliff:g id="backup_carrier" example="T-mobile">%1$s</xliff:g> for mobile data when it has better availability.</string>
<!-- Message for the dialog asking to user to change the preferred SIM [CHAR LIMIT=NONE] -->
<string name="auto_data_switch_dialog_managed_profile_warning">\n\nCalls, messages, and network traffic may be visible to your organization.</string>
<!-- Instructions telling the user that they entered the wrong SIM PIN for the last time.
Displayed in a dialog box. [CHAR LIMIT=100] -->
<string name="wrong_pin_code_pukked">Incorrect SIM PIN code you must now contact your carrier to unlock your device.</string>

View File

@@ -748,6 +748,7 @@
<SwitchPreference
android:key="stylus_handwriting"
android:title="@string/stylus_handwriting"
android:defaultValue="true"
android:summary="@string/stylus_handwriting_summary" />
</PreferenceCategory>
</PreferenceScreen>

42
res/xml/languages.xml Normal file
View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/language_settings">
<com.android.settingslib.widget.TopIntroPreference
android:title="@string/desc_introduction_of_language_picker"
android:persistent="false"
android:selectable="false"/>
<PreferenceCategory
android:title="@string/language_picker_category_title">
<com.android.settingslib.widget.LayoutPreference
android:key="languages_picker"
android:layout="@layout/locale_order_list" />
</PreferenceCategory>
<com.android.settingslib.widget.FooterPreference
android:key="footer_languages_picker"
android:title="@string/desc_notice_of_language_picker"
android:persistent="false"
android:selectable="false"
settings:controller="com.android.settings.localepicker.LocaleHelperPreferenceController"/>
</PreferenceScreen>

View File

@@ -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"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="airplane_mode"

View File

@@ -196,7 +196,7 @@
<com.android.settings.widget.HomepagePreference
android:fragment="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment"
android:icon="@drawable/ic_phone_info"
android:icon="@drawable/ic_settings_about_device"
android:key="top_level_about_device"
android:order="20"
android:title="@string/about_settings"

View File

@@ -58,7 +58,7 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceController
getUserHandle());
if (toReturn == -1) {
toReturn = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_requireScreenOnToAuthEnabled) ? 1 : 0;
com.android.internal.R.bool.config_performantAuthDefault) ? 1 : 0;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED, toReturn, getUserHandle());
}

View File

@@ -78,7 +78,7 @@ public class BugReportHandlerUtil {
boolean needToResetOutdatedSettings = false;
if (!isBugreportAllowlistedApp(handlerApp)) {
handlerApp = getDefaultBugReportHandlerApp(context);
handlerUser = UserHandle.USER_SYSTEM;
handlerUser = context.getUserId();
} else if (getBugReportHandlerAppReceivers(context, handlerApp, handlerUser).isEmpty()) {
// It looks like the settings are outdated, need to reset outdated settings.
//
@@ -89,7 +89,7 @@ public class BugReportHandlerUtil {
// The chosen bugreport handler app is outdated because the profile is removed,
// so need to reset outdated settings
handlerApp = getDefaultBugReportHandlerApp(context);
handlerUser = UserHandle.USER_SYSTEM;
handlerUser = context.getUserId();
needToResetOutdatedSettings = true;
}
@@ -99,7 +99,7 @@ public class BugReportHandlerUtil {
// bugreport, so change to let shell to handle a bugreport and need to reset
// settings.
handlerApp = SHELL_APP_PACKAGE;
handlerUser = UserHandle.USER_SYSTEM;
handlerUser = context.getUserId();
needToResetOutdatedSettings = true;
}
@@ -112,13 +112,13 @@ public class BugReportHandlerUtil {
private String getCustomBugReportHandlerApp(Context context) {
// Get the package of custom bugreport handler app
return Settings.Global.getString(context.getContentResolver(),
Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP);
return Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.CUSTOM_BUGREPORT_HANDLER_APP);
}
private int getCustomBugReportHandlerUser(Context context) {
return Settings.Global.getInt(context.getContentResolver(),
Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER, UserHandle.USER_NULL);
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.CUSTOM_BUGREPORT_HANDLER_USER, UserHandle.USER_NULL);
}
private String getDefaultBugReportHandlerApp(Context context) {
@@ -164,22 +164,24 @@ public class BugReportHandlerUtil {
return validBugReportHandlerApplicationInfos;
}
// Add "Shell with system user" as System default preference on top of screen
int currentUser = UserHandle.getCallingUserId();
// Add "Shell" as user's default preference on top of screen
if (bugreportAllowlistedPackages.contains(SHELL_APP_PACKAGE)
&& !getBugReportHandlerAppReceivers(context, SHELL_APP_PACKAGE,
UserHandle.USER_SYSTEM).isEmpty()) {
currentUser).isEmpty()) {
try {
validBugReportHandlerApplicationInfos.add(
Pair.create(
context.getPackageManager().getApplicationInfo(SHELL_APP_PACKAGE,
PackageManager.MATCH_ANY_USER), UserHandle.USER_SYSTEM)
PackageManager.MATCH_ANY_USER), currentUser)
);
} catch (PackageManager.NameNotFoundException e) {
}
}
final UserManager userManager = context.getSystemService(UserManager.class);
final List<UserInfo> profileList = userManager.getProfiles(UserHandle.getCallingUserId());
final List<UserInfo> profileList = userManager.getProfiles(currentUser);
// Only add non-Shell app as normal preference
final List<String> 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);
}
/**

View File

@@ -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);
}
}

View File

@@ -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
*/

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -43,7 +43,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
class LocaleDragAndDropAdapter
extends RecyclerView.Adapter<LocaleDragAndDropAdapter.CustomViewHolder> {
@@ -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);

View File

@@ -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;
}

View File

@@ -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=*/""));
}
}

View File

@@ -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<LocaleStore.LocaleInfo> 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) {

View File

@@ -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<SubscriptionInfo> 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);
}
}

View File

@@ -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());
}
}
}

View File

@@ -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<Fragment> 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();
}
}

View File

@@ -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<SubscriptionInfo> getCurrentSubscriptions() {

View File

@@ -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<TogglePermissionAppListProvider> {
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,

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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() {

View File

@@ -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);
}
}

View File

@@ -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<EnableAutoDataSwitchDialogFragment> {
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);
}
}

View File

@@ -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();

View File

@@ -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());
}
}