Snap for 9705326 from 9e2e47c553 to udc-release

Change-Id: I2ee82479c6dd09d36711aacdc38261b28766bb4c
This commit is contained in:
Android Build Coastguard Worker
2023-03-08 04:27:56 +00:00
34 changed files with 1477 additions and 166 deletions

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/admin_details_dialog_padding"
android:paddingStart="@dimen/admin_details_dialog_padding"
android:paddingEnd="@dimen/admin_details_dialog_padding"
android:paddingBottom="@dimen/admin_details_dialog_padding_bottom"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:paddingBottom="@dimen/admin_details_dialog_title_bottom_padding">
<ImageView
android:layout_width="@dimen/admin_details_dialog_icon_size"
android:layout_height="@dimen/admin_details_dialog_icon_size"
android:scaleType="fitCenter"
android:src="@drawable/ic_settings_language"
android:tint="#4F8438"
android:contentDescription="@null"/>
<TextView
android:id="@+id/dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.AdminDialogTitle"/>
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fadeScrollbars="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/dialog_msg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="200"
android:gravity="left"
android:autoLink="email|phone|web"
android:textColor="?android:attr/textColorSecondary"/>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@@ -228,6 +228,11 @@
<!-- Summary of checkbox for enabling Bluetooth LE audio [CHAR LIMIT=none]-->
<string name="bluetooth_enable_leaudio_summary">Enables Bluetooth LE audio feature if the device supports LE audio hardware capabilities.</string>
<!-- Setting Checkbox title for enabling Bluetooth LE Audio Allow List. [CHAR LIMIT=none] -->
<string name="bluetooth_enable_leaudio_allow_list">Enable Bluetooth LE audio Allow List</string>
<!-- Summary of checkbox for enabling Bluetooth LE audio Allow List [CHAR LIMIT=none]-->
<string name="bluetooth_enable_leaudio_allow_list_summary">Enable Bluetooth LE audio allow list feature.</string>
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
<string name="connected_device_media_device_title">Media devices</string>
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
@@ -372,6 +377,21 @@
<!-- 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>
<!-- Title for asking to change system locale or not. [CHAR LIMIT=50]-->
<string name="title_change_system_locale">Change system language to %s ?</string>
<!-- The text of the confirmation dialog showing the system locale will be changed. [CHAR LIMIT=NONE]-->
<string name="desc_notice_device_locale_settings_change">Your device settings and regional preferences will change.</string>
<!-- A dialog button for confirmmation of system locale change. [CHAR LIMIT=25]-->
<string name="button_label_confirmation_of_system_locale_change">Change</string>
<!-- Title for saying this selected locale is unavailable to use. [CHAR LIMIT=50]-->
<string name="title_unavailable_locale">%s not available</string>
<!-- The text of the confirmation dialog for saying this selected locale is unavailable to use. [CHAR LIMIT=NONE]-->
<string name="desc_unavailable_locale">This language cant be used as a system language, but youve let apps and websites know you prefer this language.</string>
<!-- Regional Preferences begin -->
<!-- The title of the menu entry of regional preferences. [CHAR LIMIT=50] -->
<string name="regional_preferences_title">Regional preferences</string>

View File

@@ -345,6 +345,11 @@
android:title="@string/bluetooth_enable_leaudio"
android:summary="@string/bluetooth_enable_leaudio_summary" />
<SwitchPreference
android:key="bluetooth_enable_leaudio_allow_list"
android:title="@string/bluetooth_enable_leaudio_allow_list"
android:summary="@string/bluetooth_enable_leaudio_allow_list_summary" />
<SwitchPreference
android:key="bluetooth_disable_le_audio_hw_offload"
android:title="@string/bluetooth_disable_le_audio_hw_offload" />

View File

@@ -18,7 +18,6 @@ package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import android.content.Context;
import android.provider.Settings;
@@ -45,13 +44,13 @@ public class CameraFlashNotificationPreferenceController extends TogglePreferenc
@Override
public boolean isChecked() {
return Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_CAMERA_FLASH_NOTIFICATION, OFF) != OFF;
Settings.System.CAMERA_FLASH_NOTIFICATION, OFF) != OFF;
}
@Override
public boolean setChecked(boolean isChecked) {
return Settings.System.putInt(mContext.getContentResolver(),
SETTING_KEY_CAMERA_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
Settings.System.CAMERA_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
}
@Override

View File

@@ -19,8 +19,6 @@ package com.android.settings.accessibility;
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_SHORT_PREVIEW;
import android.content.ContentResolver;
@@ -95,10 +93,10 @@ public class FlashNotificationsPreviewPreferenceController extends
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_RESUME) {
mContentResolver.registerContentObserver(
Settings.System.getUriFor(SETTING_KEY_CAMERA_FLASH_NOTIFICATION),
Settings.System.getUriFor(Settings.System.CAMERA_FLASH_NOTIFICATION),
/* notifyForDescendants= */ false, mContentObserver);
mContentResolver.registerContentObserver(
Settings.System.getUriFor(SETTING_KEY_SCREEN_FLASH_NOTIFICATION),
Settings.System.getUriFor(Settings.System.SCREEN_FLASH_NOTIFICATION),
/* notifyForDescendants= */ false, mContentObserver);
} else if (event == Lifecycle.Event.ON_PAUSE) {
mContentResolver.unregisterContentObserver(mContentObserver);

View File

@@ -16,8 +16,6 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
@@ -43,19 +41,10 @@ class FlashNotificationsUtil {
static final String EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE =
"com.android.internal.intent.extra.FLASH_NOTIFICATION_PREVIEW_TYPE";
static final String SETTING_KEY_CAMERA_FLASH_NOTIFICATION =
"camera_flash_notification";
static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION =
"screen_flash_notification";
static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR =
"screen_flash_notification_color_global";
static final int TYPE_SHORT_PREVIEW = 0;
static final int TYPE_LONG_PREVIEW = 1;
static final int DEFAULT_SCREEN_FLASH_COLOR =
ScreenFlashNotificationColor.YELLOW.mColorInt;
static final int DEFAULT_SCREEN_FLASH_COLOR = ScreenFlashNotificationColor.YELLOW.mColorInt;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@@ -128,9 +117,9 @@ class FlashNotificationsUtil {
final boolean isTorchAvailable = FlashNotificationsUtil.isTorchAvailable(context);
final boolean isCameraFlashEnabled = Settings.System.getInt(context.getContentResolver(),
SETTING_KEY_CAMERA_FLASH_NOTIFICATION, State.OFF) != State.OFF;
Settings.System.CAMERA_FLASH_NOTIFICATION, State.OFF) != State.OFF;
final boolean isScreenFlashEnabled = Settings.System.getInt(context.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION, State.OFF) != State.OFF;
Settings.System.SCREEN_FLASH_NOTIFICATION, State.OFF) != State.OFF;
return ((isTorchAvailable && isCameraFlashEnabled) ? State.CAMERA : State.OFF)
| (isScreenFlashEnabled ? State.SCREEN : State.OFF);

View File

@@ -19,8 +19,6 @@ package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.FlashNotificationsUtil.DEFAULT_SCREEN_FLASH_COLOR;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR;
import android.content.Context;
import android.graphics.Color;
@@ -59,7 +57,7 @@ public class ScreenFlashNotificationPreferenceController extends TogglePreferenc
@Override
public boolean isChecked() {
return Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION, OFF) != OFF;
Settings.System.SCREEN_FLASH_NOTIFICATION, OFF) != OFF;
}
@Override
@@ -67,7 +65,7 @@ public class ScreenFlashNotificationPreferenceController extends TogglePreferenc
if (isChecked) checkAndSetInitialColor();
return Settings.System.putInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
Settings.System.SCREEN_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
}
@Override
@@ -79,7 +77,8 @@ public class ScreenFlashNotificationPreferenceController extends TogglePreferenc
public CharSequence getSummary() {
return FlashNotificationsUtil.getColorDescriptionText(mContext,
Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR));
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
DEFAULT_SCREEN_FLASH_COLOR));
}
@Override
@@ -94,12 +93,12 @@ public class ScreenFlashNotificationPreferenceController extends TogglePreferenc
if (getPreferenceKey().equals(preference.getKey()) && mParentFragment != null) {
final int initialColor = Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR,
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
DEFAULT_SCREEN_FLASH_COLOR);
final Consumer<Integer> consumer = color -> {
Settings.System.putInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, color);
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, color);
refreshColorSummary();
};
@@ -115,10 +114,10 @@ public class ScreenFlashNotificationPreferenceController extends TogglePreferenc
private void checkAndSetInitialColor() {
if (Settings.System.getInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT)
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT)
== Color.TRANSPARENT) {
Settings.System.putInt(mContext.getContentResolver(),
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR);
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR);
}
}

