From ddb514764957108c6e642f84c096c440da28538e Mon Sep 17 00:00:00 2001 From: Wilson Wu Date: Tue, 8 Feb 2022 22:20:05 +0800 Subject: [PATCH] Fix NPE if keyboard settings is launched by work apps IME apps can request users to enable them by directly launching the on-screen keyboard settings page. If keyboard settings is launched by works apps, the current userId would be work userId. There is no managed profile for work user so the exception happened. -. Use current userId if it's launched by work user -. Use primary user info for personal fragment Fix: 216395439 Test: Manual test with issue steps Test: make RunSettingsRoboTests ROBOTEST_FILTER=AvailableVirtualKeyboardFragmentTest Change-Id: Iea573922ee789d9932c0de05bf71179c4f005eeb --- .../AvailableVirtualKeyboardFragment.java | 37 ++++++++++++++----- .../AvailableVirtualKeyboardFragmentTest.java | 8 +++- .../testutils/shadow/ShadowUserManager.java | 8 ++++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java index 8bef7086817..a7b4b007dbb 100644 --- a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java @@ -68,16 +68,35 @@ public class AvailableVirtualKeyboardFragment extends DashboardFragment public void onAttach(Context context) { super.onAttach(context); final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE); - if (profileType == ProfileSelectFragment.ProfileType.WORK) { - final UserManager userManager = UserManager.get(context); - final UserHandle workUser = Utils.getManagedProfile(userManager); - // get work userId - mUserId = Utils.getManagedProfileId(userManager, UserHandle.myUserId()); - mUserAwareContext = context.createContextAsUser(workUser, 0); - } else { - mUserId = UserHandle.myUserId(); - mUserAwareContext = context; + final UserManager userManager = context.getSystemService(UserManager.class); + final int currentUserId = UserHandle.myUserId(); + final int newUserId; + final Context newUserAwareContext; + switch (profileType) { + case ProfileSelectFragment.ProfileType.WORK: { + final UserHandle workUser; + if (currentUserId == UserHandle.MIN_SECONDARY_USER_ID) { + newUserId = currentUserId; + workUser = UserHandle.of(currentUserId); + } else { + newUserId = Utils.getManagedProfileId(userManager, currentUserId); + workUser = Utils.getManagedProfile(userManager); + } + newUserAwareContext = context.createContextAsUser(workUser, 0); + break; + } + case ProfileSelectFragment.ProfileType.PERSONAL: { + final UserHandle primaryUser = userManager.getPrimaryUser().getUserHandle(); + newUserId = primaryUser.getIdentifier(); + newUserAwareContext = context.createContextAsUser(primaryUser, 0); + break; + } + default: + newUserId = currentUserId; + newUserAwareContext = context; } + mUserId = newUserId; + mUserAwareContext = newUserAwareContext; } @Override diff --git a/tests/robotests/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragmentTest.java b/tests/robotests/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragmentTest.java index c6c6a66b986..c6e7a977b82 100644 --- a/tests/robotests/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragmentTest.java @@ -20,7 +20,9 @@ import static com.android.settings.dashboard.profileselector.ProfileSelectFragme import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -31,6 +33,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; +import android.os.UserHandle; import android.provider.SearchIndexableResource; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -43,6 +46,7 @@ import com.android.settings.R; import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settings.testutils.shadow.ShadowInputMethodManagerWithMethodList; import com.android.settings.testutils.shadow.ShadowSecureSettings; +import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.inputmethod.InputMethodPreference; import com.android.settingslib.inputmethod.InputMethodSettingValuesWrapper; @@ -62,7 +66,8 @@ import java.util.List; @RunWith(RobolectricTestRunner.class) @Config(shadows = { ShadowSecureSettings.class, - ShadowInputMethodManagerWithMethodList.class + ShadowInputMethodManagerWithMethodList.class, + ShadowUserManager.class }) public class AvailableVirtualKeyboardFragmentTest { @@ -170,6 +175,7 @@ public class AvailableVirtualKeyboardFragmentTest { when(mFragment.getPreferenceScreen()).thenReturn(mPreferenceScreen); when(mPreferenceManager.getContext()).thenReturn(mContext); when(mContext.getSystemService(InputMethodManager.class)).thenReturn(mInputMethodManager); + doReturn(mContext).when(mContext).createContextAsUser(any(UserHandle.class), anyInt()); } private List createFakeInputMethodInfoList(final String name, int num) { diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java index dc42515bf90..ea51370c471 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java @@ -44,6 +44,8 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager private static boolean sIsSupportsMultipleUsers; + private static final int PRIMARY_USER_ID = 0; + private final List mBaseRestrictions = new ArrayList<>(); private final List mGuestRestrictions = new ArrayList<>(); private final Map> mRestrictionSources = new HashMap<>(); @@ -218,4 +220,10 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager mEnabledTypes.remove(type); } } + + @Implementation + protected UserInfo getPrimaryUser() { + return new UserInfo(PRIMARY_USER_ID, null, null, + UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY); + } }