diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1f3ba2a5b3c..fbb8b27ab2e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -258,8 +258,10 @@
Stylus
-
- Default notes app
+
+ Tail button press
+
+ %s (Work profile)
Write in text fields
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
index c93a1c6e659..e821966f428 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
@@ -16,12 +16,17 @@
package com.android.settings.connecteddevice.stylus;
+import android.app.Dialog;
import android.app.role.RoleManager;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.text.TextUtils;
@@ -38,6 +43,8 @@ import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settings.R;
+import com.android.settings.dashboard.profileselector.ProfileSelectDialog;
+import com.android.settings.dashboard.profileselector.UserAdapter;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -45,6 +52,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnResume;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -73,6 +81,9 @@ public class StylusDevicesController extends AbstractPreferenceController implem
@VisibleForTesting
PreferenceCategory mPreferencesContainer;
+ @VisibleForTesting
+ Dialog mDialog;
+
public StylusDevicesController(Context context, InputDevice inputDevice,
CachedBluetoothDevice cachedBluetoothDevice, Lifecycle lifecycle) {
super(context);
@@ -100,8 +111,8 @@ public class StylusDevicesController extends AbstractPreferenceController implem
pref.setOnPreferenceClickListener(this);
pref.setEnabled(true);
- List roleHolders = rm.getRoleHoldersAsUser(RoleManager.ROLE_NOTES,
- mContext.getUser());
+ UserHandle user = getDefaultNoteTaskProfile();
+ List roleHolders = rm.getRoleHoldersAsUser(RoleManager.ROLE_NOTES, user);
if (roleHolders.isEmpty()) {
pref.setSummary(R.string.default_app_none);
return pref;
@@ -117,7 +128,13 @@ public class StylusDevicesController extends AbstractPreferenceController implem
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Notes role package not found.");
}
- pref.setSummary(appName);
+
+ if (mContext.getSystemService(UserManager.class).isManagedProfile(user.getIdentifier())) {
+ pref.setSummary(
+ mContext.getString(R.string.stylus_default_notes_summary_work, appName));
+ } else {
+ pref.setSummary(appName);
+ }
return pref;
}
@@ -155,7 +172,13 @@ public class StylusDevicesController extends AbstractPreferenceController implem
String packageName = pm.getPermissionControllerPackageName();
Intent intent = new Intent(Intent.ACTION_MANAGE_DEFAULT_APP).setPackage(
packageName).putExtra(Intent.EXTRA_ROLE_NAME, RoleManager.ROLE_NOTES);
- mContext.startActivity(intent);
+
+ List users = getUserAndManagedProfiles();
+ if (users.size() <= 1) {
+ mContext.startActivity(intent);
+ } else {
+ createAndShowProfileSelectDialog(intent, users);
+ }
break;
case KEY_HANDWRITING:
Settings.Secure.putInt(mContext.getContentResolver(),
@@ -229,6 +252,55 @@ public class StylusDevicesController extends AbstractPreferenceController implem
return inputMethod != null && inputMethod.supportsStylusHandwriting();
}
+ private List getUserAndManagedProfiles() {
+ UserManager um = mContext.getSystemService(UserManager.class);
+ final ArrayList userManagedProfiles = new ArrayList<>();
+ // Add the current user, then add all the associated managed profiles.
+ final UserHandle currentUser = Process.myUserHandle();
+ userManagedProfiles.add(currentUser);
+
+ final List userInfos = um.getUsers();
+ for (UserInfo info : userInfos) {
+ if (um.isManagedProfile(info.id)
+ && um.getProfileParent(info.id).id == currentUser.getIdentifier()) {
+ userManagedProfiles.add(UserHandle.of(info.id));
+ }
+ }
+ return userManagedProfiles;
+ }
+
+ private UserHandle getDefaultNoteTaskProfile() {
+ final int userId = Secure.getInt(
+ mContext.getContentResolver(),
+ Secure.DEFAULT_NOTE_TASK_PROFILE,
+ UserHandle.myUserId());
+ return UserHandle.of(userId);
+ }
+
+ @VisibleForTesting
+ UserAdapter.OnClickListener createProfileDialogClickCallback(
+ Intent intent, List users) {
+ // TODO(b/281659827): improve UX flow for when activity is cancelled
+ return (int position) -> {
+ intent.putExtra(Intent.EXTRA_USER, users.get(position));
+
+ Secure.putInt(mContext.getContentResolver(),
+ Secure.DEFAULT_NOTE_TASK_PROFILE,
+ users.get(position).getIdentifier());
+ mContext.startActivity(intent);
+
+ mDialog.dismiss();
+ };
+ }
+
+ private void createAndShowProfileSelectDialog(Intent intent, List users) {
+ mDialog = ProfileSelectDialog.createDialog(
+ mContext,
+ users,
+ createProfileDialogClickCallback(intent, users));
+ mDialog.show();
+ }
+
/**
* Identifies whether a device is a stylus using the associated {@link InputDevice} or
* {@link CachedBluetoothDevice}.
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
index f4fa397e3d4..7fa6236b197 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
@@ -18,6 +18,10 @@ package com.android.settings.connecteddevice.stylus;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
@@ -27,13 +31,17 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Dialog;
import android.app.role.RoleManager;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.Process;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.view.InputDevice;
@@ -48,6 +56,7 @@ import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
+import com.android.settings.dashboard.profileselector.UserAdapter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -59,7 +68,9 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class StylusDevicesControllerTest {
@@ -79,6 +90,8 @@ public class StylusDevicesControllerTest {
@Mock
private PackageManager mPm;
@Mock
+ private UserManager mUserManager;
+ @Mock
private RoleManager mRm;
@Mock
private Lifecycle mLifecycle;
@@ -87,7 +100,6 @@ public class StylusDevicesControllerTest {
@Mock
private BluetoothDevice mBluetoothDevice;
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -101,6 +113,7 @@ public class StylusDevicesControllerTest {
when(mContext.getSystemService(InputMethodManager.class)).thenReturn(mImm);
when(mContext.getSystemService(RoleManager.class)).thenReturn(mRm);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
doNothing().when(mContext).startActivity(any());
when(mImm.getCurrentInputMethodInfo()).thenReturn(mInputMethodInfo);
@@ -115,6 +128,8 @@ public class StylusDevicesControllerTest {
when(mPm.getApplicationInfo(eq(NOTES_PACKAGE_NAME),
any(PackageManager.ApplicationInfoFlags.class))).thenReturn(new ApplicationInfo());
when(mPm.getApplicationLabel(any(ApplicationInfo.class))).thenReturn(NOTES_APP_LABEL);
+ when(mUserManager.getUsers()).thenReturn(Arrays.asList(new UserInfo(0, "default", 0)));
+ when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
@@ -228,21 +243,35 @@ public class StylusDevicesControllerTest {
when(mInputMethodInfo.supportsStylusHandwriting()).thenReturn(false);
showScreen(mController);
- Preference handwritingPref = mPreferenceContainer.getPreference(1);
+ Preference handwritingPref = mPreferenceContainer.getPreference(1);
assertThat(handwritingPref.isVisible()).isFalse();
}
@Test
- public void defaultNotesPreference_showsNotesRoleApp() {
+ public void defaultNotesPreference_singleUser_showsNotesRoleApp() {
showScreen(mController);
- Preference defaultNotesPref = mPreferenceContainer.getPreference(0);
+ 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_workProfileUser_showsWorkNotesRoleApp() {
+ when(mUserManager.isManagedProfile(0)).thenReturn(true);
+
+ 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(
+ mContext.getString(R.string.stylus_default_notes_summary_work,
+ NOTES_APP_LABEL.toString()));
+ }
+
@Test
public void defaultNotesPreference_roleHolderChanges_updatesPreference() {
showScreen(mController);
@@ -267,7 +296,7 @@ public class StylusDevicesControllerTest {
}
@Test
- public void defaultNotesPreferenceClick_sendsManageDefaultRoleIntent() {
+ public void defaultNotesPreferenceClick_singleUser_sendsManageDefaultRoleIntent() {
final String permissionPackageName = "permissions.package";
when(mPm.getPermissionControllerPackageName()).thenReturn(permissionPackageName);
final ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class);
@@ -282,6 +311,46 @@ public class StylusDevicesControllerTest {
assertThat(intent.getPackage()).isEqualTo(permissionPackageName);
assertThat(intent.getStringExtra(Intent.EXTRA_ROLE_NAME)).isEqualTo(
RoleManager.ROLE_NOTES);
+ assertNull(mController.mDialog);
+ }
+
+ @Test
+ public void defaultNotesPreferenceClick_multiUser_showsProfileSelectorDialog() {
+ mContext.setTheme(R.style.Theme_AppCompat);
+ final String permissionPackageName = "permissions.package";
+ final UserHandle currentUser = Process.myUserHandle();
+ List userInfos = Arrays.asList(
+ new UserInfo(currentUser.getIdentifier(), "current", 0),
+ new UserInfo(1, "profile", UserInfo.FLAG_PROFILE)
+ );
+ when(mUserManager.getUsers()).thenReturn(userInfos);
+ when(mUserManager.isManagedProfile(1)).thenReturn(true);
+ when(mUserManager.getUserInfo(currentUser.getIdentifier())).thenReturn(userInfos.get(0));
+ when(mUserManager.getUserInfo(1)).thenReturn(userInfos.get(1));
+ when(mUserManager.getProfileParent(1)).thenReturn(userInfos.get(0));
+ when(mPm.getPermissionControllerPackageName()).thenReturn(permissionPackageName);
+
+ showScreen(mController);
+ Preference defaultNotesPref = mPreferenceContainer.getPreference(0);
+ mController.onPreferenceClick(defaultNotesPref);
+
+ assertTrue(mController.mDialog.isShowing());
+ }
+
+ @Test
+ public void profileSelectDialogClickCallback_onClick_sendsIntent() {
+ Intent intent = new Intent();
+ UserHandle user1 = mock(UserHandle.class);
+ UserHandle user2 = mock(UserHandle.class);
+ List users = Arrays.asList(new UserHandle[] {user1, user2});
+ mController.mDialog = mock(Dialog.class);
+ UserAdapter.OnClickListener callback = mController
+ .createProfileDialogClickCallback(intent, users);
+
+ callback.onClick(1);
+
+ assertEquals(intent.getExtra(Intent.EXTRA_USER), user2);
+ verify(mContext).startActivity(intent);
}
@Test