View File

@@ -25,14 +25,11 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager;
import android.credentials.ListEnabledProvidersException;
import android.credentials.ListEnabledProvidersResponse;
import android.credentials.CredentialProviderInfo;
import android.credentials.SetEnabledProvidersException;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.OutcomeReceiver;
import android.os.UserHandle;
import android.util.IconDrawableFactory;
@@ -71,10 +68,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
private final PackageManager mPm;
private final IconDrawableFactory mIconFactory;
private final List<ServiceInfo> mServices;
private final List<CredentialProviderInfo> mServices;
private final Set<String> mEnabledPackageNames;
private final @Nullable CredentialManager mCredentialManager;
private final CancellationSignal mCancellationSignal = new CancellationSignal();
private final Executor mExecutor;
private final Map<String, SwitchPreference> mPrefs = new HashMap<>(); // key is package name
@@ -132,42 +128,20 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
lifecycleOwner,
mCredentialManager.getCredentialProviderServices(
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
mCredentialManager.listEnabledProviders(
mCancellationSignal,
mExecutor,
new OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>() {
@Override
public void onResult(ListEnabledProvidersResponse result) {
Set<String> enabledPackages = new HashSet<>();
for (String flattenedComponentName : result.getProviderComponentNames()) {
ComponentName cn =
ComponentName.unflattenFromString(flattenedComponentName);
if (cn != null) {
enabledPackages.add(cn.getPackageName());
}
}
setEnabledPackageNames(enabledPackages);
}
@Override
public void onError(ListEnabledProvidersException e) {
Log.e(TAG, "listEnabledProviders error: " + e.toString());
}
});
}
@VisibleForTesting
void setAvailableServices(LifecycleOwner lifecycleOwner, List<ServiceInfo> availableServices) {
void setAvailableServices(
LifecycleOwner lifecycleOwner, List<CredentialProviderInfo> availableServices) {
mServices.clear();
mServices.addAll(availableServices);
}
@VisibleForTesting
void setEnabledPackageNames(Set<String> enabledPackages) {
mEnabledPackageNames.clear();
mEnabledPackageNames.addAll(enabledPackages);
for (CredentialProviderInfo cpi : availableServices) {
if (cpi.isEnabled()) {
mEnabledPackageNames.add(cpi.getServiceInfo().packageName);
}
}
for (String packageName : mPrefs.keySet()) {
mPrefs.get(packageName).setChecked(mEnabledPackageNames.contains(packageName));
@@ -189,22 +163,22 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
PreferenceGroup group = screen.findPreference(getPreferenceKey());
Context context = screen.getContext();
for (ServiceInfo serviceInfo : mServices) {
CharSequence title = "";
if (serviceInfo.nonLocalizedLabel != null) {
title = serviceInfo.loadLabel(mPm);
}
group.addPreference(
addProviderPreference(
context,
title,
mIconFactory.getBadgedIcon(
serviceInfo, serviceInfo.applicationInfo, getUser()),
serviceInfo.packageName));
for (CredentialProviderInfo service : mServices) {
group.addPreference(createPreference(context, service));
}
}
/** Creates a preference object based on the provider info. */
@VisibleForTesting
public SwitchPreference createPreference(Context context, CredentialProviderInfo service) {
CharSequence label = service.getLabel(context);
return addProviderPreference(
context,
label == null ? "" : label,
service.getServiceIcon(mContext),
service.getServiceInfo().packageName);
}
/**
* Enables the package name as an enabled credential manager provider.
*
@@ -246,9 +220,10 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
public List<String> getEnabledSettings() {
// Get all the component names that match the enabled package names.
List<String> enabledServices = new ArrayList<>();
for (ServiceInfo service : mServices) {
if (mEnabledPackageNames.contains(service.packageName)) {
enabledServices.add(service.getComponentName().flattenToString());
for (CredentialProviderInfo service : mServices) {
ComponentName cn = service.getServiceInfo().getComponentName();
if (mEnabledPackageNames.contains(service.getServiceInfo().packageName)) {
enabledServices.add(cn.flattenToString());
}
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright 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.development;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.os.SystemProperties;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
/**
* Preference controller to control Bluetooth LE audio feature
*/
public class BluetoothLeAudioAllowListPreferenceController
extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
private static final String PREFERENCE_KEY = "bluetooth_enable_leaudio_allow_list";
private static final String LE_AUDIO_ALLOW_LIST_SWITCH_SUPPORT_PROPERTY =
"ro.bluetooth.leaudio_allow_list.supported";
@VisibleForTesting
static final String LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY =
"persist.bluetooth.leaudio.enable_allow_list";
private static final String LE_AUDIO_DYNAMIC_SWITCH_PROPERTY =
"ro.bluetooth.leaudio_switcher.supported";
@VisibleForTesting
static final String LE_AUDIO_DYNAMIC_ENABLED_PROPERTY =
"persist.bluetooth.leaudio_switcher.enabled";
@VisibleForTesting
BluetoothAdapter mBluetoothAdapter;
private final DevelopmentSettingsDashboardFragment mFragment;
@VisibleForTesting
boolean mChanged = false;
public BluetoothLeAudioAllowListPreferenceController(Context context,
DevelopmentSettingsDashboardFragment fragment) {
super(context);
mFragment = fragment;
mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
}
@Override
public String getPreferenceKey() {
return PREFERENCE_KEY;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
BluetoothRebootDialog.show(mFragment);
mChanged = true;
return false;
}
@Override
public void updateState(Preference preference) {
if (mBluetoothAdapter == null) {
return;
}
int leAudioSupportedState = mBluetoothAdapter.isLeAudioSupported();
boolean leAudioEnabled = false;
if ((leAudioSupportedState == BluetoothStatusCodes.FEATURE_SUPPORTED)
|| (leAudioSupportedState == BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED
&& SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_SWITCH_PROPERTY, false)
&& SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY, false))) {
leAudioEnabled = true;
}
final boolean leAudioAllowListSupport =
SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_SWITCH_SUPPORT_PROPERTY, false);
if (leAudioEnabled && leAudioAllowListSupport) {
final boolean leAudioAllowListEnabled =
SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
((SwitchPreference) mPreference).setChecked(leAudioAllowListEnabled);
} else {
mPreference.setEnabled(false);
((SwitchPreference) mPreference).setChecked(false);
}
}
/**
* Called when the RebootDialog confirm is clicked.
*/
public void onRebootDialogConfirmed() {
if (!mChanged) {
return;
}
final boolean leAudioAllowListEnabled =
SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY,
Boolean.toString(!leAudioAllowListEnabled));
}
/**
* Called when the RebootDialog cancel is clicked.
*/
public void onRebootDialogCanceled() {
mChanged = false;
}
}

View File

