Snap for 10330433 from a1fd330fb5 to udc-qpr1-release

Change-Id: I8c6d13f66574e626026aa37052d1476c760fd516
This commit is contained in:
Android Build Coastguard Worker
2023-06-16 03:19:09 +00:00
33 changed files with 595 additions and 457 deletions

View File

@@ -2398,6 +2398,7 @@
<action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL" />
<action android:name="android.app.action.CONFIRM_FRP_CREDENTIAL" />
<action android:name="android.app.action.PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL" />
<action android:name="android.app.action.CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

View File

@@ -18,7 +18,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/udfps_animation_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:visibility="gone">
<ImageView
android:id="@+id/udfps_enroll_animation_fp_progress_view"

View File

@@ -3495,6 +3495,18 @@
<!-- Checkbox label to set password as new screen lock if remote device credential validation succeeds. [CHAR LIMIT=43] -->
<string name="lockpassword_remote_validation_set_password_as_screenlock">Also use password to unlock this device</string>
<!-- Header shown when pattern needs to be solved before the device exits repair mode. [CHAR LIMIT=100] [DO NOT TRANSLATE] TODO(b/275677027): update with finalized UX string -->
<string name="lockpassword_confirm_repair_mode_pattern_header">Verify pattern</string>
<!-- Header shown when the pin needs to be solved before the device exits repair mode. [CHAR LIMIT=100] [DO NOT TRANSLATE] TODO(b/275677027): update with finalized UX string -->
<string name="lockpassword_confirm_repair_mode_pin_header">Verify PIN</string>
<!-- Header shown when the password needs to be solved before the device exits repair mode. [CHAR LIMIT=100] [DO NOT TRANSLATE] TODO(b/275677027): update with finalized UX string -->
<string name="lockpassword_confirm_repair_mode_password_header">Verify password</string>
<!-- An explanation text that the pattern needs to be solved before the device exits repair mode. [CHAR LIMIT=100] [DO NOT TRANSLATE] TODO(b/275677027): update with finalized UX string -->
<string name="lockpassword_confirm_repair_mode_pattern_details" translatable="false">Enter your device pattern enrolled in normal mode to continue</string>
<!-- An explanation text that the PIN needs to be solved before the device exits repair mode. [CHAR LIMIT=100] [DO NOT TRANSLATE] TODO(b/275677027): update with finalized UX string -->
<string name="lockpassword_confirm_repair_mode_pin_details" translatable="false">Enter your device PIN enrolled in normal mode to continue</string>
<!-- An explanation text that the password needs to be solved before the device exits repair mode. [CHAR LIMIT=100] [DO NOT TRANSLATE] TODO(b/275677027): update with finalized UX string -->
<string name="lockpassword_confirm_repair_mode_password_details" translatable="false">Enter your device password enrolled in normal mode to continue</string>
<!-- Security & location settings screen, change security method screen instruction if user
enters incorrect PIN [CHAR LIMIT=30] -->

View File

