Merge change 9522 into donut

* changes:
  Merge Korean abbreviated date format fix from cupcake.
diff --git a/Android.mk b/Android.mk
index 011e59e..fcb3e26 100644
--- a/Android.mk
+++ b/Android.mk
@@ -326,7 +326,13 @@
 
 framework_docs_LOCAL_MODULE_CLASS := JAVA_LIBRARIES
 framework_docs_LOCAL_DROIDDOC_HTML_DIR := docs/html
+# The since flag (-since N.xml API_LEVEL) is used to add API Level information
+# to the reference documentation. Must be in order of oldest to newest.
 framework_docs_LOCAL_DROIDDOC_OPTIONS := \
+    -since ./frameworks/base/api/1.xml 1 \
+    -since ./frameworks/base/api/2.xml 2 \
+    -since ./frameworks/base/api/3.xml 3 \
+    -since ./frameworks/base/api/current.xml Donut \
 		-error 1 -error 2 -warning 3 -error 4 -error 6 -error 8 \
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 95f3680..8db874a 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -674,6 +674,26 @@
                 }
                 values.put(MediaStore.MediaColumns.TITLE, title);
             }
+            String album = values.getAsString(Audio.Media.ALBUM);
+            if (MediaFile.UNKNOWN_STRING.equals(album)) {
+                album = values.getAsString(MediaStore.MediaColumns.DATA);
+                // extract last path segment before file name
+                int lastSlash = album.lastIndexOf('/');
+                if (lastSlash >= 0) {
+                    int previousSlash = 0;
+                    while (true) {
+                        int idx = album.indexOf('/', previousSlash + 1);
+                        if (idx < 0 || idx >= lastSlash) {
+                            break;
+                        }
+                        previousSlash = idx;
+                    }
+                    if (previousSlash != 0) {
+                        album = album.substring(previousSlash + 1, lastSlash);
+                        values.put(Audio.Media.ALBUM, album);
+                    }
+                }
+            }
             if (isAudio) {
                 values.put(Audio.Media.IS_RINGTONE, ringtones);
                 values.put(Audio.Media.IS_NOTIFICATION, notifications);
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 1b99d32..70960b5 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -142,6 +142,8 @@
     private final ReentrantLock synthesizerLock = new ReentrantLock();
 
     private static SynthProxy sNativeSynth = null;
+    private static Boolean sIsKillingSynth = true;
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -152,6 +154,7 @@
         String soLibPath = "/system/lib/libttspico.so";
         if (sNativeSynth == null) {
             sNativeSynth = new SynthProxy(soLibPath);
+            sIsKillingSynth = false;
         }
 
         mSelf = this;
@@ -172,6 +175,9 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
+
+        sIsKillingSynth = true;
+        Log.i("TtsService", "TtsService.onDestroy()");
         // Don't hog the media player
         cleanUpPlayer();
 
@@ -180,6 +186,7 @@
 
         // Unregister all callbacks.
         mCallbacks.kill();
+        //Log.i("TtsService", "TtsService.onDestroy() ended");
     }
 
 
