Snap for 12173239 from f2d6fe9e32 to 24Q4-release

Change-Id: I993b777f5a9e84bf1aa9be97af904dcf8d42ba85
This commit is contained in:
Android Build Coastguard Worker
2024-08-02 01:26:20 +00:00
36 changed files with 725 additions and 102 deletions

View File

@@ -51,6 +51,16 @@ flag {
bug: "301198830"
}
flag {
name: "fix_a11y_settings_search"
namespace: "accessibility"
description: "Fix the a11y related search items in Settings app"
bug: "333437173"
metadata {
purpose: PURPOSE_BUGFIX
}
}
flag {
name: "hide_magnification_always_on_toggle_when_window_mode_only"
namespace: "accessibility"

View File

@@ -26,7 +26,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:textAlignment="viewStart"/>
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorPrimary"/>
<EditText
android:id="@+id/broadcast_edit_text"
android:layout_width="match_parent"
@@ -34,11 +35,4 @@
android:maxLength="16"
android:minHeight="48dp"
android:textAlignment="viewStart"/>
<TextView
android:id="@+id/broadcast_error_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
style="@style/TextAppearance.ErrorText"
android:visibility="invisible"/>
</LinearLayout>

View File

@@ -5456,9 +5456,9 @@
<!-- Title for the preference to show a tile for a particular feature in the Quick Settings pane. [CHAR LIMIT=NONE] -->
<string name="enable_quick_setting">Show in Quick Settings</string>
<!-- Title shown for deuteranomaly (red-green color blindness) [CHAR LIMIT=45] -->
<string name="daltonizer_mode_deuteranomaly_title">Red-green</string>
<string name="daltonizer_mode_deuteranomaly_title">Red-green, green weak</string>
<!-- Title shown for protanomaly (red-green color blindness) [CHAR LIMIT=45] -->
<string name="daltonizer_mode_protanomaly_title">Red-green</string>
<string name="daltonizer_mode_protanomaly_title">Red-green, red weak</string>
<!-- Title shown for tritanomaly (blue-yellow color blindness) [CHAR LIMIT=45] -->
<string name="daltonizer_mode_tritanomaly_title">Blue-yellow</string>
<!-- Title shown for grayscale [CHAR LIMIT=45] -->
@@ -5468,9 +5468,9 @@
<!-- The summary shown for settings that controls color correction intensity/saturation level. It is shown when intensity slider is grayed out and is not usable and it explains why it's not usable to the user. [CHAR LIMIT=NONE] -->
<string name="daltonizer_saturation_unavailable_summary">Unavailable for grayscale mode or when color correction is disabled</string>
<!-- Summary shown for deuteranomaly (red-green color blindness) [CHAR LIMIT=45] -->
<string name="daltonizer_mode_deuteranomaly_summary">Green weak, deuteranomaly</string>
<string name="daltonizer_mode_deuteranomaly_summary">Deuteranomaly</string>
<!-- Summary shown for protanomaly (red-green color blindness) [CHAR LIMIT=45] -->
<string name="daltonizer_mode_protanomaly_summary">Red weak, protanomaly</string>
<string name="daltonizer_mode_protanomaly_summary">Protanomaly</string>
<!-- Summary shown for tritanomaly (blue-yellow color blindness) [CHAR LIMIT=45] -->
<string name="daltonizer_mode_tritanomaly_summary">Tritanomaly</string>

View File

@@ -507,6 +507,11 @@
android:title="@string/show_key_presses"
android:summary="@string/show_key_presses_summary" />
<SwitchPreference
android:key="touchpad_visualizer"
android:title="@string/touchpad_visualizer"
android:summary="@string/touchpad_visualizer_summary" />
</PreferenceCategory>
<PreferenceCategory

View File

@@ -293,10 +293,10 @@
settings:controller=
"com.android.settings.network.telephony.NullAlgorithmsPreferenceController"/>
<!-- Settings search is handled by NrAdvancedCallingSearchItem. -->
<com.android.settings.spa.preference.ComposePreference
android:key="nr_advanced_calling"
android:title="@string/nr_advanced_calling_title"
settings:keywords="@string/keywords_nr_advanced_calling"
settings:searchable="false"
settings:controller="com.android.settings.network.telephony.NrAdvancedCallingPreferenceController"/>
</PreferenceCategory>

View File

@@ -613,7 +613,7 @@ public class AccessibilitySettings extends DashboardFragment implements
}
}
private boolean isAnyHardKeyboardsExist() {
static boolean isAnyHardKeyboardsExist() {
for (int deviceId : InputDevice.getDeviceIds()) {
final InputDevice device = InputDevice.getDevice(deviceId);
if (device != null && !device.isVirtual() && device.isFullKeyboard()) {

View File

@@ -19,16 +19,21 @@ package com.android.settings.accessibility;
import android.content.Context;
import android.hardware.input.InputSettings;
import android.util.Log;
import androidx.annotation.NonNull;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.inputmethod.PhysicalKeyboardFragment;
import java.util.List;
/**
* A toggle preference controller for keyboard bounce key.
*/
public class KeyboardBounceKeyPreferenceController extends TogglePreferenceController {
private static final String TAG = "BounceKeyPrefController";
static final String PREF_KEY = "toggle_keyboard_bounce_keys";
public KeyboardBounceKeyPreferenceController(Context context, String preferenceKey) {
@@ -58,4 +63,17 @@ public class KeyboardBounceKeyPreferenceController extends TogglePreferenceContr
public int getSliceHighlightMenuRes() {
return R.string.menu_key_accessibility;
}
@Override
public void updateNonIndexableKeys(@NonNull List<String> keys) {
super.updateNonIndexableKeys(keys);
if (Flags.fixA11ySettingsSearch() && !AccessibilitySettings.isAnyHardKeyboardsExist()) {
if (keys.contains(getPreferenceKey())) {
Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list.");
return;
}
keys.add(getPreferenceKey());
}
}
}

View File

@@ -19,15 +19,21 @@ package com.android.settings.accessibility;
import android.content.Context;
import android.hardware.input.InputSettings;
import android.util.Log;
import androidx.annotation.NonNull;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.inputmethod.PhysicalKeyboardFragment;
import java.util.List;
/**
* A toggle preference controller for keyboard slow key.
*/
public class KeyboardSlowKeyPreferenceController extends TogglePreferenceController {
private static final String TAG = "SlowKeyPrefController";
static final String PREF_KEY = "toggle_keyboard_slow_keys";
@@ -58,4 +64,17 @@ public class KeyboardSlowKeyPreferenceController extends TogglePreferenceControl
public int getSliceHighlightMenuRes() {
return R.string.menu_key_accessibility;
}
@Override
public void updateNonIndexableKeys(@NonNull List<String> keys) {
super.updateNonIndexableKeys(keys);
if (Flags.fixA11ySettingsSearch() && !AccessibilitySettings.isAnyHardKeyboardsExist()) {
if (keys.contains(getPreferenceKey())) {
Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list.");
return;
}
keys.add(getPreferenceKey());
}
}
}

View File

@@ -19,15 +19,20 @@ package com.android.settings.accessibility;
import android.content.Context;
import android.hardware.input.InputSettings;
import android.util.Log;
import androidx.annotation.NonNull;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import java.util.List;
/**
* A toggle preference controller for keyboard sticky key.
*/
public class KeyboardStickyKeyPreferenceController extends TogglePreferenceController {
private static final String TAG = "StickyKeyPrefController";
static final String PREF_KEY = "toggle_keyboard_sticky_keys";
public KeyboardStickyKeyPreferenceController(Context context, String preferenceKey) {
@@ -55,4 +60,17 @@ public class KeyboardStickyKeyPreferenceController extends TogglePreferenceContr
public int getSliceHighlightMenuRes() {
return R.string.menu_key_accessibility;
}
@Override
public void updateNonIndexableKeys(@NonNull List<String> keys) {
super.updateNonIndexableKeys(keys);
if (Flags.fixA11ySettingsSearch() && !AccessibilitySettings.isAnyHardKeyboardsExist()) {
if (keys.contains(getPreferenceKey())) {
Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list.");
return;
}
keys.add(getPreferenceKey());
}
}
}

View File

@@ -132,7 +132,7 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh
new Thread(() -> {
try {
mIsSatelliteOn.set(mSatelliteRepository.requestIsEnabled(
mIsSatelliteOn.set(mSatelliteRepository.requestIsSessionStarted(
Executors.newSingleThreadExecutor()).get(3000, TimeUnit.MILLISECONDS));
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Log.e(TAG, "Error to get satellite status : " + e);

View File

@@ -79,7 +79,7 @@ public class BluetoothPairingDetail extends BluetoothDevicePairingDetailBase imp
boolean isSatelliteOn = true;
try {
isSatelliteOn =
satelliteRepository.requestIsEnabled(
satelliteRepository.requestIsSessionStarted(
Executors.newSingleThreadExecutor()).get(3000, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Log.e(TAG, "Error to get satellite status : " + e);

View File

@@ -30,6 +30,9 @@ import android.content.IntentFilter;
import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
@@ -284,6 +287,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
: mProfileManager.getLeAudioBroadcastAssistantProfile();
mExecutor = Executors.newSingleThreadExecutor();
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
mSwitchBar.getRootView().setAccessibilityDelegate(new MainSwitchAccessibilityDelegate());
}
@Override
@@ -564,4 +568,19 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
}
});
}
private static final class MainSwitchAccessibilityDelegate extends View.AccessibilityDelegate {
@Override
public boolean onRequestSendAccessibilityEvent(
@NonNull ViewGroup host, @NonNull View view, @NonNull AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
&& (event.getContentChangeTypes()
& AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED)
!= 0) {
Log.d(TAG, "Skip accessibility event for CONTENT_CHANGE_TYPE_ENABLED");
return false;
}
return super.onRequestSendAccessibilityEvent(host, view, event);
}
}
}

View File

@@ -43,24 +43,13 @@ class AudioStreamPreference extends TwoTargetPreference {
* Update preference UI based on connection status
*
* @param isConnected Is this stream connected
* @param summary Summary text
* @param onPreferenceClickListener Click listener for the preference
*/
void setIsConnected(
boolean isConnected,
String summary,
@Nullable OnPreferenceClickListener onPreferenceClickListener) {
if (mIsConnected == isConnected
&& getSummary() == summary
&& getOnPreferenceClickListener() == onPreferenceClickListener) {
// Nothing to update.
return;
}
void setIsConnected(boolean isConnected) {
if (mIsConnected != isConnected) {
mIsConnected = isConnected;
setSummary(summary);
setOnPreferenceClickListener(onPreferenceClickListener);
notifyChanged();
}
}
@VisibleForTesting
AudioStreamPreference(Context context, @Nullable AttributeSet attrs) {

View File

@@ -16,8 +16,12 @@
package com.android.settings.connecteddevice.audiosharing.audiostreams;
import static android.text.Spanned.SPAN_EXCLUSIVE_INCLUSIVE;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -26,6 +30,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.utils.ThreadUtils;
@@ -68,15 +73,31 @@ class AudioStreamStateHandler {
// Update UI
ThreadUtils.postOnMainThread(
() ->
() -> {
String summary =
getSummary() != EMPTY_STRING_RES
? preference.getContext().getString(getSummary())
: "";
if (newState
== AudioStreamsProgressCategoryController.AudioStreamState
.ADD_SOURCE_BAD_CODE) {
SpannableString summarySpan = new SpannableString(summary);
int colorError = Utils.getColorErrorDefaultColor(preference.getContext());
summarySpan.setSpan(
new ForegroundColorSpan(colorError),
0,
summary.length(),
SPAN_EXCLUSIVE_INCLUSIVE);
preference.setSummary(summarySpan);
} else {
preference.setSummary(summary);
}
preference.setIsConnected(
newState
== AudioStreamsProgressCategoryController.AudioStreamState
.SOURCE_ADDED,
getSummary() != EMPTY_STRING_RES
? preference.getContext().getString(getSummary())
: "",
getOnClickListener(controller)));
.SOURCE_ADDED);
preference.setOnPreferenceClickListener(getOnClickListener(controller));
});
}
/**

View File

@@ -16,6 +16,7 @@
package com.android.settings.development;
import static android.app.Activity.RESULT_OK;
import static android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED;
import static android.service.quicksettings.TileService.ACTION_QS_TILE_PREFERENCES;
import static android.view.flags.Flags.sensitiveContentAppProtectionApi;
@@ -100,11 +101,13 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
NfcRebootDialog.OnNfcRebootDialogConfirmedListener, BluetoothSnoopLogHost {
private static final String TAG = "DevSettingsDashboard";
@VisibleForTesting static final int REQUEST_BIOMETRIC_PROMPT = 100;
private final BluetoothA2dpConfigStore mBluetoothA2dpConfigStore =
new BluetoothA2dpConfigStore();
private boolean mIsAvailable = true;
private boolean mIsBiometricsAuthenticated;
private SettingsMainSwitchBar mSwitchBar;
private DevelopmentSwitchBarController mSwitchBarController;
private List<AbstractPreferenceController> mPreferenceControllers = new ArrayList<>();
@@ -216,6 +219,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
public void onStart() {
super.onStart();
final ContentResolver cr = getContext().getContentResolver();
mIsBiometricsAuthenticated = false;
cr.registerContentObserver(mDevelopEnabled, false, mDeveloperSettingsObserver);
// Restore UI state based on whether developer options is enabled
@@ -360,7 +364,18 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext());
if (isChecked != developmentEnabledState) {
if (isChecked) {
final int userId = getContext().getUserId();
if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getContext(),
mIsBiometricsAuthenticated,
false /* biometricsAuthenticationRequested */, userId)) {
mSwitchBar.setChecked(false);
Utils.launchBiometricPromptForMandatoryBiometrics(this,
REQUEST_BIOMETRIC_PROMPT, userId, false /* hideBackground */);
} else {
//Reset biometrics once enable dialog is shown
mIsBiometricsAuthenticated = false;
EnableDevelopmentSettingWarningDialog.show(this /* host */);
}
} else {
final BluetoothA2dpHwOffloadPreferenceController a2dpController =
getDevelopmentOptionsController(
@@ -534,6 +549,12 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
boolean handledResult = false;
if (requestCode == REQUEST_BIOMETRIC_PROMPT) {
if (resultCode == RESULT_OK) {
mIsBiometricsAuthenticated = true;
mSwitchBar.setChecked(true);
}
}
for (AbstractPreferenceController controller : mPreferenceControllers) {
if (controller instanceof OnActivityResultListener) {
// We do not break early because it is possible for multiple controllers to
@@ -715,6 +736,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new ShowTapsPreferenceController(context));
controllers.add(new PointerLocationPreferenceController(context));
controllers.add(new ShowKeyPressesPreferenceController(context));
controllers.add(new TouchpadVisualizerPreferenceController(context));
controllers.add(new ShowSurfaceUpdatesPreferenceController(context));
controllers.add(new ShowLayoutBoundsPreferenceController(context));
controllers.add(new ShowHdrSdrRatioPreferenceController(context));

View File

@@ -16,3 +16,6 @@ per-file DesktopModePreferenceController.java=file:platform/frameworks/base:/lib
# ADB
per-file Adb*=set noparent
per-file Adb*=file:platform/packages/modules/adb:/OWNERS
#TouchpadVisualizerPreferenceController
per-file TouchpadVisualizerPreferenceController.java=file:platform/frameworks/base:/INPUT_OWNERS

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import android.content.Context;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.hardware.input.InputSettings;
/** PreferenceController that controls the "Touchpad visualizer" developer option. */
public class TouchpadVisualizerPreferenceController extends
DeveloperOptionsPreferenceController implements
Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
private static final String TOUCHPAD_VISUALIZER_KEY = "touchpad_visualizer";
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
@VisibleForTesting
static final int SETTING_VALUE_OFF = 0;
public TouchpadVisualizerPreferenceController(@NonNull Context context) {
super(context);
}
@Override
public @NonNull String getPreferenceKey() {
return TOUCHPAD_VISUALIZER_KEY;
}
@Override
public boolean isAvailable(){
return InputSettings.isTouchpadVisualizerFeatureFlagEnabled();
}
@Override
public boolean onPreferenceChange(@NonNull Preference preference, @Nullable Object newValue) {
final boolean isEnabled = newValue != null ? (Boolean) newValue : false;
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.TOUCHPAD_VISUALIZER,
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
return true;
}
@Override
public void updateState(@NonNull Preference preference) {
int touchpadVisualizer = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.TOUCHPAD_VISUALIZER, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(touchpadVisualizer != SETTING_VALUE_OFF);
}
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
Settings.System.putInt(mContext.getContentResolver(), Settings.System.TOUCHPAD_VISUALIZER,
SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(false);
}
}

View File

@@ -55,6 +55,7 @@ public class BuildNumberPreferenceController extends BasePreferenceController im
static final int TAPS_TO_BE_A_DEVELOPER = 7;
static final int REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF = 100;
static final int REQUEST_IDENTITY_CHECK_FOR_DEV_PREF = 101;
private Activity mActivity;
private InstrumentedPreferenceFragment mFragment;
@@ -217,10 +218,24 @@ public class BuildNumberPreferenceController extends BasePreferenceController im
* @return if activity result is handled.
*/
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF) {
if (requestCode != REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF
&& requestCode != REQUEST_IDENTITY_CHECK_FOR_DEV_PREF) {
return false;
}
if (resultCode == Activity.RESULT_OK) {
if (requestCode == REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF
&& resultCode == Activity.RESULT_OK) {
final int userId = mContext.getUserId();
if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
false /* biometricsSuccessfullyAuthenticated */,
false /* biometricsAuthenticationRequested */,
userId)) {
Utils.launchBiometricPromptForMandatoryBiometrics(mFragment,
REQUEST_IDENTITY_CHECK_FOR_DEV_PREF, userId, false /* hideBackground */);
} else {
enableDevelopmentSettings();
}
} else if (requestCode == REQUEST_IDENTITY_CHECK_FOR_DEV_PREF
&& resultCode == Activity.RESULT_OK) {
enableDevelopmentSettings();
}
mProcessingLastDevHit = false;

View File

@@ -162,7 +162,8 @@ public class AirplaneModePreferenceController extends TogglePreferenceController
public void onResume() {
try {
mIsSatelliteOn.set(
mSatelliteRepository.requestIsEnabled(Executors.newSingleThreadExecutor())
mSatelliteRepository
.requestIsSessionStarted(Executors.newSingleThreadExecutor())
.get(2000, TimeUnit.MILLISECONDS));
} catch (ExecutionException | TimeoutException | InterruptedException e) {
Log.e(TAG, "Error to get satellite status : " + e);

View File

@@ -25,6 +25,7 @@ import androidx.annotation.VisibleForTesting
import androidx.concurrent.futures.CallbackToFutureAdapter
import com.google.common.util.concurrent.Futures.immediateFuture
import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.Executor
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
@@ -32,7 +33,6 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOf
import java.util.concurrent.Executor
import kotlinx.coroutines.flow.flowOn
/**
@@ -58,6 +58,7 @@ class SatelliteRepository(
}
return CallbackToFutureAdapter.getFuture { completer ->
try {
satelliteManager.requestIsEnabled(executor,
object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> {
override fun onResult(result: Boolean) {
@@ -72,6 +73,11 @@ class SatelliteRepository(
}
})
"requestIsEnabled"
} catch (e: IllegalStateException) {
Log.w(TAG, "IllegalStateException $e")
completer.set(false)
}
}
}
@@ -96,14 +102,21 @@ class SatelliteRepository(
val callback = object : SatelliteModemStateCallback {
override fun onSatelliteModemStateChanged(state: Int) {
val isSessionStarted = isSatelliteSessionStarted(state)
Log.i(TAG, "Satellite modem state changed: state=$state"
+ ", isSessionStarted=$isSessionStarted")
Log.i(
TAG, "Satellite modem state changed: state=$state"
+ ", isSessionStarted=$isSessionStarted"
)
completer.set(isSessionStarted)
satelliteManager.unregisterForModemStateChanged(this)
}
}
val registerResult = satelliteManager.registerForModemStateChanged(executor, callback)
var registerResult = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN
try {
registerResult = satelliteManager.registerForModemStateChanged(executor, callback)
} catch (e: IllegalStateException) {
Log.w(TAG, "IllegalStateException $e")
}
if (registerResult != SatelliteManager.SATELLITE_RESULT_SUCCESS) {
Log.w(TAG, "Failed to register for satellite modem state change: $registerResult")
completer.set(false)
@@ -132,15 +145,21 @@ class SatelliteRepository(
return callbackFlow {
val callback = SatelliteModemStateCallback { state ->
val isSessionStarted = isSatelliteSessionStarted(state)
Log.i(TAG, "Satellite modem state changed: state=$state"
+ ", isSessionStarted=$isSessionStarted")
Log.i(
TAG, "Satellite modem state changed: state=$state"
+ ", isSessionStarted=$isSessionStarted"
)
trySend(isSessionStarted)
}
val registerResult = satelliteManager.registerForModemStateChanged(
var registerResult: Int = SatelliteManager.SATELLITE_RESULT_ERROR
try {
registerResult = satelliteManager.registerForModemStateChanged(
defaultDispatcher.asExecutor(),
callback
)
} catch (e: IllegalStateException) {
Log.w(TAG, "IllegalStateException $e")
}
if (registerResult != SatelliteManager.SATELLITE_RESULT_SUCCESS) {
// If the registration failed (e.g., device doesn't support satellite),
@@ -150,7 +169,13 @@ class SatelliteRepository(
trySend(false)
}
awaitClose { satelliteManager.unregisterForModemStateChanged(callback) }
awaitClose {
try {
satelliteManager.unregisterForModemStateChanged(callback)
} catch (e: IllegalStateException) {
Log.w(TAG, "IllegalStateException $e")
}
}
}.flowOn(Dispatchers.Default)
}

View File

@@ -22,6 +22,7 @@ import android.telephony.SubscriptionInfo
import com.android.settings.R
import com.android.settings.network.SubscriptionUtil
import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem
import com.android.settings.network.telephony.NrAdvancedCallingPreferenceController.Companion.NrAdvancedCallingSearchItem
import com.android.settings.spa.SpaSearchLanding.BundleValue
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey
@@ -41,6 +42,9 @@ class MobileNetworkSettingsSearchIndex(
val title: String
val keywords: String?
get() = null
fun isAvailable(subId: Int): Boolean
}
@@ -89,6 +93,7 @@ class MobileNetworkSettingsSearchIndex(
context = context,
spaSearchLandingKey = key,
itemTitle = searchItem.title,
keywords = searchItem.keywords,
indexableClass = MobileNetworkSettings::class.java,
pageTitle = "$simsTitle > ${subInfo.displayName}",
)
@@ -107,6 +112,7 @@ class MobileNetworkSettingsSearchIndex(
fun createSearchItems(context: Context): List<MobileNetworkSettingsSearchItem> =
listOf(
MmsMessageSearchItem(context),
NrAdvancedCallingSearchItem(context),
)
}
}

View File

@@ -25,6 +25,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
import com.android.settings.spa.preference.ComposePreferenceController
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
@@ -41,6 +42,7 @@ class NrAdvancedCallingPreferenceController @JvmOverloads constructor(
) : ComposePreferenceController(context, key) {
private var subId: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
private var repository: VoNrRepository? = null
private val searchItem = NrAdvancedCallingSearchItem(context)
/** Initial this PreferenceController. */
@JvmOverloads
@@ -50,7 +52,7 @@ class NrAdvancedCallingPreferenceController @JvmOverloads constructor(
}
override fun getAvailabilityStatus() =
if (repository?.isVoNrAvailable() == true) AVAILABLE else CONDITIONALLY_UNAVAILABLE
if (searchItem.isAvailable(subId)) AVAILABLE else CONDITIONALLY_UNAVAILABLE
@Composable
override fun Content() {
@@ -73,4 +75,16 @@ class NrAdvancedCallingPreferenceController @JvmOverloads constructor(
}
})
}
companion object {
class NrAdvancedCallingSearchItem(private val context: Context) :
MobileNetworkSettingsSearchItem {
override val key = "nr_advanced_calling"
override val title: String = context.getString(R.string.nr_advanced_calling_title)
override val keywords: String = context.getString(R.string.keywords_nr_advanced_calling)
override fun isAvailable(subId: Int): Boolean =
VoNrRepository(context, subId).isVoNrAvailable()
}
}
}

View File

@@ -93,10 +93,12 @@ class SpaSearchRepository(
itemTitle: String,
indexableClass: Class<*>,
pageTitle: String,
keywords: String? = null,
) =
SearchIndexableRaw(context).apply {
key = spaSearchLandingKey.toByteString().toStringUtf8()
title = itemTitle
this.keywords = keywords
intentAction = SEARCH_LANDING_ACTION
intentTargetClass = SpaSearchLandingActivity::class.qualifiedName
packageName = context.packageName

View File

@@ -139,7 +139,8 @@ public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListene
// Refresh satellite mode status.
try {
mIsSatelliteOn.set(
mSatelliteRepository.requestIsEnabled(Executors.newSingleThreadExecutor())
mSatelliteRepository
.requestIsSessionStarted(Executors.newSingleThreadExecutor())
.get(2000, TimeUnit.MILLISECONDS));
} catch (ExecutionException | TimeoutException | InterruptedException e) {
Log.e(TAG, "Error to get satellite status : " + e);

View File

@@ -431,7 +431,7 @@ public class WifiSlice implements CustomSliceable {
boolean isSatelliteOn = false;
try {
isSatelliteOn =
satelliteRepository.requestIsEnabled(Executors.newSingleThreadExecutor())
satelliteRepository.requestIsSessionStarted(Executors.newSingleThreadExecutor())
.get(2000, TimeUnit.MILLISECONDS);
} catch (ExecutionException | TimeoutException | InterruptedException e) {
Log.e(TAG, "Error to get satellite status : " + e);

View File

@@ -25,6 +25,8 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
@@ -34,19 +36,24 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class KeyboardBounceKeyPreferenceControllerTest {
private static final String KEY_ACCESSIBILITY_BOUNCE_KEYS =
Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS;
private static final int UNKNOWN = -1;
@Rule
public final SetFlagsRule mSetFlagRule = new SetFlagsRule();
private final Context mContext = ApplicationProvider.getApplicationContext();
private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
private final KeyboardBounceKeyPreferenceController mController =
@@ -131,4 +138,26 @@ public class KeyboardBounceKeyPreferenceControllerTest {
mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS,
UNKNOWN)).isNotEqualTo(OFF);
}
@Test
@EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
public void updateNonIndexableKeys_physicalKeyboardExists_returnEmptyList() {
Assume.assumeTrue(AccessibilitySettings.isAnyHardKeyboardsExist());
List<String> nonIndexableKeys = new ArrayList<>();
mController.updateNonIndexableKeys(nonIndexableKeys);
assertThat(nonIndexableKeys).isEmpty();
}
@Test
@EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
public void updateNonIndexableKeys_noPhysicalKeyboard_returnPreKey() {
Assume.assumeFalse(AccessibilitySettings.isAnyHardKeyboardsExist());
List<String> nonIndexableKeys = new ArrayList<>();
mController.updateNonIndexableKeys(nonIndexableKeys);
assertThat(nonIndexableKeys).contains(mController.getPreferenceKey());
}
}

View File

@@ -25,6 +25,8 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
@@ -34,19 +36,24 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class KeyboardSlowKeyPreferenceControllerTest {
private static final String KEY_ACCESSIBILITY_SLOW_KEYS =
Settings.Secure.ACCESSIBILITY_SLOW_KEYS;
private static final int UNKNOWN = -1;
@Rule
public final SetFlagsRule mSetFlagRule = new SetFlagsRule();
private final Context mContext = ApplicationProvider.getApplicationContext();
private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
private final KeyboardSlowKeyPreferenceController mController =
@@ -131,4 +138,26 @@ public class KeyboardSlowKeyPreferenceControllerTest {
mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, UNKNOWN)).isNotEqualTo(
OFF);
}
@Test
@EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
public void updateNonIndexableKeys_physicalKeyboardExists_returnEmptyList() {
Assume.assumeTrue(AccessibilitySettings.isAnyHardKeyboardsExist());
List<String> nonIndexableKeys = new ArrayList<>();
mController.updateNonIndexableKeys(nonIndexableKeys);
assertThat(nonIndexableKeys).isEmpty();
}
@Test
@EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
public void updateNonIndexableKeys_noPhysicalKeyboard_returnPreKey() {
Assume.assumeFalse(AccessibilitySettings.isAnyHardKeyboardsExist());
List<String> nonIndexableKeys = new ArrayList<>();
mController.updateNonIndexableKeys(nonIndexableKeys);
assertThat(nonIndexableKeys).contains(mController.getPreferenceKey());
}
}

View File

@@ -25,6 +25,8 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
@@ -34,19 +36,24 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class KeyboardStickyKeyPreferenceControllerTest {
private static final String KEY_ACCESSIBILITY_STICKY_KEYS =
Settings.Secure.ACCESSIBILITY_STICKY_KEYS;
private static final int UNKNOWN = -1;
@Rule
public final SetFlagsRule mSetFlagRule = new SetFlagsRule();
private final Context mContext = ApplicationProvider.getApplicationContext();
private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
private final KeyboardStickyKeyPreferenceController mController =
@@ -129,4 +136,26 @@ public class KeyboardStickyKeyPreferenceControllerTest {
assertThat(Settings.Secure.getInt(
mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, UNKNOWN)).isEqualTo(ON);
}
@Test
@EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
public void updateNonIndexableKeys_physicalKeyboardExists_returnEmptyList() {
Assume.assumeTrue(AccessibilitySettings.isAnyHardKeyboardsExist());
List<String> nonIndexableKeys = new ArrayList<>();
mController.updateNonIndexableKeys(nonIndexableKeys);
assertThat(nonIndexableKeys).isEmpty();
}
@Test
@EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
public void updateNonIndexableKeys_noPhysicalKeyboard_returnPreKey() {
Assume.assumeFalse(AccessibilitySettings.isAnyHardKeyboardsExist());
List<String> nonIndexableKeys = new ArrayList<>();
mController.updateNonIndexableKeys(nonIndexableKeys);
assertThat(nonIndexableKeys).contains(mController.getPreferenceKey());
}
}

View File

@@ -21,10 +21,12 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import androidx.test.core.app.ApplicationProvider;
@@ -52,6 +54,7 @@ public class AudioSharingDashboardFragmentTest {
@Mock private SettingsActivity mActivity;
@Mock private SettingsMainSwitchBar mSwitchBar;
@Mock private View mView;
@Mock private AudioSharingDeviceVolumeGroupController mVolumeGroupController;
@Mock private AudioSharingCallAudioPreferenceController mCallAudioController;
@Mock private AudioSharingPlaySoundPreferenceController mPlaySoundController;
@@ -61,6 +64,7 @@ public class AudioSharingDashboardFragmentTest {
@Before
public void setUp() {
when(mSwitchBar.getRootView()).thenReturn(mView);
mFragment = new AudioSharingDashboardFragment();
}

View File

@@ -51,6 +51,8 @@ import android.os.Looper;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.FeatureFlagUtils;
import android.util.Pair;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.CompoundButton;
import androidx.fragment.app.DialogFragment;
@@ -590,4 +592,26 @@ public class AudioSharingSwitchBarControllerTest {
mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 1);
verifyNoMoreInteractions(mFeatureFactory.metricsFeatureProvider);
}
@Test
public void testAccessibilityDelegate() {
View view = new View(mContext);
AccessibilityEvent event =
new AccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
assertThat(
mSwitchBar
.getRootView()
.getAccessibilityDelegate()
.onRequestSendAccessibilityEvent(mSwitchBar, view, event))
.isTrue();
event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED);
assertThat(
mSwitchBar
.getRootView()
.getAccessibilityDelegate()
.onRequestSendAccessibilityEvent(mSwitchBar, view, event))
.isFalse();
}
}

View File

@@ -28,7 +28,6 @@ import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import androidx.preference.Preference.OnPreferenceClickListener;
import androidx.preference.PreferenceViewHolder;
import androidx.test.core.app.ApplicationProvider;
@@ -93,17 +92,6 @@ public class AudioStreamPreferenceTest {
assertThat(divider.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void setConnected_shouldUpdatePreferenceUI() {
String summary = "Connected";
OnPreferenceClickListener listener = mock(OnPreferenceClickListener.class);
mPreference.setIsConnected(true, summary, listener);
assertThat(mPreference.getSummary()).isNotNull();
assertThat(mPreference.getSummary().toString()).isEqualTo(summary);
assertThat(mPreference.getOnPreferenceClickListener()).isEqualTo(listener);
}
@Test
public void setAudioStreamMetadata_shouldUpdateMetadata() {
AudioStreamPreference p =
@@ -147,7 +135,7 @@ public class AudioStreamPreferenceTest {
@Test
public void shouldHideSecondTarget_connected() {
mPreference.setIsConnected(true, "", null);
mPreference.setIsConnected(true);
assertThat(mPreference.shouldHideSecondTarget()).isTrue();
}

View File

@@ -21,7 +21,6 @@ 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.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -31,6 +30,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.text.SpannableString;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
@@ -39,6 +39,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -75,7 +76,9 @@ public class AudioStreamStateHandlerTest {
verify(mPreference, never()).setAudioStreamState(any());
verify(mHandler, never()).performAction(any(), any(), any());
verify(mPreference, never()).setIsConnected(anyBoolean(), anyString(), any());
verify(mPreference, never()).setIsConnected(anyBoolean());
verify(mPreference, never()).setSummary(any());
verify(mPreference, never()).setOnPreferenceClickListener(any());
}
@Test
@@ -93,7 +96,9 @@ public class AudioStreamStateHandlerTest {
.setAudioStreamState(
AudioStreamsProgressCategoryController.AudioStreamState.SOURCE_ADDED);
verify(mHandler).performAction(any(), any(), any());
verify(mPreference).setIsConnected(eq(true), eq(""), eq(null));
verify(mPreference).setIsConnected(eq(true));
verify(mPreference).setSummary(eq(""));
verify(mPreference).setOnPreferenceClickListener(eq(null));
}
@Test
@@ -119,7 +124,13 @@ public class AudioStreamStateHandlerTest {
AudioStreamsProgressCategoryController.AudioStreamState
.ADD_SOURCE_BAD_CODE);
verify(mHandler).performAction(any(), any(), any());
verify(mPreference).setIsConnected(eq(false), eq(SUMMARY), eq(listener));
verify(mPreference).setIsConnected(eq(false));
ArgumentCaptor<SpannableString> argumentCaptor =
ArgumentCaptor.forClass(SpannableString.class);
verify(mPreference).setSummary(argumentCaptor.capture());
assertThat(argumentCaptor.getValue()).isNotNull();
assertThat(argumentCaptor.getValue().toString()).isEqualTo(SUMMARY);
verify(mPreference).setOnPreferenceClickListener(eq(listener));
}
@Test

View File

@@ -18,13 +18,21 @@ package com.android.settings.development;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.Flags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.SearchIndexableResource;
import android.provider.Settings;
@@ -42,6 +50,7 @@ import com.android.settingslib.development.DevelopmentSettingsEnabler;
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;
import org.mockito.MockitoAnnotations;
@@ -51,6 +60,7 @@ import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowBiometricManager;
import org.robolectric.shadows.androidx.fragment.FragmentController;
import org.robolectric.util.ReflectionHelpers;
@@ -61,22 +71,34 @@ import java.util.List;
ShadowAlertDialogCompat.class,
ShadowUserManager.class,
ShadowUserManager.class,
ShadowBiometricManager.class,
})
public class DevelopmentSettingsDashboardFragmentTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private Context mContext;
private ShadowUserManager mShadowUserManager;
private ShadowBiometricManager mShadowBiometricManager;
private DevelopmentSettingsDashboardFragment mDashboard;
private SettingsMainSwitchBar mSwitchBar;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
SettingsMainSwitchBar switchBar = new SettingsMainSwitchBar(mContext);
mSwitchBar = new SettingsMainSwitchBar(mContext);
mDashboard = spy(new DevelopmentSettingsDashboardFragment());
ReflectionHelpers.setField(mDashboard, "mSwitchBar", switchBar);
ReflectionHelpers.setField(mDashboard, "mSwitchBar", mSwitchBar);
mShadowUserManager = Shadow.extract(mContext.getSystemService(Context.USER_SERVICE));
mShadowUserManager.setIsAdminUser(true);
mShadowBiometricManager = Shadow.extract(mContext.getSystemService(
Context.BIOMETRIC_SERVICE));
mShadowBiometricManager.setCanAuthenticate(false);
//TODO(b/352603684): Should be Authenticators.MANDATORY_BIOMETRICS,
// but it is not supported by ShadowBiometricManager
mShadowBiometricManager.setAuthenticatorType(
BiometricManager.Authenticators.BIOMETRIC_STRONG);
}
@After
@@ -176,6 +198,41 @@ public class DevelopmentSettingsDashboardFragmentTest {
assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isTrue();
}
@Test
@Config(shadows = ShadowEnableDevelopmentSettingWarningDialog.class)
@EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
public void onSwitchChanged_turnOn_shouldLaunchBiometricPromptIfMandatoryBiometricsEffective() {
when(mDashboard.getContext()).thenReturn(mContext);
doNothing().when(mDashboard).startActivityForResult(any(),
eq(DevelopmentSettingsDashboardFragment.REQUEST_BIOMETRIC_PROMPT));
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
mShadowBiometricManager.setCanAuthenticate(true);
mDashboard.onCheckedChanged(null, true /* isChecked */);
assertThat(mSwitchBar.isChecked()).isFalse();
verify(mDashboard).startActivityForResult(any(),
eq(DevelopmentSettingsDashboardFragment.REQUEST_BIOMETRIC_PROMPT));
assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isFalse();
}
@Test
@Config(shadows = ShadowEnableDevelopmentSettingWarningDialog.class)
@EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
public void onActivityResult_requestBiometricPrompt_shouldShowWarningDialog() {
when(mDashboard.getContext()).thenReturn(mContext);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
mDashboard.onActivityResult(DevelopmentSettingsDashboardFragment.REQUEST_BIOMETRIC_PROMPT,
Activity.RESULT_OK, null);
mDashboard.onCheckedChanged(null, true /* isChecked */);
assertThat(mSwitchBar.isChecked()).isTrue();
assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isTrue();
}
@Test
@Ignore
@Config(shadows = ShadowEnableDevelopmentSettingWarningDialog.class)

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.provider.Settings;
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 TouchpadVisualizerPreferenceControllerTest {
@Mock
private PreferenceScreen mScreen;
@Mock
private SwitchPreference mPreference;
private Context mContext;
private TouchpadVisualizerPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new TouchpadVisualizerPreferenceController(mContext);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
mController.displayPreference(mScreen);
}
@Test
public void updateState_touchpadVisualizerEnabled_shouldCheckedPreference() {
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.TOUCHPAD_VISUALIZER, ShowTapsPreferenceController.SETTING_VALUE_ON);
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
}
@Test
public void updateState_touchpadVisualizerDisabled_shouldUncheckedPreference() {
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.TOUCHPAD_VISUALIZER,
ShowTapsPreferenceController.SETTING_VALUE_OFF);
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
}
@Test
public void onPreferenceChange_preferenceChecked_shouldEnableTouchpadVisualizer() {
mController.onPreferenceChange(mPreference, true /* new value */);
final int touchpadVisualizer = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.TOUCHPAD_VISUALIZER, -1 /* default */);
assertThat(touchpadVisualizer).isEqualTo(ShowTapsPreferenceController.SETTING_VALUE_ON);
}
@Test
public void onPreferenceChange_preferenceUnchecked_shouldDisableTouchpadVisualizer() {
mController.onPreferenceChange(mPreference, false /* new value */);
final int showTapsMode = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.TOUCHPAD_VISUALIZER, -1 /* default */);
assertThat(showTapsMode).isEqualTo(ShowTapsPreferenceController.SETTING_VALUE_OFF);
}
@Test
public void onDeveloperOptionsSwitchDisabled_preferenceShouldBeEnabled() {
mController.onDeveloperOptionsSwitchDisabled();
final int showTapsMode = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.TOUCHPAD_VISUALIZER, -1 /* default */);
assertThat(showTapsMode).isEqualTo(ShowTapsPreferenceController.SETTING_VALUE_OFF);
verify(mPreference).setEnabled(false);
verify(mPreference).setChecked(false);
}
}