@@ -389,6 +389,11 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
getDevelopmentOptionsController(
BluetoothLeAudioPreferenceController.class);
leAudioFeatureController.onRebootDialogConfirmed();
final BluetoothLeAudioAllowListPreferenceController leAudioAllowListController =
getDevelopmentOptionsController(
BluetoothLeAudioAllowListPreferenceController.class);
leAudioAllowListController.onRebootDialogConfirmed();
}
@Override
@@ -406,6 +411,11 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
getDevelopmentOptionsController(
BluetoothLeAudioPreferenceController.class);
leAudioFeatureController.onRebootDialogCanceled();
final BluetoothLeAudioAllowListPreferenceController leAudioAllowListController =
getDevelopmentOptionsController(
BluetoothLeAudioAllowListPreferenceController.class);
leAudioAllowListController.onRebootDialogCanceled();
}
@Override
@@ -602,6 +612,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new BluetoothAvrcpVersionPreferenceController(context));
controllers.add(new BluetoothMapVersionPreferenceController(context));
controllers.add(new BluetoothLeAudioPreferenceController(context, fragment));
controllers.add(new BluetoothLeAudioAllowListPreferenceController(context, fragment));
controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment));
controllers.add(new BluetoothLeAudioHwOffloadPreferenceController(context, fragment));
controllers.add(new BluetoothMaxConnectedAudioDevicesPreferenceController(context));

View File

@@ -118,7 +118,7 @@ public class BatterySaverButtonPreferenceController extends
@Override
public boolean setChecked(boolean stateOn) {
return BatterySaverUtils.setPowerSaveMode(mContext, stateOn,
true /* needFirstTimeWarning */);
false /* needFirstTimeWarning */);
}
@Override

View File

@@ -0,0 +1,198 @@
/*
* 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.
*/
package com.android.settings.localepicker;
import android.app.Activity;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentManager;
import com.android.internal.app.LocaleStore;
import com.android.settings.R;
import com.android.settings.RestrictedSettingsFragment;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
/**
* Create a dialog for system locale events.
*/
public class LocaleDialogFragment extends InstrumentedDialogFragment {
private static final String TAG = LocaleDialogFragment.class.getSimpleName();
static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 0;
static final int DIALOG_NOT_AVAILABLE_LOCALE = 1;
static final String ARG_DIALOG_TYPE = "arg_dialog_type";
static final String ARG_TARGET_LOCALE = "arg_target_locale";
static final String ARG_RESULT_RECEIVER = "arg_result_receiver";
/**
* Show dialog
*/
public static void show(
@NonNull RestrictedSettingsFragment fragment,
int dialogType,
LocaleStore.LocaleInfo localeInfo) {
show(fragment, dialogType, localeInfo, null);
}
/**
* Show dialog
*/
public static void show(
@NonNull RestrictedSettingsFragment fragment,
int dialogType,
LocaleStore.LocaleInfo localeInfo,
ResultReceiver resultReceiver) {
FragmentManager manager = fragment.getChildFragmentManager();
Bundle args = new Bundle();
args.putInt(ARG_DIALOG_TYPE, dialogType);
args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
args.putParcelable(ARG_RESULT_RECEIVER, resultReceiver);
LocaleDialogFragment localeDialogFragment = new LocaleDialogFragment();
localeDialogFragment.setArguments(args);
localeDialogFragment.show(manager, TAG);
}
@Override
public int getMetricsCategory() {
int dialogType = getArguments().getInt(ARG_DIALOG_TYPE);
switch (dialogType) {
case DIALOG_CONFIRM_SYSTEM_DEFAULT:
return SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE;
case DIALOG_NOT_AVAILABLE_LOCALE:
return SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE;
default:
return SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE;
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LocaleDialogController controller = new LocaleDialogController(this);
LocaleDialogController.DialogContent dialogContent = controller.getDialogContent();
ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(getContext()).inflate(
R.layout.locale_dialog, null);
setDialogTitle(viewGroup, dialogContent.mTitle);
setDialogMessage(viewGroup, dialogContent.mMessage);
AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
.setView(viewGroup);
if (!dialogContent.mPositiveButton.isEmpty()) {
builder.setPositiveButton(dialogContent.mPositiveButton, controller);
}
if (!dialogContent.mNegativeButton.isEmpty()) {
builder.setNegativeButton(dialogContent.mNegativeButton, controller);
}
return builder.create();
}
private static void setDialogTitle(View root, String content) {
TextView titleView = root.findViewById(R.id.dialog_title);
if (titleView == null) {
return;
}
titleView.setText(content);
}
private static void setDialogMessage(View root, String content) {
TextView textView = root.findViewById(R.id.dialog_msg);
if (textView == null) {
return;
}
textView.setText(content);
}
static class LocaleDialogController implements DialogInterface.OnClickListener {
private final Context mContext;
private final int mDialogType;
private final LocaleStore.LocaleInfo mLocaleInfo;
private final ResultReceiver mResultReceiver;
LocaleDialogController(
@NonNull Context context, @NonNull LocaleDialogFragment dialogFragment) {
mContext = context;
Bundle arguments = dialogFragment.getArguments();
mDialogType = arguments.getInt(ARG_DIALOG_TYPE);
mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(
ARG_TARGET_LOCALE);
mResultReceiver = (ResultReceiver) arguments.getParcelable(ARG_RESULT_RECEIVER);
}
LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment) {
this(dialogFragment.getContext(), dialogFragment);
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (mResultReceiver != null && mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
Bundle bundle = new Bundle();
bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
if (which == DialogInterface.BUTTON_POSITIVE) {
mResultReceiver.send(Activity.RESULT_OK, bundle);
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
mResultReceiver.send(Activity.RESULT_CANCELED, bundle);
}
}
}
@VisibleForTesting
DialogContent getDialogContent() {
DialogContent
dialogContent = new DialogContent();
switch (mDialogType) {
case DIALOG_CONFIRM_SYSTEM_DEFAULT:
dialogContent.mTitle = String.format(mContext.getString(
R.string.title_change_system_locale), mLocaleInfo.getFullNameNative());
dialogContent.mMessage = mContext.getString(
R.string.desc_notice_device_locale_settings_change);
dialogContent.mPositiveButton = mContext.getString(
R.string.button_label_confirmation_of_system_locale_change);
dialogContent.mNegativeButton = mContext.getString(R.string.cancel);
break;
case DIALOG_NOT_AVAILABLE_LOCALE:
dialogContent.mTitle = String.format(mContext.getString(
R.string.title_unavailable_locale), mLocaleInfo.getFullNameNative());
dialogContent.mMessage = mContext.getString(R.string.desc_unavailable_locale);
dialogContent.mPositiveButton = mContext.getString(R.string.okay);
break;
default:
break;
}
return dialogContent;
}
@VisibleForTesting
static class DialogContent {
String mTitle = "";
String mMessage = "";
String mPositiveButton = "";
String mNegativeButton = "";
}
}
}

View File

