Snap for 10154358 from 28edfb8df9
to udc-release
Change-Id: Ib9d209d6fd01fb52de34f835fe8c25bcc438cdd9
This commit is contained in:
@@ -60,6 +60,8 @@
|
|||||||
android:id="@android:id/title"
|
android:id="@android:id/title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
android:hyphenationFrequency="normalFast"
|
android:hyphenationFrequency="normalFast"
|
||||||
|
@@ -8164,6 +8164,12 @@
|
|||||||
<!-- [CHAR LIMIT=NONE] Channel notification settings: Block option description-->
|
<!-- [CHAR LIMIT=NONE] Channel notification settings: Block option description-->
|
||||||
<string name="notification_content_block_summary">Never show notifications in the shade or on peripheral devices</string>
|
<string name="notification_content_block_summary">Never show notifications in the shade or on peripheral devices</string>
|
||||||
|
|
||||||
|
<!-- [CHAR LIMIT=NONE] App notification settings: Full screen intent permission option title -->
|
||||||
|
<string name="app_notification_fsi_permission_title">Allow full screen notifications</string>
|
||||||
|
|
||||||
|
<!-- [CHAR LIMIT=NONE] App notification settings: Full screen intent permission option description -->
|
||||||
|
<string name="app_notification_fsi_permission_summary">Allow notifications to take up the full screen when the device is locked</string>
|
||||||
|
|
||||||
<!-- [CHAR LIMIT=NONE BACKUP_MESSAGE_ID:7166470350070693657] App notification settings: Badging option title -->
|
<!-- [CHAR LIMIT=NONE BACKUP_MESSAGE_ID:7166470350070693657] App notification settings: Badging option title -->
|
||||||
<string name="notification_badge_title">Allow notification dot</string>
|
<string name="notification_badge_title">Allow notification dot</string>
|
||||||
|
|
||||||
@@ -10158,7 +10164,9 @@
|
|||||||
<string name="financed_privacy_restrictions_removed">All restrictions are removed from the device</string>
|
<string name="financed_privacy_restrictions_removed">All restrictions are removed from the device</string>
|
||||||
<!-- Label explaining that the app installed by credit provider can be uninstalled. [CHAR LIMIT=60]-->
|
<!-- Label explaining that the app installed by credit provider can be uninstalled. [CHAR LIMIT=60]-->
|
||||||
<string name="financed_privacy_uninstall_creditor_app">You can uninstall the creditor app</string>
|
<string name="financed_privacy_uninstall_creditor_app">You can uninstall the creditor app</string>
|
||||||
|
<!-- Title of setting on security settings screen on a device provisioned by Device Lock. This will take the user to a screen in Device Lock with information about what a device provider can control and their impact on the user's privacy. Shown on Device Lock provisioned devices only. [CHAR LIMIT=NONE] -->
|
||||||
|
<!-- TODO(b/282040794): Update the title -->
|
||||||
|
<string name="device_lock_info">Device Lock</string>
|
||||||
<!-- Strings for displaying which applications were set as default for specific actions. -->
|
<!-- Strings for displaying which applications were set as default for specific actions. -->
|
||||||
<!-- Title for the apps that have been set as default handlers of camera-related intents. [CHAR LIMIT=30] -->
|
<!-- Title for the apps that have been set as default handlers of camera-related intents. [CHAR LIMIT=30] -->
|
||||||
<string name="default_camera_app_title">{count, plural,
|
<string name="default_camera_app_title">{count, plural,
|
||||||
|
@@ -59,38 +59,57 @@
|
|||||||
<com.android.settingslib.RestrictedSwitchPreference
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
android:key="allow_sound"
|
android:key="allow_sound"
|
||||||
android:title="@string/allow_interruption"
|
android:title="@string/allow_interruption"
|
||||||
android:summary="@string/allow_interruption_summary" />
|
android:summary="@string/allow_interruption_summary"
|
||||||
|
settings:allowDividerAbove="true"
|
||||||
|
settings:allowDividerBelow="false" />
|
||||||
|
|
||||||
<!-- Visibility Override -->
|
<!-- Visibility Override -->
|
||||||
<com.android.settings.RestrictedListPreference
|
<com.android.settings.RestrictedListPreference
|
||||||
android:key="visibility_override"
|
android:key="visibility_override"
|
||||||
android:title="@string/app_notification_visibility_override_title"/>
|
android:title="@string/app_notification_visibility_override_title"
|
||||||
|
settings:allowDividerAbove="true"
|
||||||
|
settings:allowDividerBelow="false" />
|
||||||
|
|
||||||
<!-- Bypass DND -->
|
<!-- Bypass DND -->
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
android:key="bypass_dnd"
|
android:key="bypass_dnd"
|
||||||
android:title="@string/app_notification_override_dnd_title"
|
android:title="@string/app_notification_override_dnd_title"
|
||||||
android:summary="@string/app_notification_override_dnd_summary"/>
|
android:summary="@string/app_notification_override_dnd_summary"
|
||||||
|
settings:allowDividerAbove="true"
|
||||||
|
settings:allowDividerBelow="false" />
|
||||||
|
|
||||||
|
<!-- Allow full-screen intents -->
|
||||||
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
|
android:key="fsi_permission"
|
||||||
|
android:title="@string/app_notification_fsi_permission_title"
|
||||||
|
android:summary="@string/app_notification_fsi_permission_summary"
|
||||||
|
settings:allowDividerAbove="true"
|
||||||
|
settings:allowDividerBelow="false" />
|
||||||
|
|
||||||
<!-- Show badge -->
|
<!-- Show badge -->
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
android:key="badge"
|
android:key="badge"
|
||||||
android:title="@string/notification_badge_title"
|
android:title="@string/notification_badge_title"
|
||||||
settings:useAdditionalSummary="true"
|
|
||||||
android:order="1001"
|
|
||||||
android:icon="@drawable/ic_notification_dot"
|
android:icon="@drawable/ic_notification_dot"
|
||||||
|
settings:useAdditionalSummary="true"
|
||||||
|
settings:restrictedSwitchSummary="@string/enabled_by_admin"
|
||||||
|
android:order="1001"
|
||||||
settings:allowDividerAbove="true"
|
settings:allowDividerAbove="true"
|
||||||
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
|
settings:allowDividerBelow="false" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="app_link"
|
android:key="app_link"
|
||||||
android:order="1003"
|
|
||||||
android:icon="@drawable/ic_settings_24dp"
|
android:icon="@drawable/ic_settings_24dp"
|
||||||
android:title="@string/app_settings_link" />
|
android:title="@string/app_settings_link"
|
||||||
|
android:order="1003"
|
||||||
|
settings:allowDividerAbove="true"
|
||||||
|
settings:allowDividerBelow="false" />
|
||||||
|
|
||||||
<com.android.settingslib.widget.FooterPreference
|
<com.android.settingslib.widget.FooterPreference
|
||||||
android:key="deleted"
|
android:key="deleted"
|
||||||
android:icon="@drawable/ic_trash_can"
|
android:icon="@drawable/ic_trash_can"
|
||||||
android:order="8000" />
|
android:order="8000"
|
||||||
|
settings:allowDividerAbove="true"
|
||||||
|
settings:allowDividerBelow="false" />
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@@ -146,6 +146,13 @@
|
|||||||
android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
|
android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
|
||||||
settings:controller="com.android.settings.enterprise.FinancedPrivacyPreferenceController"/>
|
settings:controller="com.android.settings.enterprise.FinancedPrivacyPreferenceController"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="device_lock_info"
|
||||||
|
android:title="@string/device_lock_info"
|
||||||
|
android:summary="@string/summary_placeholder"
|
||||||
|
settings:controller="com.android.settings.devicelock.DeviceLockPreferenceController">
|
||||||
|
<intent android:action="com.android.devicelockcontroller.action.DEVICE_INFO_SETTINGS"/>
|
||||||
|
</Preference>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
@@ -58,6 +58,13 @@
|
|||||||
android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
|
android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
|
||||||
settings:controller="com.android.settings.enterprise.FinancedPrivacyPreferenceController"/>
|
settings:controller="com.android.settings.enterprise.FinancedPrivacyPreferenceController"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="device_lock_info"
|
||||||
|
android:title="@string/device_lock_info"
|
||||||
|
android:summary="@string/summary_placeholder"
|
||||||
|
settings:controller="com.android.settings.devicelock.DeviceLockPreferenceController">
|
||||||
|
<intent android:action="com.android.devicelockcontroller.action.DEVICE_INFO_SETTINGS"/>
|
||||||
|
</Preference>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
@@ -69,6 +69,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
|
|
||||||
private static final String ENABLE_DUAL_MODE_AUDIO =
|
private static final String ENABLE_DUAL_MODE_AUDIO =
|
||||||
"persist.bluetooth.enable_dual_mode_audio";
|
"persist.bluetooth.enable_dual_mode_audio";
|
||||||
|
private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
|
||||||
|
|
||||||
private LocalBluetoothManager mManager;
|
private LocalBluetoothManager mManager;
|
||||||
private LocalBluetoothProfileManager mProfileManager;
|
private LocalBluetoothProfileManager mProfileManager;
|
||||||
@@ -99,7 +100,9 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||||
SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
|
SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
|
||||||
mIsLeAudioToggleEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
mIsLeAudioToggleEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
|
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false)
|
||||||
|
|| DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH,
|
||||||
|
CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
|
||||||
// Call refresh here even though it will get called later in onResume, to avoid the
|
// Call refresh here even though it will get called later in onResume, to avoid the
|
||||||
// list of switches appearing to "pop" into the page.
|
// list of switches appearing to "pop" into the page.
|
||||||
refresh();
|
refresh();
|
||||||
|
@@ -39,6 +39,7 @@ public class BluetoothLeAudioDeviceDetailsPreferenceController
|
|||||||
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
|
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
|
||||||
|
|
||||||
private static final String PREFERENCE_KEY = "bluetooth_show_leaudio_device_details";
|
private static final String PREFERENCE_KEY = "bluetooth_show_leaudio_device_details";
|
||||||
|
private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
|
||||||
static int sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
|
static int sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -87,8 +88,12 @@ public class BluetoothLeAudioDeviceDetailsPreferenceController
|
|||||||
final boolean leAudioDeviceDetailEnabled = DeviceConfig.getBoolean(
|
final boolean leAudioDeviceDetailEnabled = DeviceConfig.getBoolean(
|
||||||
DeviceConfig.NAMESPACE_SETTINGS_UI,
|
DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||||
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
|
SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
|
||||||
|
final boolean leAudioEnabledByDefault = DeviceConfig.getBoolean(
|
||||||
|
DeviceConfig.NAMESPACE_BLUETOOTH, CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
|
||||||
|
|
||||||
((SwitchPreference) mPreference).setChecked(leAudioDeviceDetailEnabled);
|
mPreference.setEnabled(!leAudioEnabledByDefault);
|
||||||
|
((SwitchPreference) mPreference).setChecked(leAudioDeviceDetailEnabled
|
||||||
|
|| leAudioEnabledByDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.devicelock;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.devicelock.DeviceLockManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PreferenceController that manages the Device Lock entry preference.
|
||||||
|
*/
|
||||||
|
public final class DeviceLockPreferenceController extends BasePreferenceController {
|
||||||
|
|
||||||
|
private static final String TAG = "DeviceLockPreferenceController";
|
||||||
|
|
||||||
|
private final DeviceLockManager mDeviceLockManager;
|
||||||
|
|
||||||
|
public DeviceLockPreferenceController(Context context, String preferenceKey) {
|
||||||
|
super(context, preferenceKey);
|
||||||
|
mDeviceLockManager = mContext.getSystemService(DeviceLockManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
// TODO(b/282856378): make this entry searchable
|
||||||
|
return AVAILABLE_UNSEARCHABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
super.updateState(preference);
|
||||||
|
mDeviceLockManager.getKioskApps(mContext.getMainExecutor(),
|
||||||
|
result -> {
|
||||||
|
// if kiosk apps present on the device, the device is provisioned by Device Lock
|
||||||
|
boolean isDeviceProvisionedByDeviceLock = result != null && !result.isEmpty();
|
||||||
|
Log.d(TAG, "Set preference visibility to " + isDeviceProvisionedByDeviceLock);
|
||||||
|
// TODO(b/282179089): find alternatives instead of calling setVisible
|
||||||
|
preference.setVisible(isDeviceProvisionedByDeviceLock);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -18,7 +18,9 @@ package com.android.settings.fuelgauge.batterytip;
|
|||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.BadParcelableException;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -142,14 +144,26 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void restoreInstanceState(Bundle bundle) {
|
public void restoreInstanceState(Bundle bundle) {
|
||||||
if (bundle != null) {
|
if (bundle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
List<BatteryTip> batteryTips = bundle.getParcelableArrayList(KEY_BATTERY_TIPS);
|
List<BatteryTip> batteryTips = bundle.getParcelableArrayList(KEY_BATTERY_TIPS);
|
||||||
updateBatteryTips(batteryTips);
|
updateBatteryTips(batteryTips);
|
||||||
|
} catch (BadParcelableException e) {
|
||||||
|
Log.e(TAG, "failed to invoke restoreInstanceState()", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveInstanceState(Bundle outState) {
|
public void saveInstanceState(Bundle bundle) {
|
||||||
outState.putParcelableList(KEY_BATTERY_TIPS, mBatteryTips);
|
if (bundle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
bundle.putParcelableList(KEY_BATTERY_TIPS, mBatteryTips);
|
||||||
|
} catch (BadParcelableException e) {
|
||||||
|
Log.e(TAG, "failed to invoke saveInstanceState()", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean needUpdate() {
|
public boolean needUpdate() {
|
||||||
|
@@ -79,10 +79,13 @@ public class SpinnerPreference extends Preference {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(Parcelable state) {
|
protected void onRestoreInstanceState(Parcelable state) {
|
||||||
if (state == null || !state.getClass().equals(SavedState.class)) {
|
if (state == null || state == BaseSavedState.EMPTY_STATE) {
|
||||||
super.onRestoreInstanceState(state);
|
super.onRestoreInstanceState(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!(state instanceof SavedState)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SavedState savedState = (SavedState) state;
|
SavedState savedState = (SavedState) state;
|
||||||
super.onRestoreInstanceState(savedState.getSuperState());
|
super.onRestoreInstanceState(savedState.getSuperState());
|
||||||
mSavedSpinnerPosition = savedState.getSpinnerPosition();
|
mSavedSpinnerPosition = savedState.getSpinnerPosition();
|
||||||
|
@@ -74,6 +74,7 @@ public class AppNotificationSettings extends NotificationSettings {
|
|||||||
mControllers = new ArrayList<>();
|
mControllers = new ArrayList<>();
|
||||||
mControllers.add(new HeaderPreferenceController(context, this));
|
mControllers.add(new HeaderPreferenceController(context, this));
|
||||||
mControllers.add(new BlockPreferenceController(context, mDependentFieldListener, mBackend));
|
mControllers.add(new BlockPreferenceController(context, mDependentFieldListener, mBackend));
|
||||||
|
mControllers.add(new FullScreenIntentPermissionPreferenceController(context, mBackend));
|
||||||
mControllers.add(new BadgePreferenceController(context, mBackend));
|
mControllers.add(new BadgePreferenceController(context, mBackend));
|
||||||
mControllers.add(new AllowSoundPreferenceController(
|
mControllers.add(new AllowSoundPreferenceController(
|
||||||
context, mDependentFieldListener, mBackend));
|
context, mDependentFieldListener, mBackend));
|
||||||
|
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.Manifest.permission.USE_FULL_SCREEN_INTENT
|
||||||
|
import android.app.AppOpsManager
|
||||||
|
import android.app.AppOpsManager.OP_USE_FULL_SCREEN_INTENT
|
||||||
|
import android.content.AttributionSource
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET
|
||||||
|
import android.content.pm.PackageManager.GET_PERMISSIONS
|
||||||
|
import android.os.UserHandle
|
||||||
|
import android.permission.PermissionManager
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.Preference.OnPreferenceChangeListener
|
||||||
|
import com.android.settings.notification.NotificationBackend
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference
|
||||||
|
|
||||||
|
class FullScreenIntentPermissionPreferenceController(
|
||||||
|
context: Context,
|
||||||
|
backend: NotificationBackend
|
||||||
|
) : NotificationPreferenceController(context, backend), OnPreferenceChangeListener {
|
||||||
|
private val packageManager = mPm!!
|
||||||
|
private val permissionManager = context.getSystemService(PermissionManager::class.java)!!
|
||||||
|
private val appOpsManager = context.getSystemService(AppOpsManager::class.java)!!
|
||||||
|
|
||||||
|
private val packageName get() = mAppRow.pkg
|
||||||
|
private val uid get() = mAppRow.uid
|
||||||
|
private val userHandle get() = UserHandle.getUserHandleForUid(uid)
|
||||||
|
|
||||||
|
override fun getPreferenceKey() = KEY_FSI_PERMISSION
|
||||||
|
|
||||||
|
override fun isAvailable(): Boolean {
|
||||||
|
val inAppWidePreferences = mChannelGroup == null && mChannel == null
|
||||||
|
|
||||||
|
if (!inAppWidePreferences) {
|
||||||
|
Log.wtf(TAG, "Belongs only in app-wide notification preferences!")
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.isAvailable() && inAppWidePreferences && isPermissionRequested()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isIncludedInFilter() = false
|
||||||
|
|
||||||
|
override fun updateState(preference: Preference) {
|
||||||
|
check(KEY_FSI_PERMISSION.equals(preference.key))
|
||||||
|
check(preference is RestrictedSwitchPreference)
|
||||||
|
|
||||||
|
preference.setDisabledByAdmin(mAdmin)
|
||||||
|
preference.isEnabled = !preference.isDisabledByAdmin
|
||||||
|
preference.isChecked = isPermissionGranted()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPreferenceChange(preference: Preference, value: Any): Boolean {
|
||||||
|
check(KEY_FSI_PERMISSION.equals(preference.key))
|
||||||
|
check(preference is RestrictedSwitchPreference)
|
||||||
|
check(value is Boolean)
|
||||||
|
|
||||||
|
if (isPermissionGranted() != value) {
|
||||||
|
setPermissionGranted(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isPermissionRequested(): Boolean {
|
||||||
|
val packageInfo = packageManager.getPackageInfo(packageName, GET_PERMISSIONS)
|
||||||
|
|
||||||
|
for (requestedPermission in packageInfo.requestedPermissions) {
|
||||||
|
if (USE_FULL_SCREEN_INTENT.equals(requestedPermission)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isPermissionGranted(): Boolean {
|
||||||
|
val attributionSource = AttributionSource.Builder(uid).setPackageName(packageName).build()
|
||||||
|
|
||||||
|
val permissionResult =
|
||||||
|
permissionManager.checkPermissionForPreflight(USE_FULL_SCREEN_INTENT, attributionSource)
|
||||||
|
|
||||||
|
return (permissionResult == PermissionManager.PERMISSION_GRANTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setPermissionGranted(allowed: Boolean) {
|
||||||
|
val mode = if (allowed) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_ERRORED
|
||||||
|
appOpsManager.setUidMode(OP_USE_FULL_SCREEN_INTENT, uid, mode)
|
||||||
|
packageManager.updatePermissionFlags(
|
||||||
|
USE_FULL_SCREEN_INTENT,
|
||||||
|
packageName,
|
||||||
|
FLAG_PERMISSION_USER_SET,
|
||||||
|
FLAG_PERMISSION_USER_SET,
|
||||||
|
userHandle
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val KEY_FSI_PERMISSION = "fsi_permission"
|
||||||
|
const val TAG = "FsiPermPrefController"
|
||||||
|
}
|
||||||
|
}
|
@@ -183,7 +183,8 @@ public class NumberingSystemItemController extends BasePreferenceController {
|
|||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putString(RegionalPreferencesEntriesFragment.ARG_KEY_REGIONAL_PREFERENCE,
|
bundle.putString(RegionalPreferencesEntriesFragment.ARG_KEY_REGIONAL_PREFERENCE,
|
||||||
ARG_VALUE_NUMBERING_SYSTEM_SELECT);
|
ARG_VALUE_NUMBERING_SYSTEM_SELECT);
|
||||||
bundle.putString(KEY_SELECTED_LANGUAGE, updatedLocale.toLanguageTag());
|
bundle.putString(KEY_SELECTED_LANGUAGE,
|
||||||
|
updatedLocale != null ? updatedLocale.toLanguageTag() : "");
|
||||||
mParentFragment.setArguments(bundle);
|
mParentFragment.setArguments(bundle);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -194,13 +195,14 @@ public class NumberingSystemItemController extends BasePreferenceController {
|
|||||||
private Locale saveNumberingSystemToLocale(Locale targetLocale, String value) {
|
private Locale saveNumberingSystemToLocale(Locale targetLocale, String value) {
|
||||||
LocaleList localeList = LocalePicker.getLocales();
|
LocaleList localeList = LocalePicker.getLocales();
|
||||||
Locale[] locales = new Locale[localeList.size()];
|
Locale[] locales = new Locale[localeList.size()];
|
||||||
|
Locale updatedLocale = null;
|
||||||
for (int i = 0; i < localeList.size(); i++) {
|
for (int i = 0; i < localeList.size(); i++) {
|
||||||
Locale locale = localeList.get(i);
|
Locale locale = localeList.get(i);
|
||||||
if (targetLocale.equals(locale)) {
|
if (targetLocale.equals(locale)) {
|
||||||
if (value.equals(RegionalPreferencesDataUtils.DEFAULT_VALUE)) {
|
if (RegionalPreferencesDataUtils.DEFAULT_VALUE.equals(value)) {
|
||||||
value = null;
|
value = null;
|
||||||
}
|
}
|
||||||
Locale updatedLocale = new Locale.Builder()
|
updatedLocale = new Locale.Builder()
|
||||||
.setLocale(locale)
|
.setLocale(locale)
|
||||||
.setUnicodeLocaleKeyword(ExtensionTypes.NUMBERING_SYSTEM, value)
|
.setUnicodeLocaleKeyword(ExtensionTypes.NUMBERING_SYSTEM, value)
|
||||||
.build();
|
.build();
|
||||||
@@ -210,7 +212,7 @@ public class NumberingSystemItemController extends BasePreferenceController {
|
|||||||
locales[i] = localeList.get(i);
|
locales[i] = localeList.get(i);
|
||||||
}
|
}
|
||||||
LocalePicker.updateLocales(new LocaleList(locales));
|
LocalePicker.updateLocales(new LocaleList(locales));
|
||||||
return targetLocale;
|
return updatedLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getNumberingSystem(Locale locale) {
|
private static String getNumberingSystem(Locale locale) {
|
||||||
|
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* 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.devicelock;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.devicelock.DeviceLockManager;
|
||||||
|
import android.os.OutcomeReceiver;
|
||||||
|
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public final class DeviceLockPreferenceControllerTest {
|
||||||
|
|
||||||
|
private static final String TEST_PREFERENCE_KEY = "KEY";
|
||||||
|
private static final Map<Integer, String> TEST_KIOSK_APPS = Map.of(0, "test");
|
||||||
|
@Mock
|
||||||
|
private DeviceLockManager mDeviceLockManager;
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<OutcomeReceiver<Map<Integer, String>, Exception>>
|
||||||
|
mOutcomeReceiverArgumentCaptor;
|
||||||
|
private DeviceLockPreferenceController mController;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = ApplicationProvider.getApplicationContext();
|
||||||
|
Context context = spy(mContext);
|
||||||
|
when(context.getSystemService(DeviceLockManager.class)).thenReturn(mDeviceLockManager);
|
||||||
|
mController = new DeviceLockPreferenceController(context, TEST_PREFERENCE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_preferenceBecomesInvisibleIfNoKioskAppsPresent() {
|
||||||
|
Preference preference = new Preference(mContext, null, 0, 0);
|
||||||
|
preference.setVisible(true);
|
||||||
|
|
||||||
|
mController.updateState(preference);
|
||||||
|
|
||||||
|
verify(mDeviceLockManager).getKioskApps(any(), mOutcomeReceiverArgumentCaptor.capture());
|
||||||
|
OutcomeReceiver<Map<Integer, String>, Exception> outcomeReceiver =
|
||||||
|
mOutcomeReceiverArgumentCaptor.getValue();
|
||||||
|
|
||||||
|
outcomeReceiver.onResult(Collections.emptyMap());
|
||||||
|
assertThat(preference.isVisible()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_preferenceBecomesVisibleIfKioskAppsPresent() {
|
||||||
|
Preference preference = new Preference(mContext, null, 0, 0);
|
||||||
|
preference.setVisible(false);
|
||||||
|
|
||||||
|
mController.updateState(preference);
|
||||||
|
|
||||||
|
verify(mDeviceLockManager).getKioskApps(any(), mOutcomeReceiverArgumentCaptor.capture());
|
||||||
|
OutcomeReceiver<Map<Integer, String>, Exception> outcomeReceiver =
|
||||||
|
mOutcomeReceiverArgumentCaptor.getValue();
|
||||||
|
|
||||||
|
outcomeReceiver.onResult(TEST_KIOSK_APPS);
|
||||||
|
assertThat(preference.isVisible()).isTrue();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.Manifest.permission.USE_FULL_SCREEN_INTENT
|
||||||
|
import android.app.AppOpsManager
|
||||||
|
import android.app.AppOpsManager.MODE_ALLOWED
|
||||||
|
import android.app.AppOpsManager.MODE_ERRORED
|
||||||
|
import android.app.AppOpsManager.OP_USE_FULL_SCREEN_INTENT
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationChannelGroup
|
||||||
|
import android.app.NotificationManager.IMPORTANCE_UNSPECIFIED
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.PackageInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET
|
||||||
|
import android.content.pm.PackageManager.GET_PERMISSIONS
|
||||||
|
import android.os.UserHandle
|
||||||
|
import android.permission.PermissionManager.PERMISSION_GRANTED
|
||||||
|
import android.permission.PermissionManager.PERMISSION_HARD_DENIED
|
||||||
|
import android.permission.PermissionManager.PERMISSION_SOFT_DENIED
|
||||||
|
import android.permission.PermissionManager.PermissionResult
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceScreen
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import com.android.settings.notification.NotificationBackend
|
||||||
|
import com.android.settings.notification.NotificationBackend.AppRow
|
||||||
|
import com.android.settings.notification.app.FullScreenIntentPermissionPreferenceController.Companion.KEY_FSI_PERMISSION
|
||||||
|
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Answers
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.Mockito.spy
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.junit.MockitoJUnit
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import org.robolectric.shadows.ShadowApplicationPackageManager
|
||||||
|
import org.robolectric.shadows.ShadowPermissionChecker
|
||||||
|
import org.mockito.Mockito.`when` as whenever
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(shadows = [ShadowApplicationPackageManager::class])
|
||||||
|
class FullScreenIntentPermissionPreferenceControllerTest {
|
||||||
|
@JvmField
|
||||||
|
@Rule
|
||||||
|
val mockitoRule = MockitoJUnit.rule()!!
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var packageManager: PackageManager
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var appOpsManager: AppOpsManager
|
||||||
|
|
||||||
|
private lateinit var preference: RestrictedSwitchPreference
|
||||||
|
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private lateinit var screen: PreferenceScreen
|
||||||
|
|
||||||
|
private lateinit var controller: FullScreenIntentPermissionPreferenceController
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
val context = spy(ApplicationProvider.getApplicationContext<Context>())
|
||||||
|
|
||||||
|
whenever(context.packageManager).thenReturn(packageManager)
|
||||||
|
whenever(context.getSystemService(AppOpsManager::class.java)).thenReturn(appOpsManager)
|
||||||
|
|
||||||
|
preference = RestrictedSwitchPreference(context).apply { key = KEY_FSI_PERMISSION }
|
||||||
|
|
||||||
|
whenever(screen.findPreference<Preference>(KEY_FSI_PERMISSION)).thenReturn(preference)
|
||||||
|
|
||||||
|
controller = FullScreenIntentPermissionPreferenceController(
|
||||||
|
context,
|
||||||
|
mock(NotificationBackend::class.java)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsAvailable_notWhenPermissionNotRequested() {
|
||||||
|
setPermissionRequestedInManifest(requested = false)
|
||||||
|
initController()
|
||||||
|
|
||||||
|
assertFalse(controller.isAvailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsAvailable_notWhenOnChannelScreen() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
initController(channel = makeTestChannel())
|
||||||
|
|
||||||
|
assertFalse(controller.isAvailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsAvailable_notWhenOnGroupScreen() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
initController(group = makeTestGroup())
|
||||||
|
|
||||||
|
assertFalse(controller.isAvailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsAvailable_onAppScreenWhenRequested() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
initController()
|
||||||
|
|
||||||
|
assertTrue(controller.isAvailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsEnabled_notWhenDisabledByAdmin() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
initController(admin = makeTestAdmin())
|
||||||
|
|
||||||
|
controller.updateState(preference)
|
||||||
|
|
||||||
|
assertFalse(preference.isEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsEnabled_whenNotDisabledByAdmin() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
initController()
|
||||||
|
|
||||||
|
controller.updateState(preference)
|
||||||
|
|
||||||
|
assertTrue(preference.isEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsChecked_notWhenHardDenied() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
setPermissionResult(PERMISSION_HARD_DENIED)
|
||||||
|
initController()
|
||||||
|
|
||||||
|
controller.updateState(preference)
|
||||||
|
|
||||||
|
assertFalse(preference.isChecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsChecked_notWhenSoftDenied() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
setPermissionResult(PERMISSION_SOFT_DENIED)
|
||||||
|
initController()
|
||||||
|
|
||||||
|
controller.updateState(preference)
|
||||||
|
|
||||||
|
assertFalse(preference.isChecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIsChecked_whenGranted() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
setPermissionResult(PERMISSION_GRANTED)
|
||||||
|
initController()
|
||||||
|
|
||||||
|
controller.updateState(preference)
|
||||||
|
|
||||||
|
assertTrue(preference.isChecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOnPreferenceChange_whenHardDenied() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
setPermissionResult(PERMISSION_HARD_DENIED)
|
||||||
|
initController()
|
||||||
|
controller.displayPreference(screen)
|
||||||
|
controller.updateState(preference)
|
||||||
|
assertFalse(preference.isChecked)
|
||||||
|
|
||||||
|
setPreferenceChecked(true)
|
||||||
|
|
||||||
|
verifySetAppOpMode(MODE_ALLOWED)
|
||||||
|
verifySetPermissionUserSetFlag()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOnPreferenceChange_whenSoftDenied() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
setPermissionResult(PERMISSION_SOFT_DENIED)
|
||||||
|
initController()
|
||||||
|
controller.displayPreference(screen)
|
||||||
|
controller.updateState(preference)
|
||||||
|
assertFalse(preference.isChecked)
|
||||||
|
|
||||||
|
setPreferenceChecked(true)
|
||||||
|
|
||||||
|
verifySetAppOpMode(MODE_ALLOWED)
|
||||||
|
verifySetPermissionUserSetFlag()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOnPreferenceChange_whenGranted() {
|
||||||
|
setPermissionRequestedInManifest()
|
||||||
|
setPermissionResult(PERMISSION_GRANTED)
|
||||||
|
initController()
|
||||||
|
controller.displayPreference(screen)
|
||||||
|
controller.updateState(preference)
|
||||||
|
assertTrue(preference.isChecked)
|
||||||
|
|
||||||
|
setPreferenceChecked(false)
|
||||||
|
|
||||||
|
verifySetAppOpMode(MODE_ERRORED)
|
||||||
|
verifySetPermissionUserSetFlag()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setPermissionRequestedInManifest(
|
||||||
|
requested: Boolean = true
|
||||||
|
) {
|
||||||
|
whenever(packageManager.getPackageInfo(TEST_PACKAGE, GET_PERMISSIONS)).thenReturn(
|
||||||
|
PackageInfo().apply {
|
||||||
|
packageName = TEST_PACKAGE
|
||||||
|
applicationInfo = ApplicationInfo().apply { packageName = TEST_PACKAGE }
|
||||||
|
requestedPermissions = if (requested) arrayOf(USE_FULL_SCREEN_INTENT) else arrayOf()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setPermissionResult(@PermissionResult result: Int) {
|
||||||
|
ShadowPermissionChecker.setResult(TEST_PACKAGE, USE_FULL_SCREEN_INTENT, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setPreferenceChecked(checked: Boolean) {
|
||||||
|
preference.isChecked = checked
|
||||||
|
|
||||||
|
/* This shouldn't be necessary, but for some reason it's not called automatically when
|
||||||
|
isChecked is changed. */
|
||||||
|
controller.onPreferenceChange(preference, checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifySetAppOpMode(@AppOpsManager.Mode expectedMode: Int) {
|
||||||
|
verify(appOpsManager).setUidMode(OP_USE_FULL_SCREEN_INTENT, TEST_UID, expectedMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifySetPermissionUserSetFlag() {
|
||||||
|
verify(packageManager).updatePermissionFlags(
|
||||||
|
USE_FULL_SCREEN_INTENT,
|
||||||
|
TEST_PACKAGE,
|
||||||
|
FLAG_PERMISSION_USER_SET,
|
||||||
|
FLAG_PERMISSION_USER_SET,
|
||||||
|
makeTestUserHandle()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initController(
|
||||||
|
channel: NotificationChannel? = null,
|
||||||
|
group: NotificationChannelGroup? = null,
|
||||||
|
admin: EnforcedAdmin? = null
|
||||||
|
) {
|
||||||
|
controller.onResume(
|
||||||
|
makeTestAppRow(),
|
||||||
|
channel,
|
||||||
|
group,
|
||||||
|
/* conversationDrawable = */null,
|
||||||
|
/* conversationInfo = */null,
|
||||||
|
admin,
|
||||||
|
/* preferenceFilter = */null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeTestChannel() =
|
||||||
|
NotificationChannel("test_channel_id", "Test Channel Name", IMPORTANCE_UNSPECIFIED)
|
||||||
|
|
||||||
|
private fun makeTestGroup() = NotificationChannelGroup("test_group_id", "Test Group Name")
|
||||||
|
|
||||||
|
private fun makeTestAppRow() = AppRow().apply { pkg = TEST_PACKAGE; uid = TEST_UID }
|
||||||
|
|
||||||
|
private fun makeTestUserHandle() = UserHandle.getUserHandleForUid(TEST_UID)
|
||||||
|
|
||||||
|
private fun makeTestAdmin() = mock(EnforcedAdmin::class.java)
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val TEST_PACKAGE = "test.package.name"
|
||||||
|
const val TEST_UID = 12345
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.regionalpreferences;
|
package com.android.settings.regionalpreferences;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -34,6 +36,7 @@ import androidx.preference.PreferenceScreen;
|
|||||||
import androidx.test.annotation.UiThreadTest;
|
import androidx.test.annotation.UiThreadTest;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import com.android.internal.app.LocalePicker;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.widget.TickButtonPreference;
|
import com.android.settings.widget.TickButtonPreference;
|
||||||
|
|
||||||
@@ -68,6 +71,7 @@ public class NumberingSystemItemControllerTest {
|
|||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
LocaleList.setDefault(mCacheLocale);
|
LocaleList.setDefault(mCacheLocale);
|
||||||
|
LocalePicker.updateLocales(mCacheLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -122,6 +126,31 @@ public class NumberingSystemItemControllerTest {
|
|||||||
"test_key");
|
"test_key");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@UiThreadTest
|
||||||
|
public void handlePreferenceTreeClick_numbersSelect_numberingSystemIsUpdated() {
|
||||||
|
LocalePicker.updateLocales(LocaleList.forLanguageTags("en-US,zh-TW,ar-BH"));
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString(RegionalPreferencesEntriesFragment.ARG_KEY_REGIONAL_PREFERENCE,
|
||||||
|
NumberingSystemItemController.ARG_VALUE_NUMBERING_SYSTEM_SELECT);
|
||||||
|
bundle.putString(
|
||||||
|
NumberingSystemItemController.KEY_SELECTED_LANGUAGE, "ar-BH");
|
||||||
|
TickButtonPreference defaultPreference = new TickButtonPreference(mApplicationContext);
|
||||||
|
TickButtonPreference numberPreference = new TickButtonPreference(mApplicationContext);
|
||||||
|
defaultPreference.setKey("default");
|
||||||
|
numberPreference.setKey("latn");
|
||||||
|
mPreferenceScreen.addPreference(defaultPreference);
|
||||||
|
mPreferenceScreen.addPreference(numberPreference);
|
||||||
|
mController = new NumberingSystemItemController(mApplicationContext, bundle);
|
||||||
|
mController.setParentFragment(mFragment);
|
||||||
|
mController.displayPreference(mPreferenceScreen);
|
||||||
|
|
||||||
|
mController.handlePreferenceTreeClick(numberPreference);
|
||||||
|
|
||||||
|
assertThat(LocalePicker.getLocales().toLanguageTags()).contains(
|
||||||
|
"en-US,zh-TW,ar-BH-u-nu-latn");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@UiThreadTest
|
@UiThreadTest
|
||||||
public void displayPreference_languageOptAndHas2LocaleWithSingleNu_showNothing() {
|
public void displayPreference_languageOptAndHas2LocaleWithSingleNu_showNothing() {
|
||||||
|
Reference in New Issue
Block a user