Pass CachedBluetoothDevice into StylusDevicesController.

Styluses can now be identified using the newly added DEVICE_TYPE_STYLUS
metadata.

Bug: 251200056
Test: StylusDevicesControllerTest
Change-Id: Ie89f6419cd16ed97299944b35497c6b2ee764dab
This commit is contained in:
Vania Januar
2022-12-20 10:24:10 +00:00
parent 2b347d7f2d
commit 57822a67a8
4 changed files with 126 additions and 14 deletions

View File

@@ -312,7 +312,8 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
mCachedDevice, lifecycle)); mCachedDevice, lifecycle));
controllers.add(new BluetoothDetailsMacAddressController(context, this, mCachedDevice, controllers.add(new BluetoothDetailsMacAddressController(context, this, mCachedDevice,
lifecycle)); lifecycle));
controllers.add(new StylusDevicesController(context, mInputDevice, lifecycle)); controllers.add(new StylusDevicesController(context, mInputDevice, mCachedDevice,
lifecycle));
controllers.add(new BluetoothDetailsRelatedToolsController(context, this, mCachedDevice, controllers.add(new BluetoothDetailsRelatedToolsController(context, this, mCachedDevice,
lifecycle)); lifecycle));
controllers.add(new BluetoothDetailsPairOtherController(context, this, mCachedDevice, controllers.add(new BluetoothDetailsPairOtherController(context, this, mCachedDevice,

View File

@@ -17,12 +17,14 @@
package com.android.settings.connecteddevice.stylus; package com.android.settings.connecteddevice.stylus;
import android.app.role.RoleManager; import android.app.role.RoleManager;
import android.bluetooth.BluetoothDevice;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.provider.Settings; import android.provider.Settings;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.InputDevice; import android.view.InputDevice;
@@ -34,6 +36,8 @@ import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference; import androidx.preference.SwitchPreference;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -61,18 +65,23 @@ public class StylusDevicesController extends AbstractPreferenceController implem
@Nullable @Nullable
private final InputDevice mInputDevice; private final InputDevice mInputDevice;
@Nullable
private final CachedBluetoothDevice mCachedBluetoothDevice;
@VisibleForTesting @VisibleForTesting
PreferenceCategory mPreferencesContainer; PreferenceCategory mPreferencesContainer;
public StylusDevicesController(Context context, InputDevice inputDevice, Lifecycle lifecycle) { public StylusDevicesController(Context context, InputDevice inputDevice,
CachedBluetoothDevice cachedBluetoothDevice, Lifecycle lifecycle) {
super(context); super(context);
mInputDevice = inputDevice; mInputDevice = inputDevice;
mCachedBluetoothDevice = cachedBluetoothDevice;
lifecycle.addObserver(this); lifecycle.addObserver(this);
} }
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
return mInputDevice != null && mInputDevice.supportsSource(InputDevice.SOURCE_STYLUS); return isDeviceStylus(mInputDevice, mCachedBluetoothDevice);
} }
@Nullable @Nullable
@@ -179,7 +188,6 @@ public class StylusDevicesController extends AbstractPreferenceController implem
private void refresh() { private void refresh() {
if (!isAvailable()) return; if (!isAvailable()) return;
if (mInputDevice.getBluetoothAddress() != null) {
Preference notesPref = mPreferencesContainer.findPreference(KEY_DEFAULT_NOTES); Preference notesPref = mPreferencesContainer.findPreference(KEY_DEFAULT_NOTES);
if (notesPref == null) { if (notesPref == null) {
notesPref = createDefaultNotesPreference(); notesPref = createDefaultNotesPreference();
@@ -187,7 +195,6 @@ public class StylusDevicesController extends AbstractPreferenceController implem
mPreferencesContainer.addPreference(notesPref); mPreferencesContainer.addPreference(notesPref);
} }
} }
}
Preference handwritingPref = mPreferencesContainer.findPreference(KEY_HANDWRITING); Preference handwritingPref = mPreferencesContainer.findPreference(KEY_HANDWRITING);
// TODO(b/255732419): add proper InputMethodInfo conditional to show or hide // TODO(b/255732419): add proper InputMethodInfo conditional to show or hide
@@ -201,4 +208,32 @@ public class StylusDevicesController extends AbstractPreferenceController implem
mPreferencesContainer.addPreference(createButtonPressPreference()); mPreferencesContainer.addPreference(createButtonPressPreference());
} }
} }
/**
* Identifies whether a device is a stylus using the associated {@link InputDevice} or
* {@link CachedBluetoothDevice}.
*
* InputDevices are only available when the device is USI or Bluetooth-connected, whereas
* CachedBluetoothDevices are available for Bluetooth devices when connected or paired,
* so to handle all cases, both are needed.
*
* @param inputDevice The associated input device of the stylus
* @param cachedBluetoothDevice The associated bluetooth device of the stylus
*/
public static boolean isDeviceStylus(@Nullable InputDevice inputDevice,
@Nullable CachedBluetoothDevice cachedBluetoothDevice) {
if (inputDevice != null && inputDevice.supportsSource(InputDevice.SOURCE_STYLUS)) {
return true;
}
if (cachedBluetoothDevice != null) {
BluetoothDevice bluetoothDevice = cachedBluetoothDevice.getDevice();
String deviceType = BluetoothUtils.getStringMetaData(bluetoothDevice,
BluetoothDevice.METADATA_DEVICE_TYPE);
return TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_STYLUS);
}
return false;
}
} }