@@ -708,9 +708,13 @@ public final class Utils extends com.android.settingslib.Utils {
final int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
if (userId == LockPatternUtils.USER_FRP) {
return allowAnyUser ? userId : checkUserOwnsFrpCredential(context, userId);
} else {
return allowAnyUser ? userId : enforceSameOwner(context, userId);
}
if (userId == LockPatternUtils.USER_REPAIR_MODE) {
enforceRepairModeActive(context);
// any users can exit repair mode
return userId;
}
return allowAnyUser ? userId : enforceSameOwner(context, userId);
}
/**
@@ -729,6 +733,16 @@ public final class Utils extends com.android.settingslib.Utils {
+ " does not own frp credential.");
}
/**
* Throws {@link SecurityException} if repair mode is not active on the device.
*/
private static void enforceRepairModeActive(Context context) {
if (LockPatternUtils.isRepairModeActive(context)) {
return;
}
throw new SecurityException("Repair mode is not active on the device.");
}
/**
* Returns the given user id if it belongs to the current user.
*

View File

@@ -51,7 +51,7 @@ class DataSaverController(context: Context, key: String) : BasePreferenceControl
preference = screen.findPreference(preferenceKey)!!
}
fun init(viewLifecycleOwner: LifecycleOwner) {
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
preference.summary = getUnrestrictedSummary(mContext)

View File

@@ -21,10 +21,6 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGE_DE
import android.app.settings.SettingsEnums;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -50,12 +46,6 @@ public class SpecialAccessSettings extends DashboardFragment {
MANAGE_DEVICE_ADMIN_APPS, R.string.manage_device_admin);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
use(DataSaverController.class).init(getViewLifecycleOwner());
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.special_access;

View File

@@ -48,11 +48,16 @@ public abstract class BiometricEnrollSidecar extends InstrumentedFragment {
/**
* Called when a pointer down event has occurred.
*/
default void onPointerDown(int sensorId) { }
default void onUdfpsPointerDown(int sensorId) { }
/**
* Called when a pointer up event has occurred.
*/
default void onPointerUp(int sensorId) { }
default void onUdfpsPointerUp(int sensorId) { }
/**
* Called when udfps overlay is shown.
*/
default void onUdfpsOverlayShown() { }
}
private int mEnrollmentSteps = -1;
@@ -126,29 +131,36 @@ public abstract class BiometricEnrollSidecar extends InstrumentedFragment {
}
}
private class QueuedPointerDown extends QueuedEvent {
private class QueuedUdfpsPointerDown extends QueuedEvent {
private final int sensorId;
public QueuedPointerDown(int sensorId) {
QueuedUdfpsPointerDown(int sensorId) {
this.sensorId = sensorId;
}
@Override
public void send(Listener listener) {
listener.onPointerDown(sensorId);
listener.onUdfpsPointerDown(sensorId);
}
}
private class QueuedPointerUp extends QueuedEvent {
private class QueuedUdfpsPointerUp extends QueuedEvent {
private final int sensorId;
public QueuedPointerUp(int sensorId) {
QueuedUdfpsPointerUp(int sensorId) {
this.sensorId = sensorId;
}
@Override
public void send(Listener listener) {
listener.onPointerUp(sensorId);
listener.onUdfpsPointerUp(sensorId);
}
}
private class QueuedUdfpsOverlayShown extends QueuedEvent {
@Override
public void send(Listener listener) {
listener.onUdfpsOverlayShown();
}
}
@@ -249,19 +261,27 @@ public abstract class BiometricEnrollSidecar extends InstrumentedFragment {
}
}
protected void onPointerDown(int sensorId) {
protected void onUdfpsPointerDown(int sensorId) {
if (mListener != null) {
mListener.onPointerDown(sensorId);
mListener.onUdfpsPointerDown(sensorId);
} else {
mQueuedEvents.add(new QueuedPointerDown(sensorId));
mQueuedEvents.add(new QueuedUdfpsPointerDown(sensorId));
}
}
protected void onPointerUp(int sensorId) {
protected void onUdfpsPointerUp(int sensorId) {
if (mListener != null) {
mListener.onPointerUp(sensorId);
mListener.onUdfpsPointerUp(sensorId);
} else {
mQueuedEvents.add(new QueuedPointerUp(sensorId));
mQueuedEvents.add(new QueuedUdfpsPointerUp(sensorId));
}
}
protected void onUdfpsOverlayShown() {
if (mListener != null) {
mListener.onUdfpsOverlayShown();
} else {
mQueuedEvents.add(new QueuedUdfpsOverlayShown());
}
}

View File

@@ -828,19 +828,26 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
}
@Override
public void onPointerDown(int sensorId) {
public void onUdfpsPointerDown(int sensorId) {
if (mUdfpsEnrollHelper != null) {
mUdfpsEnrollHelper.onPointerDown(sensorId);
}
}
@Override
public void onPointerUp(int sensorId) {
public void onUdfpsPointerUp(int sensorId) {
if (mUdfpsEnrollHelper != null) {
mUdfpsEnrollHelper.onPointerUp(sensorId);
}
}
@Override
public void onUdfpsOverlayShown() {
if (mCanAssumeUdfps) {
findViewById(R.id.udfps_animation_view).setVisibility(View.VISIBLE);
}
}
private void updateProgress(boolean animate) {
if (mSidecar == null || !mSidecar.isEnrolling()) {
Log.d(TAG, "Enrollment not started yet");

View File

@@ -124,13 +124,18 @@ public class FingerprintEnrollSidecar extends BiometricEnrollSidecar {
}
@Override
public void onPointerDown(int sensorId) {
FingerprintEnrollSidecar.super.onPointerDown(sensorId);
public void onUdfpsPointerDown(int sensorId) {
FingerprintEnrollSidecar.super.onUdfpsPointerDown(sensorId);
}
@Override
public void onPointerUp(int sensorId) {
FingerprintEnrollSidecar.super.onPointerUp(sensorId);
public void onUdfpsPointerUp(int sensorId) {
FingerprintEnrollSidecar.super.onUdfpsPointerUp(sensorId);
}
@Override
public void onUdfpsOverlayShown() {
FingerprintEnrollSidecar.super.onUdfpsOverlayShown();
}
};

View File

@@ -98,13 +98,18 @@ public class FingerprintUpdater {
}
@Override
public void onPointerDown(int sensorId) {
mCallback.onPointerDown(sensorId);
public void onUdfpsPointerDown(int sensorId) {
mCallback.onUdfpsPointerDown(sensorId);
}
@Override
public void onPointerUp(int sensorId) {
mCallback.onPointerUp(sensorId);
public void onUdfpsPointerUp(int sensorId) {
mCallback.onUdfpsPointerUp(sensorId);
}
@Override
public void onUdfpsOverlayShown() {
mCallback.onUdfpsOverlayShown();
}
}

View File

@@ -86,7 +86,7 @@ public class UdfpsEnrollEnrollingView extends GlifLayout {
UdfpsEnrollHelper udfpsEnrollHelper,
AccessibilityManager accessibilityManager) {
mAccessibilityManager = accessibilityManager;
initUdfpsEnrollView(mUdfpsEnrollView, udfpsProps, udfpsEnrollHelper);
initUdfpsEnrollView(udfpsProps, udfpsEnrollHelper);
if (!mIsLandscape) {
adjustPortraitPaddings();
@@ -117,8 +117,7 @@ public class UdfpsEnrollEnrollingView extends GlifLayout {
});
}
private void initUdfpsEnrollView(UdfpsEnrollView udfpsEnrollView,
FingerprintSensorPropertiesInternal udfpsProps,
private void initUdfpsEnrollView(FingerprintSensorPropertiesInternal udfpsProps,
UdfpsEnrollHelper udfpsEnrollHelper) {
DisplayInfo displayInfo = new DisplayInfo();
mContext.getDisplay().getDisplayInfo(displayInfo);
@@ -141,8 +140,8 @@ public class UdfpsEnrollEnrollingView extends GlifLayout {
scaleFactor,
displayInfo.rotation);
udfpsEnrollView.setOverlayParams(params);
udfpsEnrollView.setEnrollHelper(udfpsEnrollHelper);
mUdfpsEnrollView.setOverlayParams(params);
mUdfpsEnrollView.setEnrollHelper(udfpsEnrollHelper);
}
private void adjustPortraitPaddings() {

View File

@@ -103,12 +103,12 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
}
@Override
public void onPointerDown(int sensorId) {
public void onUdfpsPointerDown(int sensorId) {
mPointerDownLiveData.postValue(sensorId);
}
@Override
public void onPointerUp(int sensorId) {
public void onUdfpsPointerUp(int sensorId) {
mPointerUpLiveData.postValue(sensorId);
}
};

View File

@@ -128,7 +128,7 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
if (device != null && mSelectedList.contains(device)) {
setResult(RESULT_OK);
finish();
} else if (mDevicePreferenceMap.containsKey(cachedDevice)) {
} else {
onDeviceDeleted(cachedDevice);
}
}
@@ -175,8 +175,6 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
public void updateContent(int bluetoothState) {
switch (bluetoothState) {
case BluetoothAdapter.STATE_ON:
mDevicePreferenceMap.clear();
clearPreferenceGroupCache();
mBluetoothAdapter.enable();
enableScanning();
break;
@@ -187,14 +185,6 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
}
}
/**
* Clears all cached preferences in {@code preferenceGroup}.
*/
private void clearPreferenceGroupCache() {
cacheRemoveAllPrefs(mAvailableDevicesCategory);
removeCachedPrefs(mAvailableDevicesCategory);
}
@VisibleForTesting
void showBluetoothTurnedOnToast() {
Toast.makeText(getContext(), R.string.connected_device_bluetooth_turned_on_toast,

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* 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.
@@ -35,6 +35,8 @@ import android.view.View;
import android.widget.ImageView;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;
@@ -52,6 +54,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
/**
* BluetoothDevicePreference is the preference type used to display each remote
@@ -79,7 +82,9 @@ public final class BluetoothDevicePreference extends GearPreference {
@VisibleForTesting
BluetoothAdapter mBluetoothAdapter;
private final boolean mShowDevicesWithoutNames;
private final long mCurrentTime;
@NonNull
private static final AtomicInteger sNextId = new AtomicInteger();
private final int mId;
private final int mType;
private AlertDialog mDisconnectDialog;
@@ -127,8 +132,9 @@ public final class BluetoothDevicePreference extends GearPreference {
mCachedDevice = cachedDevice;
mCallback = new BluetoothDevicePreferenceCallback();
mCurrentTime = System.currentTimeMillis();
mId = sNextId.getAndIncrement();
mType = type;
setVisible(false);
onPreferenceAttributesChanged();
}
@@ -229,35 +235,41 @@ public final class BluetoothDevicePreference extends GearPreference {
@SuppressWarnings("FutureReturnValueIgnored")
void onPreferenceAttributesChanged() {
Pair<Drawable, String> pair = mCachedDevice.getDrawableWithDescription();
setIcon(pair.first);
contentDescription = pair.second;
/*
* The preference framework takes care of making sure the value has
* changed before proceeding. It will also call notifyChanged() if
* any preference info has changed from the previous value.
*/
setTitle(mCachedDevice.getName());
try {
ThreadUtils.postOnBackgroundThread(() -> {
@Nullable String name = mCachedDevice.getName();
// Null check is done at the framework
ThreadUtils.postOnMainThread(() -> setSummary(getConnectionSummary()));
@Nullable String connectionSummary = getConnectionSummary();
@NonNull Pair<Drawable, String> pair = mCachedDevice.getDrawableWithDescription();
boolean isBusy = mCachedDevice.isBusy();
// Device is only visible in the UI if it has a valid name besides MAC address or
// when user allows showing devices without user-friendly name in developer settings
boolean isVisible =
mShowDevicesWithoutNames || mCachedDevice.hasHumanReadableName();
ThreadUtils.postOnMainThread(() -> {
/*
* The preference framework takes care of making sure the value has
* changed before proceeding. It will also call notifyChanged() if
* any preference info has changed from the previous value.
*/
setTitle(name);
setSummary(connectionSummary);
setIcon(pair.first);
contentDescription = pair.second;
// Used to gray out the item
setEnabled(!isBusy);
setVisible(isVisible);
// This could affect ordering, so notify that
if (mNeedNotifyHierarchyChanged) {
notifyHierarchyChanged();
}
});
});
} catch (RejectedExecutionException e) {
Log.w(TAG, "Handler thread unavailable, skipping getConnectionSummary!");
}
// Used to gray out the item
setEnabled(!mCachedDevice.isBusy());
// Device is only visible in the UI if it has a valid name besides MAC address or when user
// allows showing devices without user-friendly name in developer settings
setVisible(mShowDevicesWithoutNames || mCachedDevice.hasHumanReadableName());
// This could affect ordering, so notify that
if (mNeedNotifyHierarchyChanged) {
notifyHierarchyChanged();
}
}
@Override
@@ -311,7 +323,7 @@ public final class BluetoothDevicePreference extends GearPreference {
return mCachedDevice
.compareTo(((BluetoothDevicePreference) another).mCachedDevice);
case SortType.TYPE_FIFO:
return mCurrentTime > ((BluetoothDevicePreference) another).mCurrentTime ? 1 : -1;
return mId > ((BluetoothDevicePreference) another).mId ? 1 : -1;
default:
return super.compareTo(another);
}

View File

@@ -1,351 +0,0 @@
/*
* Copyright (C) 2011 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.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.os.Bundle;
import android.os.SystemProperties;
import android.text.BidiFormatter;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import com.android.settings.R;
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
/**
* Parent class for settings fragments that contain a list of Bluetooth
* devices.
*
* @see DevicePickerFragment
*/
// TODO: Refactor this fragment
public abstract class DeviceListPreferenceFragment extends
RestrictedDashboardFragment implements BluetoothCallback {
private static final String TAG = "DeviceListPreferenceFragment";
private static final String KEY_BT_SCAN = "bt_scan";
// Copied from BluetoothDeviceNoNamePreferenceController.java
private static final String BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY =
"persist.bluetooth.showdeviceswithoutnames";
private BluetoothDeviceFilter.Filter mFilter;
private List<ScanFilter> mLeScanFilters;
private ScanCallback mScanCallback;
@VisibleForTesting
protected boolean mScanEnabled;
protected BluetoothDevice mSelectedDevice;
protected BluetoothAdapter mBluetoothAdapter;
protected LocalBluetoothManager mLocalManager;
protected CachedBluetoothDeviceManager mCachedDeviceManager;
@VisibleForTesting
protected PreferenceGroup mDeviceListGroup;
protected final HashMap<CachedBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
new HashMap<>();
protected final List<BluetoothDevice> mSelectedList = new ArrayList<>();
protected boolean mShowDevicesWithoutNames;
public DeviceListPreferenceFragment(String restrictedKey) {
super(restrictedKey);
mFilter = BluetoothDeviceFilter.ALL_FILTER;
}
protected final void setFilter(BluetoothDeviceFilter.Filter filter) {
mFilter = filter;
}
protected final void setFilter(int filterType) {
mFilter = BluetoothDeviceFilter.getFilter(filterType);
}
/**
* Sets the bluetooth device scanning filter with {@link ScanFilter}s. It will change to start
* {@link BluetoothLeScanner} which will scan BLE device only.
*
* @param leScanFilters list of settings to filter scan result
*/
protected void setFilter(List<ScanFilter> leScanFilters) {
mFilter = null;
mLeScanFilters = leScanFilters;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocalManager = Utils.getLocalBtManager(getActivity());
if (mLocalManager == null) {
Log.e(TAG, "Bluetooth is not supported on this device");
return;
}
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mCachedDeviceManager = mLocalManager.getCachedDeviceManager();
mShowDevicesWithoutNames = SystemProperties.getBoolean(
BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY, false);
initPreferencesFromPreferenceScreen();
mDeviceListGroup = (PreferenceCategory) findPreference(getDeviceListKey());
}
/** find and update preference that already existed in preference screen */
protected abstract void initPreferencesFromPreferenceScreen();
@Override
public void onStart() {
super.onStart();
if (mLocalManager == null || isUiRestricted()) return;
mLocalManager.setForegroundActivity(getActivity());
mLocalManager.getEventManager().registerCallback(this);
}
@Override
public void onStop() {
super.onStop();
if (mLocalManager == null || isUiRestricted()) {
return;
}
removeAllDevices();
mLocalManager.setForegroundActivity(null);
mLocalManager.getEventManager().unregisterCallback(this);
}
void removeAllDevices() {
mDevicePreferenceMap.clear();
mDeviceListGroup.removeAll();
}
void addCachedDevices() {
Collection<CachedBluetoothDevice> cachedDevices =
mCachedDeviceManager.getCachedDevicesCopy();
for (CachedBluetoothDevice cachedDevice : cachedDevices) {
onDeviceAdded(cachedDevice);
}
}
@Override
public boolean onPreferenceTreeClick(Preference preference) {
if (KEY_BT_SCAN.equals(preference.getKey())) {
startScanning();
return true;
}
if (preference instanceof BluetoothDevicePreference) {
BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;
CachedBluetoothDevice device = btPreference.getCachedDevice();
mSelectedDevice = device.getDevice();
mSelectedList.add(mSelectedDevice);
onDevicePreferenceClick(btPreference);
return true;
}
return super.onPreferenceTreeClick(preference);
}
protected void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
btPreference.onClicked();
}
@Override
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
if (mDevicePreferenceMap.get(cachedDevice) != null) {
return;
}
// Prevent updates while the list shows one of the state messages
if (mBluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) {
return;
}
if (mFilter != null && mFilter.matches(cachedDevice.getDevice())) {
createDevicePreference(cachedDevice);
}
}
void createDevicePreference(CachedBluetoothDevice cachedDevice) {
if (mDeviceListGroup == null) {
Log.w(TAG, "Trying to create a device preference before the list group/category "
+ "exists!");
return;
}
String key = cachedDevice.getDevice().getAddress();
BluetoothDevicePreference preference = (BluetoothDevicePreference) getCachedPreference(key);
if (preference == null) {
preference = new BluetoothDevicePreference(getPrefContext(), cachedDevice,
mShowDevicesWithoutNames, BluetoothDevicePreference.SortType.TYPE_FIFO);
preference.setKey(key);
//Set hideSecondTarget is true if it's bonded device.
preference.hideSecondTarget(true);
mDeviceListGroup.addPreference(preference);
}
initDevicePreference(preference);
mDevicePreferenceMap.put(cachedDevice, preference);
}
protected void initDevicePreference(BluetoothDevicePreference preference) {
// Does nothing by default
}
@VisibleForTesting
void updateFooterPreference(Preference myDevicePreference) {
final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
myDevicePreference.setTitle(getString(
R.string.bluetooth_footer_mac_message,
bidiFormatter.unicodeWrap(mBluetoothAdapter.getAddress())));
}
@Override
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
BluetoothDevicePreference preference = mDevicePreferenceMap.remove(cachedDevice);
if (preference != null) {
mDeviceListGroup.removePreference(preference);
}
}
@VisibleForTesting
protected void enableScanning() {
// BluetoothAdapter already handles repeated scan requests
if (!mScanEnabled) {
startScanning();
mScanEnabled = true;
}
}
@VisibleForTesting
protected void disableScanning() {
if (mScanEnabled) {
stopScanning();
mScanEnabled = false;
}
}
@Override
public void onScanningStateChanged(boolean started) {
if (!started && mScanEnabled) {
startScanning();
}
}
/**
* Return the key of the {@link PreferenceGroup} that contains the bluetooth devices
*/
public abstract String getDeviceListKey();
public boolean shouldShowDevicesWithoutNames() {
return mShowDevicesWithoutNames;
}
@VisibleForTesting
void startScanning() {
if (mFilter != null) {
startClassicScanning();
} else if (mLeScanFilters != null) {
startLeScanning();
}
}
@VisibleForTesting
void stopScanning() {
if (mFilter != null) {
stopClassicScanning();
} else if (mLeScanFilters != null) {
stopLeScanning();
}
}
private void startClassicScanning() {
if (!mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.startDiscovery();
}
}
private void stopClassicScanning() {
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
}
private void startLeScanning() {
final BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
final ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
final BluetoothDevice device = result.getDevice();
CachedBluetoothDevice cachedDevice = mCachedDeviceManager.findDevice(device);
if (cachedDevice == null) {
cachedDevice = mCachedDeviceManager.addDevice(device);
}
// Only add device preference when it's not found in the map and there's no other
// state message showing in the list
if (mDevicePreferenceMap.get(cachedDevice) == null
&& mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
createDevicePreference(cachedDevice);
}
}
@Override
public void onScanFailed(int errorCode) {
Log.w(TAG, "BLE Scan failed with error code " + errorCode);
}
};
scanner.startScan(mLeScanFilters, settings, mScanCallback);
}
private void stopLeScanning() {
final BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
if (scanner != null) {
scanner.stopScan(mScanCallback);
}
}
}

View File

@@ -0,0 +1,348 @@
/*
* 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.bluetooth
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.os.Bundle
import android.os.SystemProperties
import android.text.BidiFormatter
import android.util.Log
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceGroup
import com.android.settings.R
import com.android.settings.dashboard.RestrictedDashboardFragment
import com.android.settingslib.bluetooth.BluetoothCallback
import com.android.settingslib.bluetooth.BluetoothDeviceFilter
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager
import com.android.settingslib.bluetooth.LocalBluetoothManager
import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* Parent class for settings fragments that contain a list of Bluetooth devices.
*
* @see DevicePickerFragment
*
* TODO: Refactor this fragment
*/
abstract class DeviceListPreferenceFragment(restrictedKey: String?) :
RestrictedDashboardFragment(restrictedKey), BluetoothCallback {
private var filter: BluetoothDeviceFilter.Filter? = BluetoothDeviceFilter.ALL_FILTER
private var leScanFilters: List<ScanFilter>? = null
@JvmField
@VisibleForTesting
var mScanEnabled = false
@JvmField
var mSelectedDevice: BluetoothDevice? = null
@JvmField
var mBluetoothAdapter: BluetoothAdapter? = null
@JvmField
var mLocalManager: LocalBluetoothManager? = null
@JvmField
var mCachedDeviceManager: CachedBluetoothDeviceManager? = null
@JvmField
@VisibleForTesting
var mDeviceListGroup: PreferenceGroup? = null
@VisibleForTesting
val devicePreferenceMap =
ConcurrentHashMap<CachedBluetoothDevice, BluetoothDevicePreference>()
@JvmField
val mSelectedList: MutableList<BluetoothDevice> = ArrayList()
private var showDevicesWithoutNames = false
protected fun setFilter(filter: BluetoothDeviceFilter.Filter?) {
this.filter = filter
}
protected fun setFilter(filterType: Int) {
filter = BluetoothDeviceFilter.getFilter(filterType)
}
/**
* Sets the bluetooth device scanning filter with [ScanFilter]s. It will change to start
* [BluetoothLeScanner] which will scan BLE device only.
*
* @param leScanFilters list of settings to filter scan result
*/
fun setFilter(leScanFilters: List<ScanFilter>?) {
filter = null
this.leScanFilters = leScanFilters
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mLocalManager = Utils.getLocalBtManager(activity)
if (mLocalManager == null) {
Log.e(TAG, "Bluetooth is not supported on this device")
return
}
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
mCachedDeviceManager = mLocalManager!!.cachedDeviceManager
showDevicesWithoutNames = SystemProperties.getBoolean(
BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY, false
)
initPreferencesFromPreferenceScreen()
mDeviceListGroup = findPreference<Preference>(deviceListKey) as PreferenceCategory
}
/** find and update preference that already existed in preference screen */
protected abstract fun initPreferencesFromPreferenceScreen()
private var lifecycleScope: LifecycleCoroutineScope? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycleScope = viewLifecycleOwner.lifecycleScope
}
override fun onStart() {
super.onStart()
if (mLocalManager == null || isUiRestricted) return
mLocalManager!!.foregroundActivity = activity
mLocalManager!!.eventManager.registerCallback(this)
}
override fun onStop() {
super.onStop()
if (mLocalManager == null || isUiRestricted) {
return
}
removeAllDevices()
mLocalManager!!.foregroundActivity = null
mLocalManager!!.eventManager.unregisterCallback(this)
}
fun removeAllDevices() {
devicePreferenceMap.clear()
mDeviceListGroup!!.removeAll()
}
fun addCachedDevices() {
lifecycleScope?.launch {
withContext(Dispatchers.Default) {
val cachedDevices = mCachedDeviceManager!!.cachedDevicesCopy
for (cachedDevice in cachedDevices) {
onDeviceAdded(cachedDevice)
}
}
}
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
if (KEY_BT_SCAN == preference.key) {
startScanning()
return true
}
if (preference is BluetoothDevicePreference) {
val device = preference.cachedDevice.device
mSelectedDevice = device
mSelectedList.add(device)
onDevicePreferenceClick(preference)
return true
}
return super.onPreferenceTreeClick(preference)
}
protected open fun onDevicePreferenceClick(btPreference: BluetoothDevicePreference) {
btPreference.onClicked()
}
override fun onDeviceAdded(cachedDevice: CachedBluetoothDevice) {
lifecycleScope?.launch {
addDevice(cachedDevice)
}
}
private suspend fun addDevice(cachedDevice: CachedBluetoothDevice) =
withContext(Dispatchers.Default) {
// Prevent updates while the list shows one of the state messages
if (mBluetoothAdapter!!.state == BluetoothAdapter.STATE_ON &&
filter?.matches(cachedDevice.device) == true
) {
createDevicePreference(cachedDevice)
}
}
private suspend fun createDevicePreference(cachedDevice: CachedBluetoothDevice) {
if (mDeviceListGroup == null) {
Log.w(
TAG,
"Trying to create a device preference before the list group/category exists!",
)
return
}
// Only add device preference when it's not found in the map and there's no other state
// message showing in the list
val preference = devicePreferenceMap.computeIfAbsent(cachedDevice) {
BluetoothDevicePreference(
prefContext,
cachedDevice,
showDevicesWithoutNames,
BluetoothDevicePreference.SortType.TYPE_FIFO,
).apply {
key = cachedDevice.device.address
//Set hideSecondTarget is true if it's bonded device.
hideSecondTarget(true)
}
}
withContext(Dispatchers.Main) {
mDeviceListGroup!!.addPreference(preference)
initDevicePreference(preference)
}
}
protected open fun initDevicePreference(preference: BluetoothDevicePreference?) {
// Does nothing by default
}
@VisibleForTesting
fun updateFooterPreference(myDevicePreference: Preference) {
val bidiFormatter = BidiFormatter.getInstance()
myDevicePreference.title = getString(
R.string.bluetooth_footer_mac_message,
bidiFormatter.unicodeWrap(mBluetoothAdapter!!.address)
)
}
override fun onDeviceDeleted(cachedDevice: CachedBluetoothDevice) {
devicePreferenceMap.remove(cachedDevice)?.let {
mDeviceListGroup!!.removePreference(it)
}
}
@VisibleForTesting
open fun enableScanning() {
// BluetoothAdapter already handles repeated scan requests
if (!mScanEnabled) {
startScanning()
mScanEnabled = true
}
}
@VisibleForTesting
fun disableScanning() {
if (mScanEnabled) {
stopScanning()
mScanEnabled = false
}
}
override fun onScanningStateChanged(started: Boolean) {
if (!started && mScanEnabled) {
startScanning()
}
}
/**
* Return the key of the [PreferenceGroup] that contains the bluetooth devices
*/
abstract val deviceListKey: String
@VisibleForTesting
open fun startScanning() {
if (filter != null) {
startClassicScanning()
} else if (leScanFilters != null) {
startLeScanning()
}
}
@VisibleForTesting
open fun stopScanning() {
if (filter != null) {
stopClassicScanning()
} else if (leScanFilters != null) {
stopLeScanning()
}
}
private fun startClassicScanning() {
if (!mBluetoothAdapter!!.isDiscovering) {
mBluetoothAdapter!!.startDiscovery()
}
}
private fun stopClassicScanning() {
if (mBluetoothAdapter!!.isDiscovering) {
mBluetoothAdapter!!.cancelDiscovery()
}
}
private val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
lifecycleScope?.launch {
withContext(Dispatchers.Default) {
if (mBluetoothAdapter!!.state == BluetoothAdapter.STATE_ON) {
val device = result.device
val cachedDevice = mCachedDeviceManager!!.findDevice(device)
?: mCachedDeviceManager!!.addDevice(device)
createDevicePreference(cachedDevice)
}
}
}
}
override fun onScanFailed(errorCode: Int) {
Log.w(TAG, "BLE Scan failed with error code $errorCode")
}
}
private fun startLeScanning() {
val scanner = mBluetoothAdapter!!.bluetoothLeScanner
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build()
scanner.startScan(leScanFilters, settings, scanCallback)
}
private fun stopLeScanning() {
val scanner = mBluetoothAdapter!!.bluetoothLeScanner
scanner?.stopScan(scanCallback)
}
companion object {
private const val TAG = "DeviceListPreferenceFragment"
private const val KEY_BT_SCAN = "bt_scan"
// Copied from BluetoothDeviceNoNamePreferenceController.java
private const val BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY =
"persist.bluetooth.showdeviceswithoutnames"
}
}

View File

@@ -25,11 +25,14 @@ import android.preference.PreferenceManager.OnActivityResultListener;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
@@ -169,6 +172,15 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
LifecycleOwner viewLifecycleOwner = getViewLifecycleOwner();
for (AbstractPreferenceController controller : mControllers) {
controller.onViewCreated(viewLifecycleOwner);
}
}
@Override
public void onCategoriesChanged(Set<String> categories) {
final String categoryKey = getCategoryKey();

View File

@@ -19,11 +19,9 @@ import android.app.settings.SettingsEnums
import android.content.Context
import android.os.Bundle
import android.telephony.SubscriptionManager
import android.view.View
import android.widget.Switch
import com.android.settings.R
import com.android.settings.SettingsActivity
import com.android.settings.applications.specialaccess.DataSaverController
import com.android.settings.dashboard.DashboardFragment
import com.android.settings.search.BaseSearchIndexProvider
import com.android.settings.widget.SettingsMainSwitchBar
@@ -59,11 +57,6 @@ class DataSaverSummary : DashboardFragment() {
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
use(DataSaverController::class.java).init(viewLifecycleOwner)
}
override fun onResume() {
super.onResume()
dataSaverBackend.addListener(dataSaverBackendListener)

View File

@@ -362,7 +362,8 @@ public final class ChooseLockSettingsHelper {
}
@NonNull public ChooseLockSettingsHelper build() {
if (!mAllowAnyUserId && mUserId != LockPatternUtils.USER_FRP) {
if (!mAllowAnyUserId && mUserId != LockPatternUtils.USER_FRP
&& mUserId != LockPatternUtils.USER_REPAIR_MODE) {
Utils.enforceSameOwner(mActivity, mUserId);
}

View File

@@ -166,8 +166,12 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
mDetails = intent.getCharSequenceExtra(KeyguardManager.EXTRA_DESCRIPTION);
String alternateButton = intent.getStringExtra(
KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL);
boolean frp = KeyguardManager.ACTION_CONFIRM_FRP_CREDENTIAL.equals(intent.getAction());
boolean remoteValidation =
final boolean frp =
KeyguardManager.ACTION_CONFIRM_FRP_CREDENTIAL.equals(intent.getAction());
final boolean repairMode =
KeyguardManager.ACTION_CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL
.equals(intent.getAction());
final boolean remoteValidation =
KeyguardManager.ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL.equals(intent.getAction());
mTaskOverlay = isInternalActivity()
&& intent.getBooleanExtra(KeyguardManager.EXTRA_FORCE_TASK_OVERLAY, false);
@@ -222,6 +226,14 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
.setExternal(true)
.setUserId(LockPatternUtils.USER_FRP)
.show();
} else if (repairMode) {
final ChooseLockSettingsHelper.Builder builder =
new ChooseLockSettingsHelper.Builder(this);
launchedCDC = builder.setHeader(mTitle)
.setDescription(mDetails)
.setExternal(true)
.setUserId(LockPatternUtils.USER_REPAIR_MODE)
.show();
} else if (remoteValidation) {
RemoteLockscreenValidationSession remoteLockscreenValidationSession =
intent.getParcelableExtra(

View File

@@ -106,6 +106,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
protected boolean mFrp;
protected boolean mRemoteValidation;
protected boolean mRequestWriteRepairModePassword;
protected boolean mRepairMode;
protected CharSequence mAlternateButtonText;
protected BiometricManager mBiometricManager;
@Nullable protected RemoteLockscreenValidationSession mRemoteLockscreenValidationSession;
@@ -181,6 +182,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras(),
isInternalActivity());
mFrp = (mUserId == LockPatternUtils.USER_FRP);
mRepairMode = (mUserId == LockPatternUtils.USER_REPAIR_MODE);
mUserManager = UserManager.get(getActivity());
mEffectiveUserId = mUserManager.getCredentialOwnerProfile(mUserId);
mLockPatternUtils = new LockPatternUtils(getActivity());
@@ -269,7 +271,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
// verifyTiedProfileChallenge. In such case, we also wanna show the user message that
// fingerprint is disabled due to device restart.
protected boolean isStrongAuthRequired() {
return mFrp
return mFrp || mRepairMode
|| !mLockPatternUtils.isBiometricAllowedForUser(mEffectiveUserId)
|| !mUserManager.isUserUnlocked(mUserId);
}

View File

@@ -284,6 +284,11 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_header_frp)
: getString(R.string.lockpassword_confirm_your_pin_header_frp);
}
if (mRepairMode) {
return mIsAlpha
? getString(R.string.lockpassword_confirm_repair_mode_password_header)
: getString(R.string.lockpassword_confirm_repair_mode_pin_header);
}
if (mRemoteValidation) {
return getString(R.string.lockpassword_remote_validation_header);
}
@@ -307,6 +312,11 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_details_frp)
: getString(R.string.lockpassword_confirm_your_pin_details_frp);
}
if (mRepairMode) {
return mIsAlpha
? getString(R.string.lockpassword_confirm_repair_mode_password_details)
: getString(R.string.lockpassword_confirm_repair_mode_pin_details);
}
if (mRemoteValidation) {
return getContext().getString(mIsAlpha
? R.string.lockpassword_remote_validation_password_details

View File

@@ -179,7 +179,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
// ability to disable the pattern in L. Remove this block after
// ensuring it's safe to do so. (Note that ConfirmLockPassword
// doesn't have this).
if (!mFrp && !mRemoteValidation
if (!mFrp && !mRemoteValidation && !mRepairMode
&& !mLockPatternUtils.isLockPatternEnabled(mEffectiveUserId)) {
getActivity().setResult(Activity.RESULT_OK);
getActivity().finish();
@@ -308,6 +308,9 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
if (mFrp) {
return getString(R.string.lockpassword_confirm_your_pattern_details_frp);
}
if (mRepairMode) {
return getString(R.string.lockpassword_confirm_repair_mode_pattern_details);
}
if (mRemoteValidation) {
return getString(
R.string.lockpassword_remote_validation_pattern_details);
@@ -402,7 +405,12 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
}
private String getDefaultHeader() {
if (mFrp) return getString(R.string.lockpassword_confirm_your_pattern_header_frp);
if (mFrp) {
return getString(R.string.lockpassword_confirm_your_pattern_header_frp);
}
if (mRepairMode) {
return getString(R.string.lockpassword_confirm_repair_mode_pattern_header);
}
if (mRemoteValidation) {
return getString(R.string.lockpassword_remote_validation_header);
}

View File

@@ -32,7 +32,6 @@ object UsageStatsPageProvider : SettingsPageProvider {
AppListPage(
title = stringResource(R.string.testing_usage_stats),
listModel = rememberContext(::UsageStatsListModel),
primaryUserOnly = true,
)
}
}

View File

@@ -38,6 +38,7 @@ import android.content.pm.ServiceInfo;
import android.view.accessibility.AccessibilityManager;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@@ -93,6 +94,7 @@ public class AccessibilitySettingsForSetupWizardTest {
when(mAccessibilityManager.getInstalledAccessibilityServiceList()).thenReturn(
mAccessibilityServices);
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
}

View File

@@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -29,6 +30,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LifecycleOwner;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
@@ -73,6 +75,7 @@ public class TextReadingPreferenceFragmentForSetupWizardTest {
final LayoutPreference resetPreference =
new LayoutPreference(mContext, R.layout.accessibility_text_reading_reset_button);
doReturn(mContext).when(mFragment).getContext();
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
doReturn(resetPreference).when(mFragment).findPreference(RESET_KEY);
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
}

View File

@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -27,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.app.settings.SettingsEnums;
import android.content.Context;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@@ -75,6 +77,7 @@ public class ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest {
mFragment =
spy(new TestToggleScreenMagnificationPreferenceFragmentForSetupWizard(mContext));
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
}

View File

@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -28,6 +29,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
@@ -72,6 +74,7 @@ public class ToggleScreenReaderPreferenceFragmentForSetupWizardTest {
public void setUp() {
mFragment = spy(new TestToggleScreenReaderPreferenceFragmentForSetupWizard(mContext));
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
}

View File

@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -28,6 +29,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
@@ -72,6 +74,7 @@ public class ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest {
public void setUp() {
mFragment = spy(new TestToggleSelectToSpeakPreferenceFragmentForSetupWizard(mContext));
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
}

View File

@@ -352,6 +352,19 @@ public class FingerprintEnrollEnrollingTest {
assertThat(descriptionTextView.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void fingerprintUdfpsOverlayEnrollment_udfpsAnimationViewVisibility() {
initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL);
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
createActivity();
final UdfpsEnrollView enrollView = mActivity.findViewById(R.id.udfps_animation_view);
assertThat(enrollView.getVisibility()).isEqualTo(View.GONE);
mActivity.onUdfpsOverlayShown();
assertThat(enrollView.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void forwardEnrollProgressEvents() {
initializeActivityFor(TYPE_UDFPS_OPTICAL);
@@ -393,11 +406,11 @@ public class FingerprintEnrollEnrollingTest {
}
@Test
public void forwardEnrollPointerDownEvents() {
public void forwardUdfpsEnrollPointerDownEvents() {
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
mActivity.onPointerDown(0);
mActivity.onUdfpsPointerDown(0);
assertThat(listener.mProgress).isFalse();
assertThat(listener.mHelp).isFalse();
assertThat(listener.mAcquired).isFalse();
@@ -406,11 +419,11 @@ public class FingerprintEnrollEnrollingTest {
}
@Test
public void forwardEnrollPointerUpEvents() {
public void forwardUdfpsEnrollPointerUpEvents() {
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
mActivity.onPointerUp(0);
mActivity.onUdfpsPointerUp(0);
assertThat(listener.mProgress).isFalse();
assertThat(listener.mHelp).isFalse();
assertThat(listener.mAcquired).isFalse();

View File

@@ -202,7 +202,7 @@ public class BluetoothDevicePairingDetailBaseTest {
new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
true, BluetoothDevicePreference.SortType.TYPE_FIFO);
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
mFragment.mDevicePreferenceMap.put(mCachedBluetoothDevice, preference);
mFragment.getDevicePreferenceMap().put(mCachedBluetoothDevice, preference);
when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
@@ -210,7 +210,7 @@ public class BluetoothDevicePairingDetailBaseTest {
mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
assertThat(mFragment.mDevicePreferenceMap.size()).isEqualTo(0);
assertThat(mFragment.getDevicePreferenceMap().size()).isEqualTo(0);
}
@Test
@@ -221,7 +221,7 @@ public class BluetoothDevicePairingDetailBaseTest {
true, BluetoothDevicePreference.SortType.TYPE_FIFO);
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
final BluetoothDevice device2 = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
mFragment.mDevicePreferenceMap.put(mCachedBluetoothDevice, preference);
mFragment.getDevicePreferenceMap().put(mCachedBluetoothDevice, preference);
when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
when(mCachedBluetoothDevice.getDevice()).thenReturn(device);

View File

@@ -27,7 +27,12 @@ import static org.mockito.Mockito.verify;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.test.core.app.ApplicationProvider;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
@@ -53,6 +58,20 @@ public class BluetoothPairingDetailTest {
private final Context mContext = ApplicationProvider.getApplicationContext();
private final Lifecycle mFakeLifecycle = new Lifecycle() {
@Override
public void addObserver(@NonNull LifecycleObserver observer) {}
@Override
public void removeObserver(@NonNull LifecycleObserver observer) {}
@NonNull
@Override
public State getCurrentState() {
return State.CREATED;
}
};
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private LocalBluetoothManager mLocalManager;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -74,6 +93,8 @@ public class BluetoothPairingDetailTest {
.findPreference(BluetoothPairingDetail.KEY_AVAIL_DEVICES);
doReturn(mFooterPreference).when(mFragment)
.findPreference(BluetoothPairingDetail.KEY_FOOTER_PREF);
doReturn(new View(mContext)).when(mFragment).getView();
doReturn((LifecycleOwner) () -> mFakeLifecycle).when(mFragment).getViewLifecycleOwner();
doReturn(Collections.emptyList()).when(mDeviceManager).getCachedDevicesCopy();
mFragment.mBluetoothAdapter = mBluetoothAdapter;
@@ -82,7 +103,7 @@ public class BluetoothPairingDetailTest {
mFragment.mDeviceListGroup = mAvailableDevicesCategory;
mFragment.onViewCreated(mFragment.getView(), Bundle.EMPTY);
}
//
@Test
public void initPreferencesFromPreferenceScreen_findPreferences() {
mFragment.initPreferencesFromPreferenceScreen();

View File

@@ -379,7 +379,7 @@ public class FingerprintEnrollProgressViewModelTest {
// Notify acquire message
final int value = 33;
mCallbackWrapper.mValue.onPointerDown(value);
mCallbackWrapper.mValue.onUdfpsPointerDown(value);
assertThat(liveData.getValue()).isEqualTo(value);
}
@@ -397,7 +397,7 @@ public class FingerprintEnrollProgressViewModelTest {
// Notify acquire message
final int value = 44;
mCallbackWrapper.mValue.onPointerUp(value);
mCallbackWrapper.mValue.onUdfpsPointerUp(value);
assertThat(liveData.getValue()).isEqualTo(value);
}