View File

@@ -91,7 +91,8 @@ class SatelliteRepositoryTest {
@Test
fun requestIsSessionStarted_resultIsTrue() = runBlocking {
`when`(mockSatelliteManager.registerForModemStateChanged(any(), any())
`when`(
mockSatelliteManager.registerForModemStateChanged(any(), any())
).thenAnswer { invocation ->
val callback = invocation.getArgument<SatelliteModemStateCallback>(1)
callback.onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED)
@@ -105,7 +106,8 @@ class SatelliteRepositoryTest {
@Test
fun requestIsSessionStarted_resultIsFalse() = runBlocking {
`when`(mockSatelliteManager.registerForModemStateChanged(any(), any())
`when`(
mockSatelliteManager.registerForModemStateChanged(any(), any())
).thenAnswer { invocation ->
val callback = invocation.getArgument<SatelliteModemStateCallback>(1)
callback.onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_OFF)
@@ -119,7 +121,8 @@ class SatelliteRepositoryTest {
@Test
fun requestIsSessionStarted_registerFailed() = runBlocking {
`when`(mockSatelliteManager.registerForModemStateChanged(any(), any())
`when`(
mockSatelliteManager.registerForModemStateChanged(any(), any())
).thenAnswer {
SatelliteManager.SATELLITE_RESULT_ERROR
}
@@ -129,6 +132,17 @@ class SatelliteRepositoryTest {
verify(mockSatelliteManager, never()).unregisterForModemStateChanged(any())
}
@Test
fun requestIsSessionStarted_phoneCrash_registerFailed() = runBlocking {
`when`(
mockSatelliteManager.registerForModemStateChanged(any(), any())
).thenThrow(IllegalStateException("Telephony is null"))
val result: ListenableFuture<Boolean> = repository.requestIsSessionStarted(mockExecutor)
assertFalse(result.get())
verify(mockSatelliteManager, never()).unregisterForModemStateChanged(any())
}
@Test
fun requestIsSessionStarted_nullSatelliteManager() = runBlocking {
`when`(spyContext.getSystemService(SatelliteManager::class.java)).thenReturn(null)
@@ -157,6 +171,17 @@ class SatelliteRepositoryTest {
assertFalse(result.get())
}
@Test
fun requestIsEnabled_phoneCrash_resultIsFalse() = runBlocking {
`when`(
mockSatelliteManager.requestIsEnabled(any(), any())
).thenThrow(IllegalStateException("Telephony is null"))
val result: ListenableFuture<Boolean> =
repository.requestIsEnabled(mockExecutor)
assertFalse(result.get())
}
@Test
fun requestIsEnabled_exceptionFailure() = runBlocking {
@@ -232,7 +257,8 @@ class SatelliteRepositoryTest {
@Test
fun getIsSessionStartedFlow_registerFailed() = runBlocking {
`when`(mockSatelliteManager.registerForModemStateChanged(any(), any())
`when`(
mockSatelliteManager.registerForModemStateChanged(any(), any())
).thenAnswer {
SatelliteManager.SATELLITE_RESULT_ERROR
}

View File

@@ -28,8 +28,13 @@ import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.Flags;
import android.os.Looper;
import android.os.UserManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import androidx.lifecycle.LifecycleOwner;
@@ -45,6 +50,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -53,6 +59,9 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class BuildNumberPreferenceControllerTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule =
DeviceFlagsValueProvider.createCheckFlagsRule();
private static final String KEY_BUILD_NUMBER = "build_number";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -60,6 +69,7 @@ public class BuildNumberPreferenceControllerTest {
private Context mContext;
private UserManager mUserManager;
private BiometricManager mBiometricManager;
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
private FakeFeatureFactory mFactory;
@@ -76,7 +86,13 @@ public class BuildNumberPreferenceControllerTest {
mContext = spy(ApplicationProvider.getApplicationContext());
mUserManager = (UserManager) spy(mContext.getSystemService(Context.USER_SERVICE));
mBiometricManager = spy(mContext.getSystemService(BiometricManager.class));
doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
when(mContext.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
when(mBiometricManager.canAuthenticate(mContext.getUserId(),
BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
mFactory = FakeFeatureFactory.setupForTest();
mLifecycleOwner = () -> mLifecycle;
@@ -156,7 +172,7 @@ public class BuildNumberPreferenceControllerTest {
@Test
public void onActivityResult_notConfirmPasswordRequest_doNothing() {
final boolean activityResultHandled = mController.onActivityResult(
BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF + 1,
BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF + 2,
Activity.RESULT_OK,
null);
@@ -188,4 +204,38 @@ public class BuildNumberPreferenceControllerTest {
assertThat(activityResultHandled).isTrue();
assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isTrue();
}
@Test
@UiThreadTest
@RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
public void onActivityResult_confirmPasswordRequestCompleted_launchBiometricPrompt() {
when(mUserManager.isAdminUser()).thenReturn(true);
when(mBiometricManager.canAuthenticate(mContext.getUserId(),
BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
final boolean activityResultHandled = mController.onActivityResult(
BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF,
Activity.RESULT_OK,
null);
assertThat(activityResultHandled).isTrue();
assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse();
verify(mFragment).startActivityForResult(any(),
eq(BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF));
}
@Test
public void onActivityResult_confirmBiometricAuthentication_enableDevPref() {
when(mUserManager.isAdminUser()).thenReturn(true);
Looper.prepare();
final boolean activityResultHandled = mController.onActivityResult(
BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF,
Activity.RESULT_OK,
null);
assertThat(activityResultHandled).isTrue();
assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isTrue();
}
}