@@ -16,10 +16,14 @@
package com.android.settings.localepicker;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Bundle;
import android.os.Handler;
import android.os.LocaleList;
import android.os.Looper;
import android.os.ResultReceiver;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
@@ -49,9 +53,11 @@ class LocaleDragAndDropAdapter
private static final String TAG = "LocaleDragAndDropAdapter";
private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales";
private final Context mContext;
private final List<LocaleStore.LocaleInfo> mFeedItemList;
private List<LocaleStore.LocaleInfo> mFeedItemList;
private List<LocaleStore.LocaleInfo> mCacheItemList;
private final ItemTouchHelper mItemTouchHelper;
private RecyclerView mParentView = null;
private LocaleListEditor mParent;
private boolean mRemoveMode = false;
private boolean mDragEnabled = true;
private NumberFormat mNumberFormatter = NumberFormat.getNumberInstance();
@@ -81,12 +87,15 @@ class LocaleDragAndDropAdapter
}
}
public LocaleDragAndDropAdapter(Context context, List<LocaleStore.LocaleInfo> feedItemList) {
LocaleDragAndDropAdapter(LocaleListEditor parent,
List<LocaleStore.LocaleInfo> feedItemList) {
mFeedItemList = feedItemList;
mContext = context;
mParent = parent;
mCacheItemList = new ArrayList<>(feedItemList);
mContext = parent.getContext();
final float dragElevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
context.getResources().getDisplayMetrics());
mContext.getResources().getDisplayMetrics());
mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0 /* no swipe */) {
@@ -168,13 +177,13 @@ class LocaleDragAndDropAdapter
checkbox.setOnCheckedChangeListener(null);
checkbox.setChecked(mRemoveMode ? feedItem.getChecked() : false);
checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
LocaleStore.LocaleInfo feedItem =
(LocaleStore.LocaleInfo) dragCell.getTag();
feedItem.setChecked(isChecked);
}
});
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
LocaleStore.LocaleInfo feedItem =
(LocaleStore.LocaleInfo) dragCell.getTag();
feedItem.setChecked(isChecked);
}
});
}
@Override
@@ -308,6 +317,42 @@ class LocaleDragAndDropAdapter
});
}
public void doTheUpdateWithMovingLocaleItem() {
LocaleStore.LocaleInfo localeInfo = mFeedItemList.get(0);
if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) {
LocaleDialogFragment.show(mParent,
LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT,
localeInfo,
new ResultReceiver(new Handler(Looper.getMainLooper())) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
int type = resultData.getInt(LocaleDialogFragment.ARG_DIALOG_TYPE);
if (type == LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT) {
if (resultCode == Activity.RESULT_OK) {
doTheUpdate();
if (!localeInfo.isTranslated()) {
LocaleDialogFragment.show(mParent,
LocaleDialogFragment
.DIALOG_NOT_AVAILABLE_LOCALE,
localeInfo);
}
} else {
if (!localeInfo.getLocale()
.equals(mCacheItemList.get(0).getLocale())) {
mFeedItemList = new ArrayList<>(mCacheItemList);
notifyDataSetChanged();
}
}
mCacheItemList = new ArrayList<>(mFeedItemList);
}
}
});
} else {
doTheUpdate();
}
}
private void setDragEnabled(boolean enabled) {
mDragEnabled = enabled;
}
@@ -315,6 +360,7 @@ class LocaleDragAndDropAdapter
/**
* Saves the list of checked locales to preserve status when the list is destroyed.
* (for instance when the device is rotated)
*
* @param outInstanceState Bundle in which to place the saved state
*/
public void saveState(Bundle outInstanceState) {
@@ -332,6 +378,7 @@ class LocaleDragAndDropAdapter
/**
* Restores the list of checked locales to preserve status when the list is recreated.
* (for instance when the device is rotated)
*
* @param savedInstanceState Bundle with the data saved by {@link #saveState(Bundle)}
*/
public void restoreState(Bundle savedInstanceState) {

View File

@@ -105,7 +105,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
LocaleStore.fillCache(this.getContext());
final List<LocaleStore.LocaleInfo> feedsList = getUserLocaleList();
mAdapter = new LocaleDragAndDropAdapter(this.getContext(), feedsList);
mAdapter = new LocaleDragAndDropAdapter(this, feedsList);
}
@Override

View File

@@ -40,7 +40,7 @@ class LocaleRecyclerView extends RecyclerView {
if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) {
LocaleDragAndDropAdapter adapter = (LocaleDragAndDropAdapter) this.getAdapter();
if (adapter != null) {
adapter.doTheUpdate();
adapter.doTheUpdateWithMovingLocaleItem();
}
}
return super.onTouchEvent(e);

View File

@@ -50,6 +50,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
@@ -560,7 +561,8 @@ public class SubscriptionUtil {
if (TextUtils.isEmpty(rawPhoneNumber)) {
return null;
}
String countryIso = MccTable.countryCodeForMcc(subscriptionInfo.getMccString());
String countryIso = MccTable.countryCodeForMcc(subscriptionInfo.getMccString())
.toUpperCase(Locale.ROOT);
return PhoneNumberUtils.formatNumber(rawPhoneNumber, countryIso);
}

View File

@@ -27,6 +27,7 @@ import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.core.text.BidiFormatter;
import androidx.lifecycle.LifecycleObserver;
import androidx.preference.Preference;
@@ -54,7 +55,7 @@ import java.util.List;
public class AppChannelsBypassingDndPreferenceController extends NotificationPreferenceController
implements PreferenceControllerMixin, LifecycleObserver {
private static final String KEY = "zen_mode_bypassing_app_channels_list";
@VisibleForTesting static final String KEY = "zen_mode_bypassing_app_channels_list";
private static final String ARG_FROM_SETTINGS = "fromSettings";
private RestrictedSwitchPreference mAllNotificationsToggle;
@@ -74,8 +75,8 @@ public class AppChannelsBypassingDndPreferenceController extends NotificationPre
mAllNotificationsToggle = new RestrictedSwitchPreference(mPreferenceCategory.getContext());
mAllNotificationsToggle.setTitle(R.string.zen_mode_bypassing_app_channels_toggle_all);
mAllNotificationsToggle.setDisabledByAdmin(mAdmin);
mAllNotificationsToggle.setEnabled(
(mAdmin == null || !mAllNotificationsToggle.isDisabledByAdmin()));
mAllNotificationsToggle.setEnabled(!mAppRow.banned
&& (mAdmin == null || !mAllNotificationsToggle.isDisabledByAdmin()));
mAllNotificationsToggle.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
@@ -206,6 +207,9 @@ public class AppChannelsBypassingDndPreferenceController extends NotificationPre
}
private boolean areAllChannelsBypassing() {
if (mAppRow.banned) {
return false;
}
boolean allChannelsBypassing = true;
for (NotificationChannel channel : mChannels) {
if (showNotification(channel)) {
@@ -226,7 +230,7 @@ public class AppChannelsBypassingDndPreferenceController extends NotificationPre
* Whether notifications from this channel would show if DND weren't on.
*/
private boolean showNotification(NotificationChannel channel) {
return channel.getImportance() != IMPORTANCE_NONE;
return !mAppRow.banned && channel.getImportance() != IMPORTANCE_NONE;
}
/**

View File

@@ -32,6 +32,7 @@ import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
import com.android.settings.spa.app.specialaccess.SpecialAppAccessPageProvider
import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
import com.android.settings.spa.app.specialaccess.UseFullScreenIntentAppListProvider
import com.android.settings.spa.core.instrumentation.SpaLogProvider
import com.android.settings.spa.development.UsageStatsPageProvider
import com.android.settings.spa.home.HomePageProvider
import com.android.settings.spa.network.NetworkAndInternetPageProvider
@@ -87,4 +88,5 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
),
)
}
override val logger = SpaLogProvider
}

View File

@@ -16,18 +16,29 @@
package com.android.settings.spa
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.os.RemoteException
import android.os.UserHandle
import android.util.Log
import com.android.settingslib.spa.framework.BrowseActivity
import com.android.settingslib.spa.framework.util.SESSION_BROWSE
import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
import com.android.settingslib.spa.framework.util.appendSpaParams
class SpaActivity : BrowseActivity() {
companion object {
private const val TAG = "SpaActivity"
@JvmStatic
fun Context.startSpaActivity(destination: String) {
val intent = Intent(this, SpaActivity::class.java)
.appendSpaParams(destination = destination)
if (isLaunchedFromInternal()) {
intent.appendSpaParams(sessionName = SESSION_BROWSE)
} else {
intent.appendSpaParams(sessionName = SESSION_EXTERNAL)
}
startActivity(intent)
}
@@ -37,5 +48,15 @@ class SpaActivity : BrowseActivity() {
startSpaActivity("$destinationPrefix/$packageName/${UserHandle.myUserId()}")
return true
}
fun Context.isLaunchedFromInternal(): Boolean {
var pkg: String? = null
try {
pkg = ActivityManager.getService().getLaunchedFromPackage(getActivityToken())
} catch (e: RemoteException) {
Log.v(TAG, "Could not talk to activity manager.", e)
}
return applicationContext.packageName == pkg
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.
*/
package com.android.settings.spa.core.instrumentation
import androidx.annotation.VisibleForTesting
/**
* This class stores some metrics temporary data. Such as the timestamp of the page enter for
* calculating the duration time on page.
*/
class MetricsDataModel {
@VisibleForTesting
val pageTimeStampList = mutableListOf<PageTimeStamp>()
fun addTimeStamp(dataItem: PageTimeStamp){
pageTimeStampList.add(dataItem)
}
fun getPageDuration(pageId: String, removed: Boolean = true): String {
val lastItem = pageTimeStampList.findLast { it.pageId == pageId }
if (removed && lastItem != null) {
pageTimeStampList.remove(lastItem)
}
return if (lastItem == null) "0"
else (System.currentTimeMillis() - lastItem.timeStamp).toString()
}
}

View File

@@ -0,0 +1,132 @@
/*
* 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.
*/
package com.android.settings.spa.core.instrumentation
import android.app.settings.SettingsEnums
import android.os.Bundle
import androidx.annotation.VisibleForTesting
import com.android.settings.core.instrumentation.ElapsedTimeUtils
import com.android.settings.core.instrumentation.SettingsStatsLog
import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
import com.android.settingslib.spa.framework.common.LogCategory
import com.android.settingslib.spa.framework.common.LogEvent
import com.android.settingslib.spa.framework.common.SpaLogger
import com.android.settingslib.spa.framework.util.SESSION_BROWSE
import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
import com.android.settingslib.spa.framework.util.SESSION_SEARCH
import com.android.settingslib.spa.framework.util.SESSION_SLICE
import com.android.settingslib.spa.framework.util.SESSION_UNKNOWN
/**
* To receive the events from spa framework and logging the these events.
*/
object SpaLogProvider : SpaLogger {
private val dataModel = MetricsDataModel()
override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
when(event) {
LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE ->
write(SpaLogData(id, event, extraData, dataModel))
else -> return //TODO(b/253979024): Will be implemented in subsequent CLs.
}
}
private fun write(data: SpaLogData) {
with(data) {
SettingsStatsLog.write(
SettingsStatsLog.SETTINGS_SPA_REPORTED /* atomName */,
getSessionType(),
getPageId(),
getTarget(),
getAction(),
getKey(),
getValue(),
getPreValue(),
getElapsedTime()
)
}
}
}
@VisibleForTesting
class SpaLogData(val id: String, val event: LogEvent,
val extraData: Bundle, val dataModel: MetricsDataModel) {
fun getSessionType(): Int {
if (!extraData.containsKey(LOG_DATA_SESSION_NAME)) {
return SettingsEnums.SESSION_UNKNOWN
}
val sessionSource = extraData.getString(LOG_DATA_SESSION_NAME)
return when(sessionSource) {
SESSION_BROWSE -> SettingsEnums.BROWSE
SESSION_SEARCH -> SettingsEnums.SEARCH
SESSION_SLICE -> SettingsEnums.SLICE_TYPE
SESSION_EXTERNAL -> SettingsEnums.EXTERNAL
else -> SettingsEnums.SESSION_UNKNOWN
}
}
fun getPageId(): String {
return when(event) {
LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE -> id
else -> getPageIdByEntryId(id)
}
}
//TODO(b/253979024): Will be implemented in subsequent CLs.
fun getTarget(): String? {
return null
}
fun getAction(): Int {
return event.action
}
//TODO(b/253979024): Will be implemented in subsequent CLs.
fun getKey(): String? {
return null
}
fun getValue(): String? {
when(event) {
LogEvent.PAGE_ENTER -> dataModel.addTimeStamp(
PageTimeStamp(id, System.currentTimeMillis()))
LogEvent.PAGE_LEAVE -> return dataModel.getPageDuration(id)
else -> {} //TODO(b/253979024): Will be implemented in subsequent CLs.
}
return null
}
//TODO(b/253979024): Will be implemented in subsequent CLs.
fun getPreValue(): String? {
return null
}
fun getElapsedTime(): Long {
return ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())
}
//TODO(b/253979024): Will be implemented in subsequent CLs.
private fun getPageIdByEntryId(id: String): String {
return ""
}
}
/**
* The buffer is keeping the time stamp while spa page entering.
*/
data class PageTimeStamp(val pageId: String, val timeStamp: Long)

View File

@@ -16,7 +16,8 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
@@ -81,28 +82,30 @@ public class CameraFlashNotificationPreferenceControllerTest {
@Test
public void isChecked_setOff_assertFalse() {
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, OFF);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_setOn_assertTrue() {
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
assertThat(mController.isChecked()).isTrue();
}
@Test
public void setChecked_setTrue_assertNotZero() {
public void setChecked_setTrue_assertNotOff() {
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION,
0)).isNotEqualTo(0);
assertThat(
Settings.System.getInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION,
OFF)).isNotEqualTo(OFF);
}
@Test
public void setChecked_setFalse_assertNotOne() {
public void setChecked_setFalse_assertNotOn() {
mController.setChecked(false);
assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION,
1)).isNotEqualTo(1);
assertThat(
Settings.System.getInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION,
OFF)).isNotEqualTo(ON);
}
@Test