@@ -243,6 +250,9 @@
 
 
     private int setSpeechRate(String callingApp, int rate) {
+        if (sIsKillingSynth) {
+            return TextToSpeech.ERROR;
+        }
         if (isDefaultEnforced()) {
             return sNativeSynth.setSpeechRate(getDefaultRate());
         } else {
@@ -252,23 +262,37 @@
 
 
     private int setPitch(String callingApp, int pitch) {
+        if (sIsKillingSynth) {
+            return TextToSpeech.ERROR;
+        }
         return sNativeSynth.setPitch(pitch);
     }
 
 
     private int isLanguageAvailable(String lang, String country, String variant) {
+        if (sIsKillingSynth) {
+            return TextToSpeech.LANG_NOT_SUPPORTED;
+        }
         //Log.v("TtsService", "TtsService.isLanguageAvailable(" + lang + ", " + country + ", " +variant+")");
         return sNativeSynth.isLanguageAvailable(lang, country, variant);
     }
 
 
     private String[] getLanguage() {
+        if (sIsKillingSynth) {
+            Log.v("TtsService", "killing synth:: aborting getLanguage()");
+            return null;
+        }
         return sNativeSynth.getLanguage();
     }
 
 
     private int setLanguage(String callingApp, String lang, String country, String variant) {
         Log.v("TtsService", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
+        if (sIsKillingSynth) {
+            Log.v("TtsService", "killing synth:: aborting setLanguage()");
+            return TextToSpeech.ERROR;
+        }
         if (isDefaultEnforced()) {
             return sNativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
                     getDefaultLocVariant());
@@ -402,7 +426,12 @@
                 }
                 if ((mCurrentSpeechItem != null) &&
                      mCurrentSpeechItem.mCallingApp.equals(callingApp)) {
-                    result = sNativeSynth.stop();
+                    if (sIsKillingSynth) {
+                        Log.v("TtsService", "killing synth:: aborting stop()");
+                        result = TextToSpeech.ERROR;
+                    } else {
+                        result = sNativeSynth.stop();
+                    }
                     mKillList.put(mCurrentSpeechItem, true);
                     if (mPlayer != null) {
                         try {
@@ -451,7 +480,12 @@
                 if ((mCurrentSpeechItem != null) &&
                     ((mCurrentSpeechItem.mType != SpeechItem.TEXT_TO_FILE) ||
                       mCurrentSpeechItem.mCallingApp.equals(callingApp))) {
-                    result = sNativeSynth.stop();
+                    if (sIsKillingSynth) {
+                        Log.v("TtsService", "killing synth:: aborting stop()");
+                        result = TextToSpeech.ERROR;
+                    } else {
+                        result = sNativeSynth.stop();
+                    }
                     mKillList.put(mCurrentSpeechItem, true);
                     if (mPlayer != null) {
                         try {
@@ -591,7 +625,9 @@
                         if (speechRate.length() > 0){
                             setSpeechRate("", Integer.parseInt(speechRate));
                         }
-                        sNativeSynth.speak(speechItem.mText, streamType);
+                        if (!sIsKillingSynth) {
+                            sNativeSynth.speak(speechItem.mText, streamType);
+                        }
                     }
                 } catch (InterruptedException e) {
                     Log.e("TtsService", "TTS speakInternalOnly(): tryLock interrupted");
@@ -660,7 +696,9 @@
                         if (speechRate.length() > 0){
                             setSpeechRate("", Integer.parseInt(speechRate));
                         }
-                        sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename);
+                        if (!sIsKillingSynth) {
+                            sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename);
+                        }
                     }
                 } catch (InterruptedException e) {
                     Log.e("TtsService", "TTS synthToFileInternalOnly(): tryLock interrupted");
diff --git a/tests/CoreTests/android/core/TestEventHandler.java b/tests/CoreTests/android/core/TestEventHandler.java
index 4cfcade..45f2f69 100644
--- a/tests/CoreTests/android/core/TestEventHandler.java
+++ b/tests/CoreTests/android/core/TestEventHandler.java
@@ -497,7 +497,7 @@
      * SSL certificate error callback. Handles SSL error(s) on the way
      * up to the user.
      */
-    public void handleSslErrorRequest(SslError error) {
+    public boolean handleSslErrorRequest(SslError error) {
       int primaryError = error.getPrimaryError();
 
       if (Config.LOGV) {
@@ -527,6 +527,9 @@
 
       if (expectSslErrors == -1) // && expectSslCertificate == certificate?
         expects[TEST_SSL_CERTIFICATE_ERROR] = false;
+
+      // return false so that we won't block the thread
+      return false;
     }
 
     /**
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
index de39800..71d9758 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
@@ -1,5 +1,7 @@
 package com.android.dumprendertree;
 
+import android.app.Activity;
+import android.content.Intent;
 import android.os.Handler;
 import android.os.Message;
 import android.test.ActivityInstrumentationTestCase2;
@@ -33,7 +35,7 @@
     }
 
     public void runReliabilityTest() throws Throwable {
-        ReliabilityTestActivity activity = getActivity();
+//        ReliabilityTestActivity activity = getActivity();
         LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner)getInstrumentation();
 
         File testListFile = new File(TEST_LIST_FILE);
@@ -54,6 +56,8 @@
         boolean timeoutFlag = false;
         long start, elapsed;
 
+        Intent intent = new Intent(runner.getContext(), ReliabilityTestActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         //read from BufferedReader instead of populating a list in advance,
         //this will avoid excessive memory usage in case of a large list
         while((url = listReader.readLine()) != null) {
@@ -63,6 +67,8 @@
             start = System.currentTimeMillis();
             Log.v(LOGTAG, "Testing URL: " + url);
             FsUtils.updateTestStatus(TEST_STATUS_FILE, url);
+            ReliabilityTestActivity activity = (ReliabilityTestActivity)runner.startActivitySync(
+                    intent);
             activity.reset();
             //use message to send new URL to avoid interacting with
             //WebView in non-UI thread
@@ -88,12 +94,13 @@
             if(runner.mLogtime) {
                 writeLoadTime(url, activity.getPageLoadTime());
             }
+            activity.finish();
             System.runFinalization();
             System.gc();
             System.gc();
         }
         FsUtils.updateTestStatus(TEST_STATUS_FILE, TEST_DONE);
-        activity.finish();
+//        activity.finish();
         listReader.close();
     }
 
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
index 5ddd0b3..db40daf 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
@@ -122,8 +122,9 @@
 
     @Override
     protected void onDestroy() {
-        Log.v(LOGTAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
         super.onDestroy();
+        Log.v(LOGTAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
+        webView.destroy();
     }
 
     private boolean isPageDone() {
@@ -270,8 +271,7 @@
         }
 
         public void run() {
-            if (initialStartCount == pageStartCount) {
-                //perform cleanup
+            if (initialStartCount == pageStartCount && !isPageDone()) {
                 handler.removeMessages(MSG_TIMEOUT);
                 webView.stopLoading();
                 handler.postDelayed(pageDoneRunner, manualDelay);