Snap for 10330433 from a1fd330fb5 to udc-qpr1-release
Change-Id: I8c6d13f66574e626026aa37052d1476c760fd516
This commit is contained in:
@@ -2398,6 +2398,7 @@
|
|||||||
<action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL" />
|
<action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL" />
|
||||||
<action android:name="android.app.action.CONFIRM_FRP_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.PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL" />
|
||||||
|
<action android:name="android.app.action.CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/udfps_animation_view"
|
android:id="@+id/udfps_animation_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/udfps_enroll_animation_fp_progress_view"
|
android:id="@+id/udfps_enroll_animation_fp_progress_view"
|
||||||
|
|||||||
@@ -3495,6 +3495,18 @@
|
|||||||
<!-- Checkbox label to set password as new screen lock if remote device credential validation succeeds. [CHAR LIMIT=43] -->
|
<!-- 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>
|
<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
|
<!-- Security & location settings screen, change security method screen instruction if user
|
||||||
enters incorrect PIN [CHAR LIMIT=30] -->
|
enters incorrect PIN [CHAR LIMIT=30] -->
|
||||||
|
|||||||
@@ -708,9 +708,13 @@ public final class Utils extends com.android.settingslib.Utils {
|
|||||||
final int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
|
final int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
|
||||||
if (userId == LockPatternUtils.USER_FRP) {
|
if (userId == LockPatternUtils.USER_FRP) {
|
||||||
return allowAnyUser ? userId : checkUserOwnsFrpCredential(context, userId);
|
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.");
|
+ " 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.
|
* Returns the given user id if it belongs to the current user.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class DataSaverController(context: Context, key: String) : BasePreferenceControl
|
|||||||
preference = screen.findPreference(preferenceKey)!!
|
preference = screen.findPreference(preferenceKey)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun init(viewLifecycleOwner: LifecycleOwner) {
|
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
preference.summary = getUnrestrictedSummary(mContext)
|
preference.summary = getUnrestrictedSummary(mContext)
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGE_DE
|
|||||||
|
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.os.Bundle;
|
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.R;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
@@ -50,12 +46,6 @@ public class SpecialAccessSettings extends DashboardFragment {
|
|||||||
MANAGE_DEVICE_ADMIN_APPS, R.string.manage_device_admin);
|
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
|
@Override
|
||||||
protected int getPreferenceScreenResId() {
|
protected int getPreferenceScreenResId() {
|
||||||
return R.xml.special_access;
|
return R.xml.special_access;
|
||||||
|
|||||||
@@ -48,11 +48,16 @@ public abstract class BiometricEnrollSidecar extends InstrumentedFragment {
|
|||||||
/**
|
/**
|
||||||
* Called when a pointer down event has occurred.
|
* 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.
|
* 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;
|
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;
|
private final int sensorId;
|
||||||
|
|
||||||
public QueuedPointerDown(int sensorId) {
|
QueuedUdfpsPointerDown(int sensorId) {
|
||||||
this.sensorId = sensorId;
|
this.sensorId = sensorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(Listener listener) {
|
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;
|
private final int sensorId;
|
||||||
|
|
||||||
public QueuedPointerUp(int sensorId) {
|
QueuedUdfpsPointerUp(int sensorId) {
|
||||||
this.sensorId = sensorId;
|
this.sensorId = sensorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(Listener listener) {
|
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) {
|
if (mListener != null) {
|
||||||
mListener.onPointerDown(sensorId);
|
mListener.onUdfpsPointerDown(sensorId);
|
||||||
} else {
|
} else {
|
||||||
mQueuedEvents.add(new QueuedPointerDown(sensorId));
|
mQueuedEvents.add(new QueuedUdfpsPointerDown(sensorId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onPointerUp(int sensorId) {
|
protected void onUdfpsPointerUp(int sensorId) {
|
||||||
if (mListener != null) {
|
if (mListener != null) {
|
||||||
mListener.onPointerUp(sensorId);
|
mListener.onUdfpsPointerUp(sensorId);
|
||||||
} else {
|
} else {
|
||||||
mQueuedEvents.add(new QueuedPointerUp(sensorId));
|
mQueuedEvents.add(new QueuedUdfpsPointerUp(sensorId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onUdfpsOverlayShown() {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onUdfpsOverlayShown();
|
||||||
|
} else {
|
||||||
|
mQueuedEvents.add(new QueuedUdfpsOverlayShown());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -828,19 +828,26 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPointerDown(int sensorId) {
|
public void onUdfpsPointerDown(int sensorId) {
|
||||||
if (mUdfpsEnrollHelper != null) {
|
if (mUdfpsEnrollHelper != null) {
|
||||||
mUdfpsEnrollHelper.onPointerDown(sensorId);
|
mUdfpsEnrollHelper.onPointerDown(sensorId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPointerUp(int sensorId) {
|
public void onUdfpsPointerUp(int sensorId) {
|
||||||
if (mUdfpsEnrollHelper != null) {
|
if (mUdfpsEnrollHelper != null) {
|
||||||
mUdfpsEnrollHelper.onPointerUp(sensorId);
|
mUdfpsEnrollHelper.onPointerUp(sensorId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUdfpsOverlayShown() {
|
||||||
|
if (mCanAssumeUdfps) {
|
||||||
|
findViewById(R.id.udfps_animation_view).setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateProgress(boolean animate) {
|
private void updateProgress(boolean animate) {
|
||||||
if (mSidecar == null || !mSidecar.isEnrolling()) {
|
if (mSidecar == null || !mSidecar.isEnrolling()) {
|
||||||
Log.d(TAG, "Enrollment not started yet");
|
Log.d(TAG, "Enrollment not started yet");
|
||||||
|
|||||||
@@ -124,13 +124,18 @@ public class FingerprintEnrollSidecar extends BiometricEnrollSidecar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPointerDown(int sensorId) {
|
public void onUdfpsPointerDown(int sensorId) {
|
||||||
FingerprintEnrollSidecar.super.onPointerDown(sensorId);
|
FingerprintEnrollSidecar.super.onUdfpsPointerDown(sensorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPointerUp(int sensorId) {
|
public void onUdfpsPointerUp(int sensorId) {
|
||||||
FingerprintEnrollSidecar.super.onPointerUp(sensorId);
|
FingerprintEnrollSidecar.super.onUdfpsPointerUp(sensorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUdfpsOverlayShown() {
|
||||||
|
FingerprintEnrollSidecar.super.onUdfpsOverlayShown();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -98,13 +98,18 @@ public class FingerprintUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPointerDown(int sensorId) {
|
public void onUdfpsPointerDown(int sensorId) {
|
||||||
mCallback.onPointerDown(sensorId);
|
mCallback.onUdfpsPointerDown(sensorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPointerUp(int sensorId) {
|
public void onUdfpsPointerUp(int sensorId) {
|
||||||
mCallback.onPointerUp(sensorId);
|
mCallback.onUdfpsPointerUp(sensorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUdfpsOverlayShown() {
|
||||||
|
mCallback.onUdfpsOverlayShown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public class UdfpsEnrollEnrollingView extends GlifLayout {
|
|||||||
UdfpsEnrollHelper udfpsEnrollHelper,
|
UdfpsEnrollHelper udfpsEnrollHelper,
|
||||||
AccessibilityManager accessibilityManager) {
|
AccessibilityManager accessibilityManager) {
|
||||||
mAccessibilityManager = accessibilityManager;
|
mAccessibilityManager = accessibilityManager;
|
||||||
initUdfpsEnrollView(mUdfpsEnrollView, udfpsProps, udfpsEnrollHelper);
|
initUdfpsEnrollView(udfpsProps, udfpsEnrollHelper);
|
||||||
|
|
||||||
if (!mIsLandscape) {
|
if (!mIsLandscape) {
|
||||||
adjustPortraitPaddings();
|
adjustPortraitPaddings();
|
||||||
@@ -117,8 +117,7 @@ public class UdfpsEnrollEnrollingView extends GlifLayout {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initUdfpsEnrollView(UdfpsEnrollView udfpsEnrollView,
|
private void initUdfpsEnrollView(FingerprintSensorPropertiesInternal udfpsProps,
|
||||||
FingerprintSensorPropertiesInternal udfpsProps,
|
|
||||||
UdfpsEnrollHelper udfpsEnrollHelper) {
|
UdfpsEnrollHelper udfpsEnrollHelper) {
|
||||||
DisplayInfo displayInfo = new DisplayInfo();
|
DisplayInfo displayInfo = new DisplayInfo();
|
||||||
mContext.getDisplay().getDisplayInfo(displayInfo);
|
mContext.getDisplay().getDisplayInfo(displayInfo);
|
||||||
@@ -141,8 +140,8 @@ public class UdfpsEnrollEnrollingView extends GlifLayout {
|
|||||||
scaleFactor,
|
scaleFactor,
|
||||||
displayInfo.rotation);
|
displayInfo.rotation);
|
||||||
|
|
||||||
udfpsEnrollView.setOverlayParams(params);
|
mUdfpsEnrollView.setOverlayParams(params);
|
||||||
udfpsEnrollView.setEnrollHelper(udfpsEnrollHelper);
|
mUdfpsEnrollView.setEnrollHelper(udfpsEnrollHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void adjustPortraitPaddings() {
|
private void adjustPortraitPaddings() {
|
||||||
|
|||||||
@@ -103,12 +103,12 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPointerDown(int sensorId) {
|
public void onUdfpsPointerDown(int sensorId) {
|
||||||
mPointerDownLiveData.postValue(sensorId);
|
mPointerDownLiveData.postValue(sensorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPointerUp(int sensorId) {
|
public void onUdfpsPointerUp(int sensorId) {
|
||||||
mPointerUpLiveData.postValue(sensorId);
|
mPointerUpLiveData.postValue(sensorId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
if (device != null && mSelectedList.contains(device)) {
|
if (device != null && mSelectedList.contains(device)) {
|
||||||
setResult(RESULT_OK);
|
setResult(RESULT_OK);
|
||||||
finish();
|
finish();
|
||||||
} else if (mDevicePreferenceMap.containsKey(cachedDevice)) {
|
} else {
|
||||||
onDeviceDeleted(cachedDevice);
|
onDeviceDeleted(cachedDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,8 +175,6 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
public void updateContent(int bluetoothState) {
|
public void updateContent(int bluetoothState) {
|
||||||
switch (bluetoothState) {
|
switch (bluetoothState) {
|
||||||
case BluetoothAdapter.STATE_ON:
|
case BluetoothAdapter.STATE_ON:
|
||||||
mDevicePreferenceMap.clear();
|
|
||||||
clearPreferenceGroupCache();
|
|
||||||
mBluetoothAdapter.enable();
|
mBluetoothAdapter.enable();
|
||||||
enableScanning();
|
enableScanning();
|
||||||
break;
|
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
|
@VisibleForTesting
|
||||||
void showBluetoothTurnedOnToast() {
|
void showBluetoothTurnedOnToast() {
|
||||||
Toast.makeText(getContext(), R.string.connected_device_bluetooth_turned_on_toast,
|
Toast.makeText(getContext(), R.string.connected_device_bluetooth_turned_on_toast,
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 android.widget.ImageView;
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -52,6 +54,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BluetoothDevicePreference is the preference type used to display each remote
|
* BluetoothDevicePreference is the preference type used to display each remote
|
||||||
@@ -79,7 +82,9 @@ public final class BluetoothDevicePreference extends GearPreference {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BluetoothAdapter mBluetoothAdapter;
|
BluetoothAdapter mBluetoothAdapter;
|
||||||
private final boolean mShowDevicesWithoutNames;
|
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 final int mType;
|
||||||
|
|
||||||
private AlertDialog mDisconnectDialog;
|
private AlertDialog mDisconnectDialog;
|
||||||
@@ -127,8 +132,9 @@ public final class BluetoothDevicePreference extends GearPreference {
|
|||||||
|
|
||||||
mCachedDevice = cachedDevice;
|
mCachedDevice = cachedDevice;
|
||||||
mCallback = new BluetoothDevicePreferenceCallback();
|
mCallback = new BluetoothDevicePreferenceCallback();
|
||||||
mCurrentTime = System.currentTimeMillis();
|
mId = sNextId.getAndIncrement();
|
||||||
mType = type;
|
mType = type;
|
||||||
|
setVisible(false);
|
||||||
|
|
||||||
onPreferenceAttributesChanged();
|
onPreferenceAttributesChanged();
|
||||||
}
|
}
|
||||||
@@ -229,35 +235,41 @@ public final class BluetoothDevicePreference extends GearPreference {
|
|||||||
|
|
||||||
@SuppressWarnings("FutureReturnValueIgnored")
|
@SuppressWarnings("FutureReturnValueIgnored")
|
||||||
void onPreferenceAttributesChanged() {
|
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 {
|
try {
|
||||||
ThreadUtils.postOnBackgroundThread(() -> {
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
|
@Nullable String name = mCachedDevice.getName();
|
||||||
// Null check is done at the framework
|
// 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) {
|
} catch (RejectedExecutionException e) {
|
||||||
Log.w(TAG, "Handler thread unavailable, skipping getConnectionSummary!");
|
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
|
@Override
|
||||||
@@ -311,7 +323,7 @@ public final class BluetoothDevicePreference extends GearPreference {
|
|||||||
return mCachedDevice
|
return mCachedDevice
|
||||||
.compareTo(((BluetoothDevicePreference) another).mCachedDevice);
|
.compareTo(((BluetoothDevicePreference) another).mCachedDevice);
|
||||||
case SortType.TYPE_FIFO:
|
case SortType.TYPE_FIFO:
|
||||||
return mCurrentTime > ((BluetoothDevicePreference) another).mCurrentTime ? 1 : -1;
|
return mId > ((BluetoothDevicePreference) another).mId ? 1 : -1;
|
||||||
default:
|
default:
|
||||||
return super.compareTo(another);
|
return super.compareTo(another);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,11 +25,14 @@ import android.preference.PreferenceManager.OnActivityResultListener;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.lifecycle.LifecycleObserver;
|
import androidx.lifecycle.LifecycleObserver;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceCategory;
|
import androidx.preference.PreferenceCategory;
|
||||||
import androidx.preference.PreferenceGroup;
|
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
|
@Override
|
||||||
public void onCategoriesChanged(Set<String> categories) {
|
public void onCategoriesChanged(Set<String> categories) {
|
||||||
final String categoryKey = getCategoryKey();
|
final String categoryKey = getCategoryKey();
|
||||||
|
|||||||
@@ -19,11 +19,9 @@ import android.app.settings.SettingsEnums
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.telephony.SubscriptionManager
|
import android.telephony.SubscriptionManager
|
||||||
import android.view.View
|
|
||||||
import android.widget.Switch
|
import android.widget.Switch
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.SettingsActivity
|
import com.android.settings.SettingsActivity
|
||||||
import com.android.settings.applications.specialaccess.DataSaverController
|
|
||||||
import com.android.settings.dashboard.DashboardFragment
|
import com.android.settings.dashboard.DashboardFragment
|
||||||
import com.android.settings.search.BaseSearchIndexProvider
|
import com.android.settings.search.BaseSearchIndexProvider
|
||||||
import com.android.settings.widget.SettingsMainSwitchBar
|
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() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
dataSaverBackend.addListener(dataSaverBackendListener)
|
dataSaverBackend.addListener(dataSaverBackendListener)
|
||||||
|
|||||||
@@ -362,7 +362,8 @@ public final class ChooseLockSettingsHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull public ChooseLockSettingsHelper build() {
|
@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);
|
Utils.enforceSameOwner(mActivity, mUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,8 +166,12 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
|
|||||||
mDetails = intent.getCharSequenceExtra(KeyguardManager.EXTRA_DESCRIPTION);
|
mDetails = intent.getCharSequenceExtra(KeyguardManager.EXTRA_DESCRIPTION);
|
||||||
String alternateButton = intent.getStringExtra(
|
String alternateButton = intent.getStringExtra(
|
||||||
KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL);
|
KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL);
|
||||||
boolean frp = KeyguardManager.ACTION_CONFIRM_FRP_CREDENTIAL.equals(intent.getAction());
|
final boolean frp =
|
||||||
boolean remoteValidation =
|
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());
|
KeyguardManager.ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL.equals(intent.getAction());
|
||||||
mTaskOverlay = isInternalActivity()
|
mTaskOverlay = isInternalActivity()
|
||||||
&& intent.getBooleanExtra(KeyguardManager.EXTRA_FORCE_TASK_OVERLAY, false);
|
&& intent.getBooleanExtra(KeyguardManager.EXTRA_FORCE_TASK_OVERLAY, false);
|
||||||
@@ -222,6 +226,14 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
|
|||||||
.setExternal(true)
|
.setExternal(true)
|
||||||
.setUserId(LockPatternUtils.USER_FRP)
|
.setUserId(LockPatternUtils.USER_FRP)
|
||||||
.show();
|
.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) {
|
} else if (remoteValidation) {
|
||||||
RemoteLockscreenValidationSession remoteLockscreenValidationSession =
|
RemoteLockscreenValidationSession remoteLockscreenValidationSession =
|
||||||
intent.getParcelableExtra(
|
intent.getParcelableExtra(
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
|||||||
protected boolean mFrp;
|
protected boolean mFrp;
|
||||||
protected boolean mRemoteValidation;
|
protected boolean mRemoteValidation;
|
||||||
protected boolean mRequestWriteRepairModePassword;
|
protected boolean mRequestWriteRepairModePassword;
|
||||||
|
protected boolean mRepairMode;
|
||||||
protected CharSequence mAlternateButtonText;
|
protected CharSequence mAlternateButtonText;
|
||||||
protected BiometricManager mBiometricManager;
|
protected BiometricManager mBiometricManager;
|
||||||
@Nullable protected RemoteLockscreenValidationSession mRemoteLockscreenValidationSession;
|
@Nullable protected RemoteLockscreenValidationSession mRemoteLockscreenValidationSession;
|
||||||
@@ -181,6 +182,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
|||||||
mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras(),
|
mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras(),
|
||||||
isInternalActivity());
|
isInternalActivity());
|
||||||
mFrp = (mUserId == LockPatternUtils.USER_FRP);
|
mFrp = (mUserId == LockPatternUtils.USER_FRP);
|
||||||
|
mRepairMode = (mUserId == LockPatternUtils.USER_REPAIR_MODE);
|
||||||
mUserManager = UserManager.get(getActivity());
|
mUserManager = UserManager.get(getActivity());
|
||||||
mEffectiveUserId = mUserManager.getCredentialOwnerProfile(mUserId);
|
mEffectiveUserId = mUserManager.getCredentialOwnerProfile(mUserId);
|
||||||
mLockPatternUtils = new LockPatternUtils(getActivity());
|
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
|
// verifyTiedProfileChallenge. In such case, we also wanna show the user message that
|
||||||
// fingerprint is disabled due to device restart.
|
// fingerprint is disabled due to device restart.
|
||||||
protected boolean isStrongAuthRequired() {
|
protected boolean isStrongAuthRequired() {
|
||||||
return mFrp
|
return mFrp || mRepairMode
|
||||||
|| !mLockPatternUtils.isBiometricAllowedForUser(mEffectiveUserId)
|
|| !mLockPatternUtils.isBiometricAllowedForUser(mEffectiveUserId)
|
||||||
|| !mUserManager.isUserUnlocked(mUserId);
|
|| !mUserManager.isUserUnlocked(mUserId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,6 +284,11 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
|||||||
return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_header_frp)
|
return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_header_frp)
|
||||||
: getString(R.string.lockpassword_confirm_your_pin_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) {
|
if (mRemoteValidation) {
|
||||||
return getString(R.string.lockpassword_remote_validation_header);
|
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)
|
return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_details_frp)
|
||||||
: getString(R.string.lockpassword_confirm_your_pin_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) {
|
if (mRemoteValidation) {
|
||||||
return getContext().getString(mIsAlpha
|
return getContext().getString(mIsAlpha
|
||||||
? R.string.lockpassword_remote_validation_password_details
|
? R.string.lockpassword_remote_validation_password_details
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
|||||||
// ability to disable the pattern in L. Remove this block after
|
// ability to disable the pattern in L. Remove this block after
|
||||||
// ensuring it's safe to do so. (Note that ConfirmLockPassword
|
// ensuring it's safe to do so. (Note that ConfirmLockPassword
|
||||||
// doesn't have this).
|
// doesn't have this).
|
||||||
if (!mFrp && !mRemoteValidation
|
if (!mFrp && !mRemoteValidation && !mRepairMode
|
||||||
&& !mLockPatternUtils.isLockPatternEnabled(mEffectiveUserId)) {
|
&& !mLockPatternUtils.isLockPatternEnabled(mEffectiveUserId)) {
|
||||||
getActivity().setResult(Activity.RESULT_OK);
|
getActivity().setResult(Activity.RESULT_OK);
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
@@ -308,6 +308,9 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
|||||||
if (mFrp) {
|
if (mFrp) {
|
||||||
return getString(R.string.lockpassword_confirm_your_pattern_details_frp);
|
return getString(R.string.lockpassword_confirm_your_pattern_details_frp);
|
||||||
}
|
}
|
||||||
|
if (mRepairMode) {
|
||||||
|
return getString(R.string.lockpassword_confirm_repair_mode_pattern_details);
|
||||||
|
}
|
||||||
if (mRemoteValidation) {
|
if (mRemoteValidation) {
|
||||||
return getString(
|
return getString(
|
||||||
R.string.lockpassword_remote_validation_pattern_details);
|
R.string.lockpassword_remote_validation_pattern_details);
|
||||||
@@ -402,7 +405,12 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getDefaultHeader() {
|
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) {
|
if (mRemoteValidation) {
|
||||||
return getString(R.string.lockpassword_remote_validation_header);
|
return getString(R.string.lockpassword_remote_validation_header);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ object UsageStatsPageProvider : SettingsPageProvider {
|
|||||||
AppListPage(
|
AppListPage(
|
||||||
title = stringResource(R.string.testing_usage_stats),
|
title = stringResource(R.string.testing_usage_stats),
|
||||||
listModel = rememberContext(::UsageStatsListModel),
|
listModel = rememberContext(::UsageStatsListModel),
|
||||||
primaryUserOnly = true,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import android.content.pm.ServiceInfo;
|
|||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
@@ -93,6 +94,7 @@ public class AccessibilitySettingsForSetupWizardTest {
|
|||||||
when(mAccessibilityManager.getInstalledAccessibilityServiceList()).thenReturn(
|
when(mAccessibilityManager.getInstalledAccessibilityServiceList()).thenReturn(
|
||||||
mAccessibilityServices);
|
mAccessibilityServices);
|
||||||
doReturn(mActivity).when(mFragment).getActivity();
|
doReturn(mActivity).when(mFragment).getActivity();
|
||||||
|
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
|
||||||
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ import android.app.settings.SettingsEnums;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
@@ -73,6 +75,7 @@ public class TextReadingPreferenceFragmentForSetupWizardTest {
|
|||||||
final LayoutPreference resetPreference =
|
final LayoutPreference resetPreference =
|
||||||
new LayoutPreference(mContext, R.layout.accessibility_text_reading_reset_button);
|
new LayoutPreference(mContext, R.layout.accessibility_text_reading_reset_button);
|
||||||
doReturn(mContext).when(mFragment).getContext();
|
doReturn(mContext).when(mFragment).getContext();
|
||||||
|
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
|
||||||
doReturn(resetPreference).when(mFragment).findPreference(RESET_KEY);
|
doReturn(resetPreference).when(mFragment).findPreference(RESET_KEY);
|
||||||
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -27,6 +28,7 @@ import static org.mockito.Mockito.when;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
@@ -75,6 +77,7 @@ public class ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest {
|
|||||||
mFragment =
|
mFragment =
|
||||||
spy(new TestToggleScreenMagnificationPreferenceFragmentForSetupWizard(mContext));
|
spy(new TestToggleScreenMagnificationPreferenceFragmentForSetupWizard(mContext));
|
||||||
doReturn(mActivity).when(mFragment).getActivity();
|
doReturn(mActivity).when(mFragment).getActivity();
|
||||||
|
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
|
||||||
when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
|
when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
|
||||||
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -28,6 +29,7 @@ import android.app.settings.SettingsEnums;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@@ -72,6 +74,7 @@ public class ToggleScreenReaderPreferenceFragmentForSetupWizardTest {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
mFragment = spy(new TestToggleScreenReaderPreferenceFragmentForSetupWizard(mContext));
|
mFragment = spy(new TestToggleScreenReaderPreferenceFragmentForSetupWizard(mContext));
|
||||||
doReturn(mActivity).when(mFragment).getActivity();
|
doReturn(mActivity).when(mFragment).getActivity();
|
||||||
|
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
|
||||||
when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
|
when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
|
||||||
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -28,6 +29,7 @@ import android.app.settings.SettingsEnums;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@@ -72,6 +74,7 @@ public class ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
mFragment = spy(new TestToggleSelectToSpeakPreferenceFragmentForSetupWizard(mContext));
|
mFragment = spy(new TestToggleSelectToSpeakPreferenceFragmentForSetupWizard(mContext));
|
||||||
doReturn(mActivity).when(mFragment).getActivity();
|
doReturn(mActivity).when(mFragment).getActivity();
|
||||||
|
doReturn(mock(LifecycleOwner.class)).when(mFragment).getViewLifecycleOwner();
|
||||||
when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
|
when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
|
||||||
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -352,6 +352,19 @@ public class FingerprintEnrollEnrollingTest {
|
|||||||
assertThat(descriptionTextView.getVisibility()).isEqualTo(View.VISIBLE);
|
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
|
@Test
|
||||||
public void forwardEnrollProgressEvents() {
|
public void forwardEnrollProgressEvents() {
|
||||||
initializeActivityFor(TYPE_UDFPS_OPTICAL);
|
initializeActivityFor(TYPE_UDFPS_OPTICAL);
|
||||||
@@ -393,11 +406,11 @@ public class FingerprintEnrollEnrollingTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forwardEnrollPointerDownEvents() {
|
public void forwardUdfpsEnrollPointerDownEvents() {
|
||||||
initializeActivityFor(TYPE_UDFPS_OPTICAL);
|
initializeActivityFor(TYPE_UDFPS_OPTICAL);
|
||||||
|
|
||||||
EnrollListener listener = new EnrollListener(mActivity);
|
EnrollListener listener = new EnrollListener(mActivity);
|
||||||
mActivity.onPointerDown(0);
|
mActivity.onUdfpsPointerDown(0);
|
||||||
assertThat(listener.mProgress).isFalse();
|
assertThat(listener.mProgress).isFalse();
|
||||||
assertThat(listener.mHelp).isFalse();
|
assertThat(listener.mHelp).isFalse();
|
||||||
assertThat(listener.mAcquired).isFalse();
|
assertThat(listener.mAcquired).isFalse();
|
||||||
@@ -406,11 +419,11 @@ public class FingerprintEnrollEnrollingTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forwardEnrollPointerUpEvents() {
|
public void forwardUdfpsEnrollPointerUpEvents() {
|
||||||
initializeActivityFor(TYPE_UDFPS_OPTICAL);
|
initializeActivityFor(TYPE_UDFPS_OPTICAL);
|
||||||
|
|
||||||
EnrollListener listener = new EnrollListener(mActivity);
|
EnrollListener listener = new EnrollListener(mActivity);
|
||||||
mActivity.onPointerUp(0);
|
mActivity.onUdfpsPointerUp(0);
|
||||||
assertThat(listener.mProgress).isFalse();
|
assertThat(listener.mProgress).isFalse();
|
||||||
assertThat(listener.mHelp).isFalse();
|
assertThat(listener.mHelp).isFalse();
|
||||||
assertThat(listener.mAcquired).isFalse();
|
assertThat(listener.mAcquired).isFalse();
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
|
new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
|
||||||
true, BluetoothDevicePreference.SortType.TYPE_FIFO);
|
true, BluetoothDevicePreference.SortType.TYPE_FIFO);
|
||||||
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
|
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.isConnected()).thenReturn(true);
|
||||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
|
||||||
@@ -210,7 +210,7 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
|
mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
|
||||||
BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
|
BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
|
||||||
|
|
||||||
assertThat(mFragment.mDevicePreferenceMap.size()).isEqualTo(0);
|
assertThat(mFragment.getDevicePreferenceMap().size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -221,7 +221,7 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
true, BluetoothDevicePreference.SortType.TYPE_FIFO);
|
true, BluetoothDevicePreference.SortType.TYPE_FIFO);
|
||||||
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
|
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
|
||||||
final BluetoothDevice device2 = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
|
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.isConnected()).thenReturn(true);
|
||||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
|
||||||
|
|||||||
@@ -27,7 +27,12 @@ import static org.mockito.Mockito.verify;
|
|||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
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 androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||||
@@ -53,6 +58,20 @@ public class BluetoothPairingDetailTest {
|
|||||||
|
|
||||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
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)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
private LocalBluetoothManager mLocalManager;
|
private LocalBluetoothManager mLocalManager;
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
@@ -74,6 +93,8 @@ public class BluetoothPairingDetailTest {
|
|||||||
.findPreference(BluetoothPairingDetail.KEY_AVAIL_DEVICES);
|
.findPreference(BluetoothPairingDetail.KEY_AVAIL_DEVICES);
|
||||||
doReturn(mFooterPreference).when(mFragment)
|
doReturn(mFooterPreference).when(mFragment)
|
||||||
.findPreference(BluetoothPairingDetail.KEY_FOOTER_PREF);
|
.findPreference(BluetoothPairingDetail.KEY_FOOTER_PREF);
|
||||||
|
doReturn(new View(mContext)).when(mFragment).getView();
|
||||||
|
doReturn((LifecycleOwner) () -> mFakeLifecycle).when(mFragment).getViewLifecycleOwner();
|
||||||
doReturn(Collections.emptyList()).when(mDeviceManager).getCachedDevicesCopy();
|
doReturn(Collections.emptyList()).when(mDeviceManager).getCachedDevicesCopy();
|
||||||
|
|
||||||
mFragment.mBluetoothAdapter = mBluetoothAdapter;
|
mFragment.mBluetoothAdapter = mBluetoothAdapter;
|
||||||
@@ -82,7 +103,7 @@ public class BluetoothPairingDetailTest {
|
|||||||
mFragment.mDeviceListGroup = mAvailableDevicesCategory;
|
mFragment.mDeviceListGroup = mAvailableDevicesCategory;
|
||||||
mFragment.onViewCreated(mFragment.getView(), Bundle.EMPTY);
|
mFragment.onViewCreated(mFragment.getView(), Bundle.EMPTY);
|
||||||
}
|
}
|
||||||
//
|
|
||||||
@Test
|
@Test
|
||||||
public void initPreferencesFromPreferenceScreen_findPreferences() {
|
public void initPreferencesFromPreferenceScreen_findPreferences() {
|
||||||
mFragment.initPreferencesFromPreferenceScreen();
|
mFragment.initPreferencesFromPreferenceScreen();
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ public class FingerprintEnrollProgressViewModelTest {
|
|||||||
|
|
||||||
// Notify acquire message
|
// Notify acquire message
|
||||||
final int value = 33;
|
final int value = 33;
|
||||||
mCallbackWrapper.mValue.onPointerDown(value);
|
mCallbackWrapper.mValue.onUdfpsPointerDown(value);
|
||||||
assertThat(liveData.getValue()).isEqualTo(value);
|
assertThat(liveData.getValue()).isEqualTo(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,7 +397,7 @@ public class FingerprintEnrollProgressViewModelTest {
|
|||||||
|
|
||||||
// Notify acquire message
|
// Notify acquire message
|
||||||
final int value = 44;
|
final int value = 44;
|
||||||
mCallbackWrapper.mValue.onPointerUp(value);
|
mCallbackWrapper.mValue.onUdfpsPointerUp(value);
|
||||||
assertThat(liveData.getValue()).isEqualTo(value);
|
assertThat(liveData.getValue()).isEqualTo(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user