View File

@@ -18,8 +18,6 @@ package com.android.settings.accessibility;
import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_LONG_PREVIEW;
import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_SHORT_PREVIEW;
import static com.android.settings.accessibility.ShadowFlashNotificationsUtils.setFlashNotificationsState;
@@ -48,7 +46,6 @@ import androidx.test.core.app.ApplicationProvider;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -131,7 +128,6 @@ public class FlashNotificationsPreviewPreferenceControllerTest {
verify(mPreference).setEnabled(eq(true));
}
@Ignore
@Test
public void testHandlePreferenceTreeClick_invalidPreference() {
mController.handlePreferenceTreeClick(mock(Preference.class));
@@ -165,16 +161,16 @@ public class FlashNotificationsPreviewPreferenceControllerTest {
public void onStateChanged_onResume_cameraUri_verifyRegister() {
mController.onStateChanged(mock(LifecycleOwner.class), Lifecycle.Event.ON_RESUME);
verify(mContentResolver).registerContentObserver(
eq(Settings.System.getUriFor(SETTING_KEY_CAMERA_FLASH_NOTIFICATION)), anyBoolean(),
eq(mController.mContentObserver));
eq(Settings.System.getUriFor(Settings.System.CAMERA_FLASH_NOTIFICATION)),
anyBoolean(), eq(mController.mContentObserver));
}
@Test
public void onStateChanged_onResume_screenUri_verifyRegister() {
mController.onStateChanged(mock(LifecycleOwner.class), Lifecycle.Event.ON_RESUME);
verify(mContentResolver).registerContentObserver(
eq(Settings.System.getUriFor(SETTING_KEY_SCREEN_FLASH_NOTIFICATION)), anyBoolean(),
eq(mController.mContentObserver));
eq(Settings.System.getUriFor(Settings.System.SCREEN_FLASH_NOTIFICATION)),
anyBoolean(), eq(mController.mContentObserver));
}
@Test

View File

