From 2df165a58aa8d485e4545f633e99a5988597a6bf Mon Sep 17 00:00:00 2001 From: Vania Januar Date: Thu, 20 Oct 2022 14:44:59 +0100 Subject: [PATCH] Add a stylus controller to Bluetooth Device Details. Feature is currently flagged behing SETTINGS_SHOW_STYLUS_PREFERENCES. Bug: 251201006 Test: SettingsRoboTests StylusDevicesControllerTest DD: go/stylus-connected-devices-doc Change-Id: I438b7fe5ca1c94f9dfb506c8918d0e6cb005ca33 --- res/drawable/ic_article.xml | 25 ++ res/drawable/ic_block.xml | 25 ++ res/drawable/ic_text_fields_alt.xml | 25 ++ res/values/strings.xml | 11 + res/xml/bluetooth_device_details_fragment.xml | 7 +- .../BluetoothDeviceDetailsFragment.java | 49 ++++ .../stylus/StylusDevicesController.java | 199 +++++++++++++++ .../BluetoothDeviceDetailsFragmentTest.java | 132 ++++++++-- .../stylus/StylusDevicesControllerTest.java | 233 ++++++++++++++++++ 9 files changed, 687 insertions(+), 19 deletions(-) create mode 100644 res/drawable/ic_article.xml create mode 100644 res/drawable/ic_block.xml create mode 100644 res/drawable/ic_text_fields_alt.xml create mode 100644 src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java create mode 100644 tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java diff --git a/res/drawable/ic_article.xml b/res/drawable/ic_article.xml new file mode 100644 index 00000000000..0c32c0f6c56 --- /dev/null +++ b/res/drawable/ic_article.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/drawable/ic_block.xml b/res/drawable/ic_block.xml new file mode 100644 index 00000000000..cf73681e3f5 --- /dev/null +++ b/res/drawable/ic_block.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/drawable/ic_text_fields_alt.xml b/res/drawable/ic_text_fields_alt.xml new file mode 100644 index 00000000000..673c0eba78c --- /dev/null +++ b/res/drawable/ic_text_fields_alt.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index d91cb88c499..91f6f68b6e8 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -228,6 +228,17 @@ See all + + Stylus + + System note taking app + + Stylus writing in textfields + + Ignore all stylus button presses + + USI stylus + Date & time diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml index 0528973d676..5cd7c3a8e3d 100644 --- a/res/xml/bluetooth_device_details_fragment.xml +++ b/res/xml/bluetooth_device_details_fragment.xml @@ -44,15 +44,18 @@ + android:gravity="center"/> + android:layout_height="8dp"/> + + roleHolders = rm.getRoleHoldersAsUser(RoleManager.ROLE_ASSISTANT, + mContext.getUser()); + if (roleHolders.isEmpty()) { + return null; + } + + String packageName = roleHolders.get(0); + PackageManager pm = mContext.getPackageManager(); + String appName = packageName; + try { + ApplicationInfo ai = pm.getApplicationInfo(packageName, + PackageManager.ApplicationInfoFlags.of(0)); + appName = ai == null ? packageName : pm.getApplicationLabel(ai).toString(); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Notes role package not found."); + } + + Preference pref = new Preference(mContext); + pref.setKey(KEY_DEFAULT_NOTES); + pref.setTitle(mContext.getString(R.string.stylus_default_notes_app)); + pref.setIcon(R.drawable.ic_article); + pref.setEnabled(true); + pref.setSummary(appName); + return pref; + } + + private SwitchPreference createHandwritingPreference() { + SwitchPreference pref = new SwitchPreference(mContext); + pref.setKey(KEY_HANDWRITING); + pref.setTitle(mContext.getString(R.string.stylus_textfield_handwriting)); + pref.setIcon(R.drawable.ic_text_fields_alt); + pref.setOnPreferenceClickListener(this); + pref.setChecked(Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.STYLUS_HANDWRITING_ENABLED, 0) == 1); + return pref; + } + + private SwitchPreference createButtonPressPreference() { + SwitchPreference pref = new SwitchPreference(mContext); + pref.setKey(KEY_IGNORE_BUTTON); + pref.setTitle(mContext.getString(R.string.stylus_ignore_button)); + pref.setIcon(R.drawable.ic_block); + pref.setOnPreferenceClickListener(this); + return pref; + } + + @Override + public boolean onPreferenceClick(Preference preference) { + String key = preference.getKey(); + + switch (key) { + case KEY_DEFAULT_NOTES: + PackageManager pm = mContext.getPackageManager(); + String packageName = pm.getPermissionControllerPackageName(); + // TODO(b/254834764): replace with notes role once merged + Intent intent = new Intent(Intent.ACTION_MANAGE_DEFAULT_APP).setPackage( + packageName).putExtra(Intent.EXTRA_ROLE_NAME, RoleManager.ROLE_ASSISTANT); + mContext.startActivity(intent); + break; + case KEY_HANDWRITING: + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.STYLUS_HANDWRITING_ENABLED, + ((SwitchPreference) preference).isChecked() ? 1 : 0); + break; + case KEY_IGNORE_BUTTON: + // TODO(b/251199452): to turn off stylus button presses + break; + } + return true; + } + + @Override + public final void displayPreference(PreferenceScreen screen) { + mPreferencesContainer = (PreferenceCategory) screen.findPreference(getPreferenceKey()); + super.displayPreference(screen); + + refresh(); + } + + @Override + public String getPreferenceKey() { + return KEY_STYLUS; + } + + @Override + public void onResume() { + refresh(); + } + + private void refresh() { + if (!isAvailable()) return; + + if (mInputDevice.getBluetoothAddress() != null) { + Preference notesPref = mPreferencesContainer.findPreference(KEY_DEFAULT_NOTES); + if (notesPref == null) { + notesPref = createDefaultNotesPreference(); + if (notesPref != null) { + mPreferencesContainer.addPreference(notesPref); + } + } + } + + Preference handwritingPref = mPreferencesContainer.findPreference(KEY_HANDWRITING); + // TODO(b/255732419): add proper InputMethodInfo conditional to show or hide + // InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); + if (handwritingPref == null) { + mPreferencesContainer.addPreference(createHandwritingPreference()); + } + + Preference buttonPref = mPreferencesContainer.findPreference(KEY_IGNORE_BUTTON); + if (buttonPref == null) { + mPreferencesContainer.addPreference(createButtonPressPreference()); + } + } +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java index d501c154213..57af4126540 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java @@ -25,16 +25,21 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.hardware.input.InputManager; import android.os.Bundle; import android.os.UserManager; +import android.util.FeatureFlagUtils; +import android.view.InputDevice; import android.view.MenuInflater; import android.view.MenuItem; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.preference.PreferenceScreen; @@ -51,6 +56,7 @@ import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @@ -68,6 +74,7 @@ public class BluetoothDeviceDetailsFragmentTest { private RoboMenu mMenu; private MenuInflater mInflater; private FragmentTransaction mFragmentTransaction; + private FragmentActivity mActivity; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private CachedBluetoothDevice mCachedDevice; @@ -77,29 +84,18 @@ public class BluetoothDeviceDetailsFragmentTest { private PreferenceScreen mPreferenceScreen; @Mock private UserManager mUserManager; + @Mock + private InputManager mInputManager; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); + doReturn(mInputManager).when(mContext).getSystemService(InputManager.class); + removeInputDeviceWithMatchingBluetoothAddress(); FakeFeatureFactory.setupForTest(); - mFragment = spy(BluetoothDeviceDetailsFragment.newInstance(TEST_ADDRESS)); - doReturn(mLocalManager).when(mFragment).getLocalBluetoothManager(any()); - doReturn(mCachedDevice).when(mFragment).getCachedDevice(any()); - doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen(); - doReturn(mUserManager).when(mFragment).getUserManager(); - - FragmentManager fragmentManager = mock(FragmentManager.class); - when(mFragment.getFragmentManager()).thenReturn(fragmentManager); - mFragmentTransaction = mock(FragmentTransaction.class); - when(fragmentManager.beginTransaction()).thenReturn(mFragmentTransaction); - - when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS); - when(mCachedDevice.getIdentityAddress()).thenReturn(TEST_ADDRESS); - Bundle args = new Bundle(); - args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS, TEST_ADDRESS); - mFragment.setArguments(args); + mFragment = setupFragment(); mFragment.onAttach(mContext); mMenu = new RoboMenu(mContext); @@ -111,6 +107,43 @@ public class BluetoothDeviceDetailsFragmentTest { assertThat(mFragment.mDeviceAddress).isEqualTo(TEST_ADDRESS); assertThat(mFragment.mManager).isEqualTo(mLocalManager); assertThat(mFragment.mCachedDevice).isEqualTo(mCachedDevice); + assertThat(mFragment.mInputDevice).isEqualTo(null); + } + + @Test + public void verifyOnAttachResult_flagEnabledAndInputDeviceSet_returnsInputDevice() { + FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_SHOW_STYLUS_PREFERENCES, + true); + InputDevice inputDevice = createInputDeviceWithMatchingBluetoothAddress(); + BluetoothDeviceDetailsFragment fragment = setupFragment(); + FragmentActivity activity = mock(FragmentActivity.class); + doReturn(inputDevice).when(fragment).getInputDevice(any()); + doReturn(activity).when(fragment).getActivity(); + + fragment.onAttach(mContext); + + assertThat(fragment.mDeviceAddress).isEqualTo(TEST_ADDRESS); + assertThat(fragment.mManager).isEqualTo(mLocalManager); + assertThat(fragment.mCachedDevice).isEqualTo(mCachedDevice); + assertThat(fragment.mInputDevice).isEqualTo(inputDevice); + } + + @Test + public void verifyOnAttachResult_flagDisabled_returnsNullInputDevice() { + FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_SHOW_STYLUS_PREFERENCES, + false); + InputDevice inputDevice = createInputDeviceWithMatchingBluetoothAddress(); + BluetoothDeviceDetailsFragment fragment = setupFragment(); + FragmentActivity activity = mock(FragmentActivity.class); + doReturn(inputDevice).when(fragment).getInputDevice(any()); + doReturn(activity).when(fragment).getActivity(); + + fragment.onAttach(mContext); + + assertThat(fragment.mDeviceAddress).isEqualTo(TEST_ADDRESS); + assertThat(fragment.mManager).isEqualTo(mLocalManager); + assertThat(fragment.mCachedDevice).isEqualTo(mCachedDevice); + assertThat(fragment.mInputDevice).isEqualTo(null); } @Test @@ -122,6 +155,31 @@ public class BluetoothDeviceDetailsFragmentTest { assertThat(item.getTitle()).isEqualTo(mContext.getString(R.string.bluetooth_rename_button)); } + @Test + public void getTitle_inputDeviceTitle() { + FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_SHOW_STYLUS_PREFERENCES, + true); + doReturn(mock(InputDevice.class)).when(mFragment).getInputDevice(mContext); + mFragment.onAttach(mContext); + + mFragment.setTitleForInputDevice(); + + assertThat(mActivity.getTitle().toString()).isEqualTo( + mContext.getString(R.string.stylus_device_details_title)); + } + + @Test + public void getTitle_inputDeviceNull_doesNotSetTitle() { + FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_SHOW_STYLUS_PREFERENCES, + true); + doReturn(null).when(mFragment).getInputDevice(mContext); + mFragment.onAttach(mContext); + + mFragment.setTitleForInputDevice(); + + verify(mActivity, times(0)).setTitle(any()); + } + @Test public void editMenu_clicked_showDialog() { mFragment.onCreateOptionsMenu(mMenu, mInflater); @@ -131,7 +189,7 @@ public class BluetoothDeviceDetailsFragmentTest { mFragment.onOptionsItemSelected(item); assertThat(item.getItemId()) - .isEqualTo(BluetoothDeviceDetailsFragment.EDIT_DEVICE_NAME_ITEM_ID); + .isEqualTo(BluetoothDeviceDetailsFragment.EDIT_DEVICE_NAME_ITEM_ID); verify(mFragmentTransaction).add(captor.capture(), eq(RemoteDeviceNameDialogFragment.TAG)); RemoteDeviceNameDialogFragment dialog = (RemoteDeviceNameDialogFragment) captor.getValue(); assertThat(dialog).isNotNull(); @@ -145,4 +203,44 @@ public class BluetoothDeviceDetailsFragmentTest { verify(mFragment).finish(); } + + private InputDevice createInputDeviceWithMatchingBluetoothAddress() { + doReturn(new int[]{0}).when(mInputManager).getInputDeviceIds(); + InputDevice device = mock(InputDevice.class); + doReturn(TEST_ADDRESS).when(mInputManager).getInputDeviceBluetoothAddress(0); + doReturn(device).when(mInputManager).getInputDevice(0); + return device; + } + + private InputDevice removeInputDeviceWithMatchingBluetoothAddress() { + doReturn(new int[]{0}).when(mInputManager).getInputDeviceIds(); + doReturn(null).when(mInputManager).getInputDeviceBluetoothAddress(0); + return null; + } + + private BluetoothDeviceDetailsFragment setupFragment() { + BluetoothDeviceDetailsFragment fragment = spy( + BluetoothDeviceDetailsFragment.newInstance(TEST_ADDRESS)); + doReturn(mLocalManager).when(fragment).getLocalBluetoothManager(any()); + doReturn(mCachedDevice).when(fragment).getCachedDevice(any()); + doReturn(mPreferenceScreen).when(fragment).getPreferenceScreen(); + doReturn(mUserManager).when(fragment).getUserManager(); + + mActivity = spy(Robolectric.setupActivity(FragmentActivity.class)); + doReturn(mActivity).when(fragment).getActivity(); + doReturn(mContext).when(fragment).getContext(); + + FragmentManager fragmentManager = mock(FragmentManager.class); + doReturn(fragmentManager).when(fragment).getFragmentManager(); + mFragmentTransaction = mock(FragmentTransaction.class); + doReturn(mFragmentTransaction).when(fragmentManager).beginTransaction(); + + doReturn(TEST_ADDRESS).when(mCachedDevice).getAddress(); + doReturn(TEST_ADDRESS).when(mCachedDevice).getIdentityAddress(); + Bundle args = new Bundle(); + args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS, TEST_ADDRESS); + fragment.setArguments(args); + + return fragment; + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java new file mode 100644 index 00000000000..f704f2d7a0b --- /dev/null +++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2022 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.connecteddevice.stylus; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.role.RoleManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.UserHandle; +import android.provider.Settings; +import android.view.InputDevice; +import android.view.inputmethod.InputMethodManager; + +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.R; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import java.util.Collections; + +@RunWith(RobolectricTestRunner.class) +public class StylusDevicesControllerTest { + private static final String NOTES_PACKAGE_NAME = "notes.package"; + private static final CharSequence NOTES_APP_LABEL = "App Label"; + + private Context mContext; + private StylusDevicesController mController; + private PreferenceCategory mPreferenceContainer; + private PreferenceScreen mScreen; + private InputDevice mInputDevice; + + @Mock + private InputMethodManager mImm; + @Mock + private PackageManager mPm; + @Mock + private RoleManager mRm; + @Mock + private Lifecycle mLifecycle; + + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mContext = spy(ApplicationProvider.getApplicationContext()); + PreferenceManager preferenceManager = new PreferenceManager(mContext); + mScreen = preferenceManager.createPreferenceScreen(mContext); + mPreferenceContainer = new PreferenceCategory(mContext); + mPreferenceContainer.setKey(StylusDevicesController.KEY_STYLUS); + mScreen.addPreference(mPreferenceContainer); + + when(mContext.getSystemService(InputMethodManager.class)).thenReturn(mImm); + when(mContext.getSystemService(RoleManager.class)).thenReturn(mRm); + doNothing().when(mContext).startActivity(any()); + + // TODO(b/254834764): notes role placeholder + when(mRm.getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any(UserHandle.class))) + .thenReturn(Collections.singletonList(NOTES_PACKAGE_NAME)); + when(mContext.getPackageManager()).thenReturn(mPm); + when(mPm.getApplicationInfo(eq(NOTES_PACKAGE_NAME), + any(PackageManager.ApplicationInfoFlags.class))).thenReturn(new ApplicationInfo()); + when(mPm.getApplicationLabel(any(ApplicationInfo.class))).thenReturn(NOTES_APP_LABEL); + + mInputDevice = spy(new InputDevice.Builder() + .setId(1) + .setSources(InputDevice.SOURCE_STYLUS) + .build()); + when(mInputDevice.getBluetoothAddress()).thenReturn("SOME:ADDRESS"); + + mController = new StylusDevicesController(mContext, mInputDevice, mLifecycle); + } + + @Test + public void noInputDevice_noPreference() { + StylusDevicesController controller = new StylusDevicesController( + mContext, null, mLifecycle + ); + showScreen(controller); + assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(0); + } + + @Test + public void btStylusInputDevice_showsAllPreferences() { + showScreen(mController); + Preference defaultNotesPref = mPreferenceContainer.getPreference(0); + Preference handwritingPref = mPreferenceContainer.getPreference(1); + Preference buttonPref = mPreferenceContainer.getPreference(2); + + assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(3); + assertThat(defaultNotesPref.getTitle().toString()).isEqualTo( + mContext.getString(R.string.stylus_default_notes_app)); + assertThat(handwritingPref.getTitle().toString()).isEqualTo( + mContext.getString(R.string.stylus_textfield_handwriting)); + assertThat(buttonPref.getTitle().toString()).isEqualTo( + mContext.getString(R.string.stylus_ignore_button)); + } + + @Test + @Ignore // TODO(b/255732419): unignore when InputMethodInfo available + public void btStylusInputDevice_noHandwritingIme_showsSomePreferences() { + showScreen(mController); + Preference defaultNotesPref = mPreferenceContainer.getPreference(0); + Preference buttonPref = mPreferenceContainer.getPreference(1); + + assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(2); + assertThat(defaultNotesPref.getTitle().toString()).isEqualTo( + mContext.getString(R.string.stylus_default_notes_app)); + assertThat(buttonPref.getTitle().toString()).isEqualTo( + mContext.getString(R.string.stylus_ignore_button)); + } + + @Test + public void defaultNotesPreference_showsNotesRoleApp() { + showScreen(mController); + Preference defaultNotesPref = mPreferenceContainer.getPreference(0); + + assertThat(defaultNotesPref.getTitle().toString()).isEqualTo( + mContext.getString(R.string.stylus_default_notes_app)); + assertThat(defaultNotesPref.getSummary().toString()).isEqualTo(NOTES_APP_LABEL.toString()); + } + + @Test + public void defaultNotesPreference_noRoleHolder_hidesNotesRoleApp() { + // TODO(b/254834764): replace with notes role once merged + when(mRm.getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any(UserHandle.class))) + .thenReturn(Collections.emptyList()); + showScreen(mController); + + for (int i = 0; i < mPreferenceContainer.getPreferenceCount(); i++) { + Preference pref = mPreferenceContainer.getPreference(i); + assertThat(pref.getTitle().toString()).isNotEqualTo( + mContext.getString(R.string.stylus_default_notes_app)); + } + } + + @Test + public void defaultNotesPreferenceClick_sendsManageDefaultRoleIntent() { + final String permissionPackageName = "permissions.package"; + when(mPm.getPermissionControllerPackageName()).thenReturn(permissionPackageName); + final ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class); + + showScreen(mController); + Preference defaultNotesPref = mPreferenceContainer.getPreference(0); + mController.onPreferenceClick(defaultNotesPref); + verify(mContext).startActivity(captor.capture()); + + Intent intent = captor.getValue(); + assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MANAGE_DEFAULT_APP); + assertThat(intent.getPackage()).isEqualTo(permissionPackageName); + // TODO(b/254834764): when notes role is merged + assertThat(intent.getStringExtra(Intent.EXTRA_ROLE_NAME)).isEqualTo( + RoleManager.ROLE_ASSISTANT); + } + + @Test + public void handwritingPreference_checkedWhenFlagTrue() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.STYLUS_HANDWRITING_ENABLED, 1); + + showScreen(mController); + SwitchPreference handwritingPref = (SwitchPreference) mPreferenceContainer.getPreference(1); + + assertThat(handwritingPref.isChecked()).isEqualTo(true); + } + + @Test + public void handwritingPreference_uncheckedWhenFlagFalse() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.STYLUS_HANDWRITING_ENABLED, 0); + + showScreen(mController); + SwitchPreference handwritingPref = (SwitchPreference) mPreferenceContainer.getPreference(1); + + assertThat(handwritingPref.isChecked()).isEqualTo(false); + } + + @Test + public void handwritingPreference_updatesFlagOnClick() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.STYLUS_HANDWRITING_ENABLED, 0); + showScreen(mController); + SwitchPreference handwritingPref = (SwitchPreference) mPreferenceContainer.getPreference(1); + + handwritingPref.performClick(); + + assertThat(handwritingPref.isChecked()).isEqualTo(true); + assertThat(Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.STYLUS_HANDWRITING_ENABLED, -1)).isEqualTo(1); + } + + private void showScreen(StylusDevicesController controller) { + controller.displayPreference(mScreen); + } +}