Reset IMMS when the device is unlocked.

With File-Based Encryption (FBE), now we have yet another runteime event
to reset IMMS state in order to keep the list of available IMEs updated
and make sure one IME is enabled.  Here is the full list of such runtime
events.

   1. Boot phase reaches SystemService.PHASE_ACTIVITY_MANAGER_READY.
   2. One or more packages that contain InputMethodService are updated.
   3. The current user is switched.
   4. The device locale is changed.
   5. The device is unlocked by the current user.

Now we are adding the rule 5 in this CL.

We also apply Copy-On-Write (COW) settings mode, which was added in a
recent commit [1], until the deivice is unlocked.  This allows us to
temporarily update the settings when the device is locked, without
messing up actual SecureSettings.

  [1] I9c6f9bb3d51174198e5f73588637f87ea0d90e11

Here are some examples of what users would see in FBE-enabled devices.
Suppose we have following 5 IMEs installed.

 - IME A: Encryption Aware, pre-installed, ASCII-capable
 - IME B: Encryption Unaware, pre-installed, ASCII-capable
 - IME C: Encryption Unaware, not pre-installed, ASCII-capable
 - IME D: Encryption Aware, not pre-installed, ASCII-capable

 Case 1)
  Before boot:
    Enabled:   IME A
    Selected:  IME A
  Device Locked:
    Available: IME A, IME D
    Enabled:   IME A
    Selected:  IME A
  Device Unolcked:
    Available: IME A, IME B, IME C, IME D
    Enabled:   IME A
    Selected:  IME A

 Case 2)
  Before boot:
    Enabled:   IME A, IME B
    Selected:  IME B
  Device Locked:
    Available: IME A, IME D
    Enabled:   IME A
    Selected:  IME A
  Device Unolcked:
    Available: IME A, IME B, IME C, IME D
    Enabled:   IME A, IME B
    Selected:  IME B

 Case 3)
  Before boot:
    Enabled:   IME B, IME C
    Selected:  IME B
  Device Locked:
    Available: IME A, IME D
    Enabled:   IME A
    Selected:  IME A
  Device Unolcked:
    Available: IME A, IME B, IME C, IME D
    Enabled:   IME B, IME C
    Selected:  IME B

  Note: in this case, IMMS can rely on an existing rule to support
  the situation where enabled/selected IMEs were already uninstalled.

 Case 4)
  Before boot:
    Enabled:   IME B, IME C, IME D
    Selected:  IME B
  Device Locked:
    Available: IME A, IME D
    Enabled:   IME D
    Selected:  IME D
  Device Unolcked:
    Available: IME A, IME B, IME C, IME D
    Enabled:   IME B, IME C, IME D
    Selected:  IME B

Following things should be taken care of subsequent CLs.

 - Add CTS to ensure that at least one encryption-aware IME is
   pre-installed if the device supports FBE.
 - Consider an accidental case where there is no encryption-aware IME.
   This includes the case where all the encryption-aware system IMEs are
   overwritten by encryption-unaware IMEs that have higher versions.

Bug: 26279466
Change-Id: Ifa2225070bf8223f8964cf063c86889e312c5e9a
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 5f6fddf..d1de7e5 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -189,6 +189,7 @@
     private InputMethodFileManager mFileManager;
     private final HardKeyboardListener mHardKeyboardListener;
     private final AppOpsManager mAppOpsManager;
+    private final UserManager mUserManager;
 
     final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1, -1);
 
@@ -780,6 +781,27 @@
                 mService.systemRunning(statusBarService);
             }
         }
+
+        @Override
+        public void onUnlockUser(int userHandle) {
+            mService.onUnlockUser(userHandle);
+        }
+    }
+
+    public void onUnlockUser(int userId) {
+        synchronized(mMethodMap) {
+            final int currentUserId = mSettings.getCurrentUserId();
+            if (DEBUG) {
+                Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
+            }
+            if (userId != currentUserId) {
+                return;
+            }
+            mSettings.switchCurrentUser(currentUserId, !mSystemReady);
+            // We need to rebuild IMEs.
+            buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
+            updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+        }
     }
 
     public InputMethodManagerService(Context context) {
@@ -799,6 +821,7 @@
             }
         }, true /*asyncHandler*/);
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+        mUserManager = mContext.getSystemService(UserManager.class);
         mHardKeyboardListener = new HardKeyboardListener();
         mHasFeature = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_INPUT_METHODS);
@@ -972,8 +995,10 @@
         // ContentObserver should be registered again when the user is changed
         mSettingsObserver.registerContentObserverLocked(newUserId);
 
-        // If the system is not ready, then we use copy-on-write settings.
-        final boolean useCopyOnWriteSettings = !mSystemReady;
+        // If the system is not ready or the device is not yed unlocked by the user, then we use
+        // copy-on-write settings.
+        final boolean useCopyOnWriteSettings =
+                !mSystemReady || !mUserManager.isUserUnlocked(newUserId);
         mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
         updateCurrentProfileIds();
         // InputMethodFileManager should be reset when the user is changed
@@ -1002,8 +1027,7 @@
     }
 
     void updateCurrentProfileIds() {
-        List<UserInfo> profiles = mContext.getSystemService(UserManager.class)
-                .getProfiles(mSettings.getCurrentUserId());
+        List<UserInfo> profiles = mUserManager.getProfiles(mSettings.getCurrentUserId());
         int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
         for (int i = 0; i < currentProfileIds.length; i++) {
             currentProfileIds[i] = profiles.get(i).id;
@@ -1034,7 +1058,8 @@
             if (!mSystemReady) {
                 mSystemReady = true;
                 final int currentUserId = mSettings.getCurrentUserId();
-                mSettings.switchCurrentUser(currentUserId, false /* copyOnWrite */);
+                mSettings.switchCurrentUser(currentUserId,
+                        !mUserManager.isUserUnlocked(currentUserId));
                 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
                 mNotificationManager = mContext.getSystemService(NotificationManager.class);
                 mStatusBar = statusBar;
@@ -2918,6 +2943,9 @@
         // Use for queryIntentServicesAsUser
         final PackageManager pm = mContext.getPackageManager();
 
+        // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
+        // behavior of PackageManager is exactly what we want.  It by default picks up appropriate
+        // services depending on the unlock state for the specified user.
         final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
                 new Intent(InputMethod.SERVICE_INTERFACE),
                 PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,