@@ -21,8 +21,8 @@ import static android.hardware.camera2.CameraCharacteristics.LENS_FACING;
import static android.hardware.camera2.CameraCharacteristics.LENS_FACING_BACK;
import static android.hardware.camera2.CameraMetadata.LENS_FACING_FRONT;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.FlashNotificationsUtil.getColorDescriptionText;
import static com.android.settings.accessibility.FlashNotificationsUtil.getFlashNotificationsState;
import static com.android.settings.accessibility.FlashNotificationsUtil.getScreenColor;
@@ -156,8 +156,8 @@ public class FlashNotificationsUtilTest {
@Test
public void getFlashNotificationsState_torchPresent_cameraOff_screenOff_assertOff() {
setTorchPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, OFF);
Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.OFF);
@@ -166,8 +166,8 @@ public class FlashNotificationsUtilTest {
@Test
public void getFlashNotificationsState_torchNotPresent_cameraOn_screenOff_assertOff() {
setTorchNotPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.OFF);
@@ -176,8 +176,8 @@ public class FlashNotificationsUtilTest {
@Test
public void getFlashNotificationsState_torchPresent_cameraOn_screenOff_assertCamera() {
setTorchPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.CAMERA);
@@ -186,8 +186,8 @@ public class FlashNotificationsUtilTest {
@Test
public void getFlashNotificationsState_torchPresent_cameraOff_screenOn_assertScreen() {
setTorchPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, OFF);
Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, ON);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.SCREEN);
@@ -196,8 +196,8 @@ public class FlashNotificationsUtilTest {
@Test
public void testGetFlashNotificationsState_torchPresent_cameraOn_screenOn_assertCameraScreen() {
setTorchPresent();
Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, ON);
assertThat(getFlashNotificationsState(mContext))
.isEqualTo(FlashNotificationsUtil.State.CAMERA_SCREEN);

View File

@@ -16,9 +16,9 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.FlashNotificationsUtil.DEFAULT_SCREEN_FLASH_COLOR;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.google.common.truth.Truth.assertThat;
@@ -114,48 +114,50 @@ public class ScreenFlashNotificationPreferenceControllerTest {
@Test
public void isChecked_setOff_assertFalse() {
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_setOn_assertTrue() {
Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, ON);
assertThat(mController.isChecked()).isTrue();
}
@Test
public void setChecked_whenTransparentColor_setTrue_assertNotTransparentColor() {
Settings.System.putInt(mContentResolver,
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT);
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT);
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver,
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0))
.isEqualTo(DEFAULT_SCREEN_FLASH_COLOR);
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, 0)).isEqualTo(
DEFAULT_SCREEN_FLASH_COLOR);
}
@Test
public void setChecked_whenNotTransparent_setTrue_assertSameColor() {
Settings.System.putInt(mContentResolver,
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0x4D0000FF);
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, 0x4D0000FF);
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver,
SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0))
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, 0))
.isEqualTo(0x4D0000FF);
}
@Test
public void setChecked_setTrue_assertOn() {
mController.setChecked(true);
assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION,
0)).isEqualTo(1);
assertThat(
Settings.System.getInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION,
OFF)).isEqualTo(ON);
}
@Test
public void setChecked_setFalse_assertOff() {
mController.setChecked(false);
assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION,
1)).isEqualTo(0);
assertThat(
Settings.System.getInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION,
OFF)).isEqualTo(OFF);
}
@Test

View File

@@ -0,0 +1,106 @@
/*
* 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.development;
import static android.bluetooth.BluetoothStatusCodes.FEATURE_SUPPORTED;
import static com.android.settings.development.BluetoothLeAudioAllowListPreferenceController
.LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.SystemProperties;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class BluetoothLeAudioAllowListPreferenceControllerTest {
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private DevelopmentSettingsDashboardFragment mFragment;
@Mock
private BluetoothAdapter mBluetoothAdapter;
private Context mContext;
private SwitchPreference mPreference;
private BluetoothLeAudioPreferenceController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mPreference = new SwitchPreference(mContext);
mController = spy(new BluetoothLeAudioPreferenceController(mContext, mFragment));
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
mController.mBluetoothAdapter = mBluetoothAdapter;
mController.displayPreference(mPreferenceScreen);
when(mBluetoothAdapter.isLeAudioSupported())
.thenReturn(FEATURE_SUPPORTED);
}
@Test
public void onRebootDialogConfirmedAsLeAudioAllowListDisabled_shouldSwitchStatus() {
SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(false));
mController.mChanged = true;
mController.onRebootDialogConfirmed();
final boolean mode = SystemProperties.getBoolean(
LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
assertThat(mode).isFalse();
}
@Test
public void onRebootDialogConfirmedAsLeAudioAllowListEnabled_shouldSwitchStatus() {
SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(true));
mController.mChanged = true;
mController.onRebootDialogConfirmed();
final boolean status = SystemProperties.getBoolean(
LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
assertThat(status).isTrue();
}
@Test
public void onRebootDialogCanceled_shouldNotSwitchStatus() {
SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(false));
mController.mChanged = true;
mController.onRebootDialogCanceled();
final boolean status = SystemProperties.getBoolean(
LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
assertThat(status).isFalse();
}
}

View File

@@ -18,17 +18,13 @@ package com.android.settings.fuelgauge.batterysaver;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.provider.Settings;
import android.provider.SettingsSlicesContract;
@@ -85,6 +81,15 @@ public class BatterySaverButtonPreferenceControllerTest {
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void onSwitchChanged_isCheckedAndAcked_setPowerSaveMode() {
setLowPowerWarningAcked(/* acked= */ 1);
mController.onSwitchChanged(/* switchView= */ null, /* isChecked= */ true);
verify(mPowerManager).setPowerSaveModeEnabled(true);
}
@Test
public void updateState_lowPowerOn_preferenceIsChecked() {
when(mPowerManager.isPowerSaveMode()).thenReturn(true);
@@ -104,11 +109,10 @@ public class BatterySaverButtonPreferenceControllerTest {
}
@Test
public void setChecked_on_showWarningMessage() {
public void setChecked_on_setPowerSaveMode() {
mController.setChecked(true);
verify(mContext).sendBroadcast(any(Intent.class));
verify(mPowerManager, never()).setPowerSaveModeEnabled(anyBoolean());
verify(mPowerManager).setPowerSaveModeEnabled(true);
}
@Test
@@ -143,5 +147,9 @@ public class BatterySaverButtonPreferenceControllerTest {
mContext.getContentResolver(),
Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
acked);
Settings.Secure.putInt(
mContext.getContentResolver(),
Settings.Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED,
acked);
}
}

View File

@@ -93,13 +93,13 @@ public class KeyboardLayoutPickerControllerTest {
}
@Test
public void testLifecycle_onStart_NoInputDevice_shouldFinish() {
public void testLifecycle_onStart_NoInputDevice_shouldReturn() {
final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class);
when(mInputManager.getInputDeviceByDescriptor(anyString())).thenReturn(null);
when(mFragment.getActivity()).thenReturn(activity);
mController.onStart();
assertThat(activity.isFinishing()).isTrue();
verify(mInputManager, never()).getEnabledKeyboardLayoutsForInputDevice(any());
}
@Test

View File

