Apps on sdcard: Add new broadcasts

Add new broadcasts ACTION_MEDIA_RESOURCES_AVAILABLE and
ACTION_MEDIA_RESOURCES_UNAVAILABLE that get broadcast by
PackageManagerService when sdcard gets mounted/unmounted
by MountService so that packages on sdcard get recognized by
various system services as being installed/available or
removed/unavailable by the system.
The broadcasts are sent before the actual package cleanup which includes
mounting/unmounting the packages and we force a gc right after so
that any lingering file references to resources on sdcard get
released.
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 405dc2e..dc942a2 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -335,6 +335,22 @@
     class PackageReceiver extends android.content.BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            String pkgList[] = null;
+            if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
+                    Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+                Uri uri = intent.getData();
+                String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
+                if (pkg != null) {
+                    pkgList = new String[] { pkg };
+                }
+            } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action) ||
+                    Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+            }
+            if (pkgList == null || pkgList.length == 0) {
+                return;
+            }
             synchronized (mMethodMap) {
                 buildInputMethodListLocked(mMethodList, mMethodMap);
 
@@ -352,38 +368,45 @@
 
                 boolean changed = false;
 
-                Uri uri = intent.getData();
-                String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
-                if (curIm != null && curIm.getPackageName().equals(pkg)) {
-                    ServiceInfo si = null;
-                    try {
-                        si = mContext.getPackageManager().getServiceInfo(
-                                curIm.getComponent(), 0);
-                    } catch (PackageManager.NameNotFoundException ex) {
-                    }
-                    if (si == null) {
-                        // Uh oh, current input method is no longer around!
-                        // Pick another one...
-                        Log.i(TAG, "Current input method removed: " + curInputMethodId);
-                        if (!chooseNewDefaultIME()) {
-                            changed = true;
-                            curIm = null;
-                            curInputMethodId = "";
-                            Log.i(TAG, "Unsetting current input method");
-                            Settings.Secure.putString(mContext.getContentResolver(),
-                                    Settings.Secure.DEFAULT_INPUT_METHOD,
-                                    curInputMethodId);
+                if (curIm != null) {
+                    boolean foundPkg = false;
+                    for (String pkg : pkgList) {
+                        if (curIm.getPackageName().equals(pkg)) {
+                            foundPkg = true;
+                            break;
                         }
                     }
+                    if (foundPkg) {
+                        ServiceInfo si = null;
+                        try {
+                            si = mContext.getPackageManager().getServiceInfo(
+                                    curIm.getComponent(), 0);
+                        } catch (PackageManager.NameNotFoundException ex) {
+                        }
+                        if (si == null) {
+                            // Uh oh, current input method is no longer around!
+                            // Pick another one...
+                            Log.i(TAG, "Current input method removed: " + curInputMethodId);
+                            if (!chooseNewDefaultIME()) {
+                                changed = true;
+                                curIm = null;
+                                curInputMethodId = "";
+                                Log.i(TAG, "Unsetting current input method");
+                                Settings.Secure.putString(mContext.getContentResolver(),
+                                        Settings.Secure.DEFAULT_INPUT_METHOD,
+                                        curInputMethodId);
+                            }
+                        }
 
-                } else if (curIm == null) {
-                    // We currently don't have a default input method... is
-                    // one now available?
-                    changed = chooseNewDefaultIME();
-                }
+                    } else if (curIm == null) {
+                        // We currently don't have a default input method... is
+                        // one now available?
+                        changed = chooseNewDefaultIME();
+                    }
 
-                if (changed) {
-                    updateFromSettingsLocked();
+                    if (changed) {
+                        updateFromSettingsLocked();
+                    }
                 }
             }
         }
@@ -415,13 +438,19 @@
             }
         });
 
+        PackageReceiver mBroadcastReceiver = new PackageReceiver();
         IntentFilter packageFilt = new IntentFilter();
         packageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
         packageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
         packageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
         packageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
         packageFilt.addDataScheme("package");
-        mContext.registerReceiver(new PackageReceiver(), packageFilt);
+        mContext.registerReceiver(mBroadcastReceiver, packageFilt);
+        // Register for events related to sdcard installation.
+        IntentFilter sdFilter = new IntentFilter();
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
 
         IntentFilter screenOnOffFilt = new IntentFilter();
         screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON);