Merge change 23667 into eclair

* changes:
  Fix the -1 unread count bug.
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 5ed8941..8cfb758 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1397,7 +1397,7 @@
                 Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
             }
 
-            if (!imsi.equals(storedImsi) && !"initial".equals(storedImsi)) {
+            if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
                     Log.v(TAG, "wiping all passwords and authtokens");
                 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 59529be..2a17672 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1267,6 +1267,8 @@
      * enabled or disabled.  The data contains the name of the package.
      * <ul>
      * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
+     * <li> {@link #EXTRA_CHANGED_COMPONENT_NAME} containing the class name of the changed component.
+     * <li> {@link #EXTRA_DONT_KILL_APP} containing boolean field to override the default action of restarting the application.
      * </ul>
      * 
      * <p class="note">This is a protected intent that can only be sent
@@ -2034,6 +2036,14 @@
     public static final String EXTRA_REMOTE_INTENT_TOKEN =
             "android.intent.extra.remote_intent_token";
 
+    /**
+     * Used as an int extra field in {@link android.content.Intent#ACTION_PACKAGE_CHANGED}
+     * intent to supply the name of the component that changed.
+     * @hide
+     */
+    public static final String EXTRA_CHANGED_COMPONENT_NAME =
+            "android.intent.extra.changed_component_name";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java
index 6b491ab..84753ee 100644
--- a/core/java/android/provider/Checkin.java
+++ b/core/java/android/provider/Checkin.java
@@ -59,6 +59,8 @@
 
         /** Valid tag values.  Extend as necessary for your needs. */
         public enum Tag {
+            APANIC_CONSOLE,
+            APANIC_THREADS,
             AUTOTEST_FAILURE,
             AUTOTEST_SEQUENCE_BEGIN,
             AUTOTEST_SUITE_BEGIN,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 77d1740..125ed0b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2231,6 +2231,32 @@
         public static final String BACKGROUND_DATA = "background_data";
 
         /**
+         * The time in msec, when the LAST_KMSG file was send to the checkin server.
+         * We will only send the LAST_KMSG file if it was modified after this time.
+         *
+         * @hide
+         */
+        public static final String CHECKIN_SEND_LAST_KMSG_TIME = "checkin_kmsg_time";
+
+        /**
+         * The time in msec, when the apanic_console file was send to the checkin server.
+         * We will only send the apanic_console file if it was modified after this time.
+         *
+         * @hide
+         */
+        public static final String CHECKIN_SEND_APANIC_CONSOLE_TIME =
+            "checkin_apanic_console_time";
+
+        /**
+         * The time in msec, when the apanic_thread file was send to the checkin server.
+         * We will only send the apanic_thread file if it was modified after this time.
+         *
+         * @hide
+         */
+        public static final String CHECKIN_SEND_APANIC_THREAD_TIME =
+            "checkin_apanic_thread_time";
+
+        /**
          * The CDMA roaming mode 0 = Home Networks, CDMA default
          *                       1 = Roaming on Affiliated networks
          *                       2 = Roaming on any networks
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index 8bae3e4..ce0c9cb 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -425,6 +425,11 @@
     }
 
     public void onClick(View view) {
+        // Make sure there is a contact
+        if (mContactUri == null) {
+            return;
+        }
+
         switch (view.getId()) {
             case R.id.star: {
                 // Toggle "starred" state
diff --git a/core/res/res/values-en-rUS/donottranslate-names.xml b/core/res/res/values-en-rUS/donottranslate-names.xml
index 42c8ab4..82ba310 100644
--- a/core/res/res/values-en-rUS/donottranslate-names.xml
+++ b/core/res/res/values-en-rUS/donottranslate-names.xml
@@ -147,7 +147,7 @@
         MD, MS, PH.D., PHD, SR, V, VI, VII, VIII, X
     </string>
     <string name="common_last_name_prefixes">
-        D', DE, DEL, DI, LA, LE, MC, SAN, ST, TER, VAN, VON
+        D\', DE, DEL, DI, LA, LE, MC, SAN, ST, TER, VAN, VON
     </string>
     <string name="common_name_conjunctions">
         &amp;, AND, OR
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 29cdf21..5b0e0b4 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -136,7 +136,7 @@
     void clearCodecSpecificData();
 
     void setAMRFormat();
-    void setAACFormat();
+    void setAACFormat(int32_t numChannels, int32_t sampleRate);
 
     status_t setVideoPortFormatType(
             OMX_U32 portIndex,
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 0831f4a..f80843d 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -3284,7 +3284,16 @@
                     break;
                 }
                 if (c == '\'' && (quoted == 0 || quoted == '\'')) {
-                    break;
+                    /*
+                     * In practice, when people write ' instead of \'
+                     * in a string, they are doing it by accident
+                     * instead of really meaning to use ' as a quoting
+                     * character.  Warn them so they don't lose it.
+                     */
+                    if (outErrorMsg) {
+                        *outErrorMsg = "Apostrophe not preceded by \\";
+                    }
+                    return false;
                 }
             }
             p++;
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 098ddbd..6af7df9 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -174,7 +174,7 @@
     *http_status = -1;
     mHeaders.clear();
 
-    char line[256];
+    char line[1024];
     status_t err = receive_line(line, sizeof(line));
     if (err != OK) {
         return err;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 3a065ae..7c8defc 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -302,7 +302,11 @@
         codec->setAMRFormat();
     }
     if (!createEncoder && !strcasecmp("audio/mp4a-latm", mime)) {
-        codec->setAACFormat();
+        int32_t numChannels, sampleRate;
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+
+        codec->setAACFormat(numChannels, sampleRate);
     }
     if (!strncasecmp(mime, "video/", 6)) {
         int32_t width, height;
@@ -1321,10 +1325,6 @@
         return;
     }
 
-    // We're going to temporarily give up the lock while reading data
-    // from the source. A certain client unfortunately chose to have the
-    // thread supplying input data and reading output data be the same...
-
     MediaBuffer *srcBuffer;
     status_t err;
     if (mSeekTimeUs >= 0) {
@@ -1332,13 +1332,10 @@
         options.setSeekTo(mSeekTimeUs);
         mSeekTimeUs = -1;
 
-        mLock.unlock();
         err = mSource->read(&srcBuffer, &options);
     } else {
-        mLock.unlock();
         err = mSource->read(&srcBuffer);
     }
-    mLock.lock();
 
     OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
     OMX_TICKS timestamp = 0;
@@ -1496,20 +1493,22 @@
     }
 }
 
-void OMXCodec::setAACFormat() {
-    OMX_AUDIO_PARAM_AACPROFILETYPE def;
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
-    def.nPortIndex = kPortIndexInput;
+void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
+    OMX_AUDIO_PARAM_AACPROFILETYPE profile;
+    profile.nSize = sizeof(profile);
+    profile.nVersion.s.nVersionMajor = 1;
+    profile.nVersion.s.nVersionMinor = 1;
+    profile.nPortIndex = kPortIndexInput;
 
     status_t err =
-        mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+        mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
     CHECK_EQ(err, OK);
 
-    def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+    profile.nChannels = numChannels;
+    profile.nSampleRate = sampleRate;
+    profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
 
-    err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+    err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
     CHECK_EQ(err, OK);
 }
 
@@ -2123,8 +2122,19 @@
             inputFormat->findInt32(kKeyChannelCount, &numChannels);
             inputFormat->findInt32(kKeySampleRate, &sampleRate);
 
+            if ((OMX_U32)numChannels != params.nChannels) {
+                LOGW("Codec outputs a different number of channels than "
+                     "the input stream contains.");
+            }
+
             mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
-            mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+
+            // Use the codec-advertised number of channels, as some
+            // codecs appear to output stereo even if the input data is
+            // mono.
+            mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
+
+            // The codec-reported sampleRate is not reliable...
             mOutputFormat->setInt32(kKeySampleRate, sampleRate);
             break;
         }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 8ec6ec3..14cd7a8 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -62,6 +62,8 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.Environment;
@@ -140,7 +142,7 @@
 
     final HandlerThread mHandlerThread = new HandlerThread("PackageManager",
             Process.THREAD_PRIORITY_BACKGROUND);
-    final Handler mHandler;
+    final PackageHandler mHandler;
 
     final int mSdkVersion = Build.VERSION.SDK_INT;
     final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME)
@@ -272,6 +274,49 @@
     ComponentName mResolveComponentName;
     PackageParser.Package mPlatformPackage;
 
+    // Set of pending broadcasts for aggregating enable/disable of components.
+    final HashMap<String, String> mPendingBroadcasts = new HashMap<String, String>();
+    static final int SEND_PENDING_BROADCAST = 1;
+    // Delay time in millisecs
+    static final int BROADCAST_DELAY = 10 * 1000;
+
+    class PackageHandler extends Handler {
+        PackageHandler(Looper looper) {
+            super(looper);
+        }
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case SEND_PENDING_BROADCAST : {
+                    int size = 0;
+                    String broadcastList[];
+                    HashMap<String, String> tmpMap;
+                    int uids[];
+                    synchronized (mPackages) {
+                        size = mPendingBroadcasts.size();
+                        if (size <= 0) {
+                            // Nothing to be done. Just return
+                            return;
+                        }
+                        broadcastList = new String[size];
+                        mPendingBroadcasts.keySet().toArray(broadcastList);
+                        tmpMap = new HashMap<String, String>(mPendingBroadcasts);
+                        uids = new int[size];
+                        for (int i = 0; i < size; i++) {
+                            PackageSetting ps = mSettings.mPackages.get(mPendingBroadcasts.get(broadcastList[i]));
+                            uids[i] = (ps != null) ? ps.userId : -1;
+                        }
+                        mPendingBroadcasts.clear();
+                    }
+                    // Send broadcasts
+                    for (int i = 0; i < size; i++) {
+                        String className = broadcastList[i];
+                        sendPackageChangedBroadcast(className, true, tmpMap.get(className), uids[i]);
+                    }
+                    break;
+                }
+            }
+        }
+    }
     public static final IPackageManager main(Context context, boolean factoryTest) {
         PackageManagerService m = new PackageManagerService(context, factoryTest);
         ServiceManager.addService("package", m);
@@ -355,7 +400,7 @@
         synchronized (mInstallLock) {
         synchronized (mPackages) {
             mHandlerThread.start();
-            mHandler = new Handler(mHandlerThread.getLooper());
+            mHandler = new PackageHandler(mHandlerThread.getLooper());
             
             File dataDir = Environment.getDataDirectory();
             mAppDataDir = new File(dataDir, "data");
@@ -4866,7 +4911,7 @@
     }
 
     private void setEnabledSetting(
-            final String packageNameStr, String classNameStr, int newState, final int flags) {
+            final String packageName, String className, int newState, final int flags) {
         if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
               || newState == COMPONENT_ENABLED_STATE_ENABLED
               || newState == COMPONENT_ENABLED_STATE_DISABLED)) {
@@ -4878,17 +4923,20 @@
         final int permission = mContext.checkCallingPermission(
                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
         final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+        boolean sendNow = false;
+        boolean isApp = (className == null);
+        String key = isApp ? packageName : className;
         int packageUid = -1;
         synchronized (mPackages) {
-            pkgSetting = mSettings.mPackages.get(packageNameStr);
+            pkgSetting = mSettings.mPackages.get(packageName);
             if (pkgSetting == null) {
-                if (classNameStr == null) {
+                if (className == null) {
                     throw new IllegalArgumentException(
-                            "Unknown package: " + packageNameStr);
+                            "Unknown package: " + packageName);
                 }
                 throw new IllegalArgumentException(
-                        "Unknown component: " + packageNameStr
-                        + "/" + classNameStr);
+                        "Unknown component: " + packageName
+                        + "/" + className);
             }
             if (!allowedByPermission && (uid != pkgSetting.userId)) {
                 throw new SecurityException(
@@ -4896,41 +4944,67 @@
                         + Binder.getCallingPid()
                         + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
             }
-            packageUid = pkgSetting.userId;
-            if (classNameStr == null) {
+            if (className == null) {
                 // We're dealing with an application/package level state change
                 pkgSetting.enabled = newState;
             } else {
                 // We're dealing with a component level state change
                 switch (newState) {
                 case COMPONENT_ENABLED_STATE_ENABLED:
-                    pkgSetting.enableComponentLP(classNameStr);
+                    pkgSetting.enableComponentLP(className);
                     break;
                 case COMPONENT_ENABLED_STATE_DISABLED:
-                    pkgSetting.disableComponentLP(classNameStr);
+                    pkgSetting.disableComponentLP(className);
                     break;
                 case COMPONENT_ENABLED_STATE_DEFAULT:
-                    pkgSetting.restoreComponentLP(classNameStr);
+                    pkgSetting.restoreComponentLP(className);
                     break;
                 default:
                     Log.e(TAG, "Invalid new component state: " + newState);
+                    return;
                 }
             }
             mSettings.writeLP();
+            packageUid = pkgSetting.userId;
+            if ((flags&PackageManager.DONT_KILL_APP) == 0) {
+                sendNow = true;
+                // Purge entry from pending broadcast list if another one exists already
+                // since we are sending one right away.
+                if (mPendingBroadcasts.get(key) != null) {
+                    mPendingBroadcasts.remove(key);
+                    // Can ignore empty list since its handled in the handler anyway
+                }
+            } else {
+                if (mPendingBroadcasts.get(key) == null) {
+                    mPendingBroadcasts.put(key, packageName);
+                }
+                if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
+                    // Schedule a message
+                    mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
+                }
+            }
         }
-        
+
         long callingId = Binder.clearCallingIdentity();
         try {
-            Bundle extras = new Bundle(2);
-            extras.putBoolean(Intent.EXTRA_DONT_KILL_APP,
-                    (flags&PackageManager.DONT_KILL_APP) != 0);
-            extras.putInt(Intent.EXTRA_UID, packageUid);
-            sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageNameStr, extras);
+            if (sendNow) {
+                sendPackageChangedBroadcast(packageName,
+                        (flags&PackageManager.DONT_KILL_APP) != 0, key, packageUid);
+            }
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
     }
 
+    private void sendPackageChangedBroadcast(String packageName,
+            boolean killFlag, String componentName, int packageUid) {
+        Bundle extras = new Bundle(2);
+        extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentName);
+        extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
+        extras.putInt(Intent.EXTRA_UID, packageUid);
+        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras);   
+    }
+
     public String getInstallerPackageName(String packageName) {
         synchronized (mPackages) {
             PackageSetting pkg = mSettings.mPackages.get(packageName);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 4c958f6..dab529e 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -46,6 +46,7 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.gsm.MccTable;
+import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.PhoneProxy;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyEventLog;
@@ -443,6 +444,8 @@
                     if (!mIsMinInfoReady) {
                         mIsMinInfoReady = true;
                     }
+                    phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
+                            null);
                 } else {
                     Log.w(LOG_TAG,"error parsing cdmaSubscription params num="
                             + cdmaSubscription.length);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 95a2384..f9d2434 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2364,13 +2364,12 @@
                         String8 region(config.string(), 2);
                         if (configSet.find(region) == configSet.end()) {
                             if (configSet.count(defaultLocale) == 0) {
-                                fprintf(stdout, "aapt: error: "
+                                fprintf(stdout, "aapt: warning: "
                                         "*** string '%s' has no default or required localization "
                                         "for '%s' in %s\n",
                                         String8(nameIter->first).string(),
                                         config.string(),
                                         mBundle->getResourceSourceDirs()[0]);
-                                err = UNKNOWN_ERROR;
                             }
                         }
                     }
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 6daa0d2..d4d2a45c 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -219,7 +219,12 @@
             }
             spanStack.pop();
 
-            if (empty) {
+            /*
+             * This warning seems to be just an irritation to most people,
+             * since it is typically introduced by translators who then never
+             * see the warning.
+             */
+            if (0 && empty) {
                 fprintf(stderr, "%s:%d: warning: empty '%s' span found in text '%s'\n",
                         fileName, inXml->getLineNumber(),
                         String8(spanTag).string(), String8(*outString).string());