@@ -0,0 +1,151 @@
/*
* 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.
*/
package com.android.settings.notification.app;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.PrimarySwitchPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.shadows.ShadowApplication;
import java.util.ArrayList;
import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public class AppChannelsBypassingDndPreferenceControllerTest {
@Mock
private NotificationBackend mBackend;
private NotificationBackend.AppRow mAppRow;
private AppChannelsBypassingDndPreferenceController mController;
private PreferenceScreen mPreferenceScreen;
private PreferenceCategory mCategory;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Context context = ApplicationProvider.getApplicationContext();
mAppRow = new NotificationBackend.AppRow();
mAppRow.uid = 42;
mAppRow.pkg = "com.example.exampling";
mController = new AppChannelsBypassingDndPreferenceController(context, mBackend);
mController.onResume(mAppRow, null, null, null, null, null, new ArrayList<>());
PreferenceManager preferenceManager = new PreferenceManager(context);
mPreferenceScreen = preferenceManager.createPreferenceScreen(context);
mCategory = new PreferenceCategory(context);
mCategory.setKey(AppChannelsBypassingDndPreferenceController.KEY);
mPreferenceScreen.addPreference(mCategory);
}
@Test
public void displayPreference_showsAllAndChannels() {
when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
buildGroupList(true, true, false));
mController.displayPreference(mPreferenceScreen);
ShadowApplication.runBackgroundTasks();
assertThat(mCategory.getPreferenceCount()).isEqualTo(4); // "All" + 3 channels
assertThat(mCategory.getPreference(0).getTitle().toString()).isEqualTo(
"Allow all notifications");
assertThat(mCategory.getPreference(1).getTitle().toString()).isEqualTo("Channel 1");
assertThat(mCategory.getPreference(2).getTitle().toString()).isEqualTo("Channel 2");
assertThat(mCategory.getPreference(3).getTitle().toString()).isEqualTo("Channel 3");
}
@Test
public void displayPreference_canToggleAllInterrupt() {
when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
buildGroupList(true, true, false));
mController.displayPreference(mPreferenceScreen);
ShadowApplication.runBackgroundTasks();
assertThat(mCategory.getPreference(0).isEnabled()).isTrue();
}
@Test
public void displayPreference_canToggleInterruptIfChannelEnabled() {
when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
buildGroupList(true, false, true));
mController.displayPreference(mPreferenceScreen);
ShadowApplication.runBackgroundTasks();
assertThat(((PrimarySwitchPreference) mCategory.getPreference(
1)).isSwitchEnabled()).isTrue();
assertThat(((PrimarySwitchPreference) mCategory.getPreference(
2)).isSwitchEnabled()).isFalse();
assertThat(((PrimarySwitchPreference) mCategory.getPreference(
3)).isSwitchEnabled()).isTrue();
}
@Test
public void displayPreference_appBlocked_cannotToggleAllOrChannelInterrupts() {
mAppRow.banned = true;
when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
buildGroupList(true, false, true));
mController.displayPreference(mPreferenceScreen);
ShadowApplication.runBackgroundTasks();
assertThat(mCategory.getPreference(0).isEnabled()).isFalse();
assertThat(((PrimarySwitchPreference) mCategory.getPreference(
1)).isSwitchEnabled()).isFalse();
assertThat(((PrimarySwitchPreference) mCategory.getPreference(
2)).isSwitchEnabled()).isFalse();
assertThat(((PrimarySwitchPreference) mCategory.getPreference(
3)).isSwitchEnabled()).isFalse();
}
private static ParceledListSlice<NotificationChannelGroup> buildGroupList(
boolean... enabledByChannel) {
NotificationChannelGroup group = new NotificationChannelGroup("group", "The Group");
for (int i = 0; i < enabledByChannel.length; i++) {
group.addChannel(new NotificationChannel("channel-" + (i + 1), "Channel " + (i + 1),
enabledByChannel[i] ? NotificationManager.IMPORTANCE_DEFAULT
: NotificationManager.IMPORTANCE_NONE));
}
return new ParceledListSlice<>(Collections.singletonList(group));
}
}

View File

@@ -25,12 +25,15 @@ import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
import com.android.settings.spa.SpaActivity.Companion.startSpaActivityForApp
import com.android.settingslib.spa.framework.util.KEY_DESTINATION
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Answers
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@@ -39,9 +42,14 @@ class SpaActivityTest {
@get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@Mock
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private lateinit var context: Context
@Before
fun setUp() {
`when`(context.applicationContext.packageName).thenReturn("com.android.settings")
}
@Test
fun startSpaActivity() {
context.startSpaActivity(DESTINATION)

View File

@@ -0,0 +1,95 @@
/*
* 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.
*/
package com.android.settings.spa.core.instrumentation
import android.os.SystemClock
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
/** Tests for {@link MetricsDataModel}. */
@RunWith(AndroidJUnit4::class)
class MetricsDataModelTest {
private val TEST_PID = "pseudo_page_id"
private lateinit var metricsDataModel: MetricsDataModel
@Before
fun setUp() {
metricsDataModel = MetricsDataModel()
}
@Test
fun initMetricsDataModel() {
assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(0)
}
@Test
fun addTimeStamp_addOnePageTimeStamp_sizeShouldBeOne() {
metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(1)
}
@Test
fun addTimeStamp_addTwoSamePageTimeStamp_sizeShouldBeTwo() {
metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(2)
}
@Test
fun getPageDuration_getExistPageId_mustFoundValue() {
metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
SystemClock.sleep(5)
assertThat(metricsDataModel.getPageDuration(TEST_PID).toInt()).isGreaterThan(0)
assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(0)
}
@Test
fun getPageDuration_getNonExistPageId_valueShouldBeZero() {
metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
assertThat(metricsDataModel.getPageDuration("WRONG_ID").toLong()).isEqualTo(0L)
}
@Test
fun getPageDuration_getExistPageIdAndDonotRemoved_sizeShouldBeOne() {
metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
SystemClock.sleep(5)
assertThat(metricsDataModel.getPageDuration(TEST_PID, false).toLong()).isGreaterThan(0L)
assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(1)
}
@Test
fun getPageDuration_getTwoExistPageId_theOrderIsLIFO() {
metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, 10000L))
metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, 20000L))
// The formula is d1 = t1 - 20000, d2 = t2 - 10000
// d2 - d1 = t2 - t1 + 10000, because t2 > t1 the result of d2 - d1 is greater 10000
val duration1 = metricsDataModel.getPageDuration(TEST_PID).toLong()
SystemClock.sleep(5)
val duration2 = metricsDataModel.getPageDuration(TEST_PID).toLong()
assertThat(duration2 - duration1).isGreaterThan(10000L)
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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.
*/
package com.android.settings.spa.core.instrumentation
import android.app.settings.SettingsEnums
import android.os.Bundle
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
import com.android.settingslib.spa.framework.common.LogEvent
import com.android.settingslib.spa.framework.util.SESSION_BROWSE
import com.android.settingslib.spa.framework.util.SESSION_SEARCH
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
/** Tests for {@link SpaLogData}. */
@RunWith(AndroidJUnit4::class)
class SpaLogDataTest {
private val TEST_PID = "pseudo_page_id"
private lateinit var bundle: Bundle
private lateinit var dataModel: MetricsDataModel
@Before
fun setUp() {
bundle = Bundle()
dataModel = MetricsDataModel()
}
@Test
fun getSessionType_withoutSessionExtraData_returnSessionUnknow() {
val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.SESSION_UNKNOWN)
}
@Test
fun getSessionType_hasSessionBrowseExtraData_returnSessionBrowse() {
bundle.putString(LOG_DATA_SESSION_NAME, SESSION_BROWSE)
val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.BROWSE)
}
@Test
fun getSessionType_hasSessionSearchExtraData_returnSessionSearch() {
bundle.putString(LOG_DATA_SESSION_NAME, SESSION_SEARCH)
val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.SEARCH)
}
@Test
fun getSessionType_hasSessionUnknownExtraData_returnSessionUnknow() {
bundle.putString(LOG_DATA_SESSION_NAME, "SESSION_OTHER")
val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.SESSION_UNKNOWN)
}
@Test
fun getPageId_withPageEvent_returnInputId() {
val spaLogData1 = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
assertThat(spaLogData1.getPageId()).isEqualTo(TEST_PID)
val spaLogData2 = SpaLogData(TEST_PID, LogEvent.PAGE_LEAVE, bundle, dataModel)
assertThat(spaLogData2.getPageId()).isEqualTo(TEST_PID)
}
}

View File

@@ -27,12 +27,14 @@ import static org.mockito.Mockito.spy;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialProviderInfo;
import android.os.Looper;
import androidx.lifecycle.Lifecycle;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -87,7 +89,7 @@ public class CredentialManagerPreferenceControllerTest {
@Test
public void getAvailabilityStatus_withServices_returnsAvailable() {
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(createServiceInfo()));
createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
assertThat(controller.isConnected()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@@ -103,24 +105,59 @@ public class CredentialManagerPreferenceControllerTest {
@Test
public void displayPreference_withServices_preferencesAdded() {
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(createServiceInfo()));
createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
controller.displayPreference(mScreen);
assertThat(controller.isConnected()).isFalse();
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
}
@Test
public void buildSwitchPreference() {
CredentialProviderInfo providerInfo1 =
createCredentialProviderInfo(
"com.android.provider1", "ClassA", "Service Title", false);
CredentialProviderInfo providerInfo2 =
createCredentialProviderInfo(
"com.android.provider2", "ClassA", "Service Title", false);
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
assertThat(controller.isConnected()).isFalse();
// Test the data is correct.
assertThat(providerInfo1.isEnabled()).isFalse();
assertThat(providerInfo2.isEnabled()).isFalse();
assertThat(controller.getEnabledProviders().size()).isEqualTo(0);
// Toggle one provider and make sure it worked.
assertThat(controller.togglePackageNameEnabled("com.android.provider1")).isTrue();
Set<String> enabledProviders = controller.getEnabledProviders();
assertThat(enabledProviders.size()).isEqualTo(1);
assertThat(enabledProviders.contains("com.android.provider1")).isTrue();
// Create the pref (checked).
SwitchPreference pref = controller.createPreference(mContext, providerInfo1);
assertThat(pref.getTitle().toString()).isEqualTo("Service Title");
assertThat(pref.isChecked()).isTrue();
// Create the pref (not checked).
SwitchPreference pref2 = controller.createPreference(mContext, providerInfo2);
assertThat(pref2.getTitle().toString()).isEqualTo("Service Title");
assertThat(pref2.isChecked()).isFalse();
}
@Test
public void getAvailabilityStatus_handlesToggleAndSave() {
CredentialManagerPreferenceController controller =
createControllerWithServices(
Lists.newArrayList(
createServiceInfo("com.android.provider1", "ClassA"),
createServiceInfo("com.android.provider1", "ClassB"),
createServiceInfo("com.android.provider2", "ClassA"),
createServiceInfo("com.android.provider3", "ClassA"),
createServiceInfo("com.android.provider4", "ClassA"),
createServiceInfo("com.android.provider5", "ClassA"),
createServiceInfo("com.android.provider6", "ClassA")));
createCredentialProviderInfo("com.android.provider1", "ClassA"),
createCredentialProviderInfo("com.android.provider1", "ClassB"),
createCredentialProviderInfo("com.android.provider2", "ClassA"),
createCredentialProviderInfo("com.android.provider3", "ClassA"),
createCredentialProviderInfo("com.android.provider4", "ClassA"),
createCredentialProviderInfo("com.android.provider5", "ClassA"),
createCredentialProviderInfo("com.android.provider6", "ClassA")));
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
assertThat(controller.isConnected()).isFalse();
@@ -177,8 +214,38 @@ public class CredentialManagerPreferenceControllerTest {
assertThat(currentlyEnabledServices.contains("com.android.provider6/ClassA")).isFalse();
}
@Test
public void handlesCredentialProviderInfoEnabledDisabled() {
CredentialProviderInfo providerInfo1 =
createCredentialProviderInfo(
"com.android.provider1", "ClassA", "Service Title", false);
CredentialProviderInfo providerInfo2 =
createCredentialProviderInfo(
"com.android.provider2", "ClassA", "Service Title", true);
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
assertThat(controller.isConnected()).isFalse();
// Test the data is correct.
assertThat(providerInfo1.isEnabled()).isFalse();
assertThat(providerInfo2.isEnabled()).isTrue();
// Check that they are all actually registered.
Set<String> enabledProviders = controller.getEnabledProviders();
assertThat(enabledProviders.size()).isEqualTo(1);
assertThat(enabledProviders.contains("com.android.provider1")).isFalse();
assertThat(enabledProviders.contains("com.android.provider2")).isTrue();
// Check that the settings string has the right component names.
List<String> enabledServices = controller.getEnabledSettings();
assertThat(enabledServices.size()).isEqualTo(1);
assertThat(enabledServices.contains("com.android.provider1/ClassA")).isFalse();
assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue();
}
private CredentialManagerPreferenceController createControllerWithServices(
List<ServiceInfo> availableServices) {
List<CredentialProviderInfo> availableServices) {
CredentialManagerPreferenceController controller =
new CredentialManagerPreferenceController(
mContext, mCredentialsPreferenceCategory.getKey());
@@ -186,11 +253,17 @@ public class CredentialManagerPreferenceControllerTest {
return controller;
}
private ServiceInfo createServiceInfo() {
return createServiceInfo("com.android.provider", "CredManProvider");
private CredentialProviderInfo createCredentialProviderInfo() {
return createCredentialProviderInfo("com.android.provider", "CredManProvider");
}
private ServiceInfo createServiceInfo(String packageName, String className) {
private CredentialProviderInfo createCredentialProviderInfo(
String packageName, String className) {
return createCredentialProviderInfo(packageName, className, null, false);
}
private CredentialProviderInfo createCredentialProviderInfo(
String packageName, String className, CharSequence label, boolean isEnabled) {
ServiceInfo si = new ServiceInfo();
si.packageName = packageName;
si.name = className;
@@ -200,6 +273,9 @@ public class CredentialManagerPreferenceControllerTest {
si.applicationInfo.packageName = packageName;
si.applicationInfo.nonLocalizedLabel = "test";
return si;
return new CredentialProviderInfo.Builder(si)
.setOverrideLabel(label)
.setEnabled(isEnabled)
.build();
}
}

View File

@@ -0,0 +1,146 @@
/*
* 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.
*/
package com.android.settings.localepicker;
import static com.android.settings.localepicker.LocaleDialogFragment.ARG_DIALOG_TYPE;
import static com.android.settings.localepicker.LocaleDialogFragment.ARG_RESULT_RECEIVER;
import static com.android.settings.localepicker.LocaleDialogFragment.ARG_TARGET_LOCALE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.ResultReceiver;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.app.LocaleStore;
import com.android.settings.testutils.ResourcesUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.Locale;
@UiThreadTest
public class LocaleDialogFragmentTest {
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
private Context mContext;
private LocaleDialogFragment mDialogFragment;
@Before
public void setUp() throws Exception {
mContext = ApplicationProvider.getApplicationContext();
mDialogFragment = new LocaleDialogFragment();
}
private void setArgument(
int type, ResultReceiver receiver) {
LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(Locale.ENGLISH);
Bundle args = new Bundle();
args.putInt(ARG_DIALOG_TYPE, type);
args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
args.putParcelable(ARG_RESULT_RECEIVER, receiver);
mDialogFragment.setArguments(args);
}
@Test
public void getDialogContent_confirmSystemDefault_has2ButtonText() {
setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
LocaleDialogFragment.LocaleDialogController controller =
new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
controller.getDialogContent();
assertEquals(ResourcesUtils.getResourcesString(
mContext, "button_label_confirmation_of_system_locale_change"),
dialogContent.mPositiveButton);
assertEquals(ResourcesUtils.getResourcesString(mContext, "cancel"),
dialogContent.mNegativeButton);
}
@Test
public void getDialogContent_unavailableLocale_has1ButtonText() {
setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
LocaleDialogFragment.LocaleDialogController controller =
new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
controller.getDialogContent();
assertEquals(ResourcesUtils.getResourcesString(mContext, "okay"),
dialogContent.mPositiveButton);
assertTrue(dialogContent.mNegativeButton.isEmpty());
}
@Test
public void onClick_clickPositiveButton_sendOK() {
ResultReceiver resultReceiver = spy(new ResultReceiver(null));
setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
LocaleDialogFragment.LocaleDialogController controller =
new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
controller.onClick(null, DialogInterface.BUTTON_POSITIVE);
verify(resultReceiver).send(eq(Activity.RESULT_OK), any());
}
@Test
public void onClick_clickNegativeButton_sendCancel() {
ResultReceiver resultReceiver = spy(new ResultReceiver(null));
setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
LocaleDialogFragment.LocaleDialogController controller =
new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
controller.onClick(null, DialogInterface.BUTTON_NEGATIVE);
verify(resultReceiver).send(eq(Activity.RESULT_CANCELED), any());
}
@Test
public void getMetricsCategory_systemLocaleChange() {
setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
int result = mDialogFragment.getMetricsCategory();
assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE, result);
}
@Test
public void getMetricsCategory_unavailableLocale() {
setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
int result = mDialogFragment.getMetricsCategory();
assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE, result);
}
}