View File

@@ -77,7 +77,7 @@ public class StylusUsiDetailsFragment extends DashboardFragment {
if (mInputDevice != null) { if (mInputDevice != null) {
Lifecycle lifecycle = getSettingsLifecycle(); Lifecycle lifecycle = getSettingsLifecycle();
controllers.add(new StylusUsiHeaderController(context, mInputDevice)); controllers.add(new StylusUsiHeaderController(context, mInputDevice));
controllers.add(new StylusDevicesController(context, mInputDevice, lifecycle)); controllers.add(new StylusDevicesController(context, mInputDevice, null, lifecycle));
} }
return controllers; return controllers;
} }

View File

@@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.role.RoleManager; import android.app.role.RoleManager;
import android.bluetooth.BluetoothDevice;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
@@ -44,6 +45,7 @@ import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before; import org.junit.Before;
@@ -76,6 +78,10 @@ public class StylusDevicesControllerTest {
private RoleManager mRm; private RoleManager mRm;
@Mock @Mock
private Lifecycle mLifecycle; private Lifecycle mLifecycle;
@Mock
private CachedBluetoothDevice mCachedBluetoothDevice;
@Mock
private BluetoothDevice mBluetoothDevice;
@Before @Before
@@ -101,24 +107,94 @@ public class StylusDevicesControllerTest {
any(PackageManager.ApplicationInfoFlags.class))).thenReturn(new ApplicationInfo()); any(PackageManager.ApplicationInfoFlags.class))).thenReturn(new ApplicationInfo());
when(mPm.getApplicationLabel(any(ApplicationInfo.class))).thenReturn(NOTES_APP_LABEL); when(mPm.getApplicationLabel(any(ApplicationInfo.class))).thenReturn(NOTES_APP_LABEL);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
mInputDevice = spy(new InputDevice.Builder() mInputDevice = spy(new InputDevice.Builder()
.setId(1) .setId(1)
.setSources(InputDevice.SOURCE_STYLUS) .setSources(InputDevice.SOURCE_STYLUS)
.build()); .build());
when(mInputDevice.getBluetoothAddress()).thenReturn("SOME:ADDRESS"); when(mInputDevice.getBluetoothAddress()).thenReturn("SOME:ADDRESS");
mController = new StylusDevicesController(mContext, mInputDevice, mLifecycle); mController = new StylusDevicesController(mContext, mInputDevice, null, mLifecycle);
} }
@Test @Test
public void noInputDevice_noPreference() { public void isDeviceStylus_noDevices_false() {
assertThat(StylusDevicesController.isDeviceStylus(null, null)).isFalse();
}
@Test
public void isDeviceStylus_nonStylusInputDevice_false() {
InputDevice inputDevice = new InputDevice.Builder()
.setSources(InputDevice.SOURCE_DPAD)
.build();
assertThat(StylusDevicesController.isDeviceStylus(inputDevice, null)).isFalse();
}
@Test
public void isDeviceStylus_stylusInputDevice_true() {
InputDevice inputDevice = new InputDevice.Builder()
.setSources(InputDevice.SOURCE_STYLUS)
.build();
assertThat(StylusDevicesController.isDeviceStylus(inputDevice, null)).isTrue();
}
@Test
public void isDeviceStylus_nonStylusBluetoothDevice_false() {
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
BluetoothDevice.DEVICE_TYPE_WATCH.getBytes());
assertThat(StylusDevicesController.isDeviceStylus(null, mCachedBluetoothDevice)).isFalse();
}
@Test
public void isDeviceStylus_stylusBluetoothDevice_true() {
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
BluetoothDevice.DEVICE_TYPE_STYLUS.getBytes());
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
assertThat(StylusDevicesController.isDeviceStylus(null, mCachedBluetoothDevice)).isTrue();
}
@Test
public void noInputDevice_noBluetoothDevice_noPreference() {
StylusDevicesController controller = new StylusDevicesController( StylusDevicesController controller = new StylusDevicesController(
mContext, null, mLifecycle mContext, null, null, mLifecycle
); );
showScreen(controller); showScreen(controller);
assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(0); assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(0);
} }
@Test
public void noInputDevice_nonStylusBluetoothDevice_noPreference() {
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
BluetoothDevice.DEVICE_TYPE_WATCH.getBytes());
StylusDevicesController controller = new StylusDevicesController(
mContext, null, mCachedBluetoothDevice, mLifecycle
);
showScreen(controller);
assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(0);
}
@Test
public void noInputDevice_stylusBluetoothDevice_showsPreference() {
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
BluetoothDevice.DEVICE_TYPE_STYLUS.getBytes());
StylusDevicesController controller = new StylusDevicesController(
mContext, null, mCachedBluetoothDevice, mLifecycle
);
showScreen(controller);
assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(3);
}
@Test @Test
public void btStylusInputDevice_showsAllPreferences() { public void btStylusInputDevice_showsAllPreferences() {
showScreen(mController); showScreen(mController);