Merge "Updates the status of some HTML5 storage layout tests in the DumpRenderTree skipped list"
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index cc1167f..e9b21f1 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -115,8 +115,8 @@
     dump_file("KERNEL WAKELOCKS", "/proc/wakelocks");
     dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
 
+    run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
     run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
-    run_command("MOUNTED FILESYSTEMS", 10, "df", NULL);
 
     run_command("PROCESSES", 10, "ps", "-P", NULL);
     run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index ebc64d7..add99d7 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -483,7 +483,7 @@
         int textId = mSearchable.getSearchButtonText(); 
         if (isBrowserSearch()){
             iconLabel = getContext().getResources()
-                    .getDrawable(com.android.internal.R.drawable.ic_btn_search_play);
+                    .getDrawable(com.android.internal.R.drawable.ic_btn_search_go);
         } else if (textId != 0) {
             textLabel = mActivityContext.getResources().getString(textId);  
         } else {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 034a631..3a34fb4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3851,7 +3851,6 @@
                 || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
             if (nativeFocusIsPlugin()) {
                 mShiftIsPressed = false;
-                return true;
             } else if (commitCopy()) {
                 return true;
             }
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 9537ba0..5482958 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -985,6 +985,11 @@
 
     /** {@inheritDoc} */
     public void onFilterComplete(int count) {
+        updateDropDownForFilter(count);
+
+    }
+
+    private void updateDropDownForFilter(int count) {
         // Not attached to window, don't update drop-down
         if (getWindowVisibility() == View.GONE) return;
 
@@ -1214,18 +1219,30 @@
         ViewGroup dropDownView;
         int otherHeights = 0;
 
-        if (mAdapter != null) {
+        final ListAdapter adapter = mAdapter;
+        if (adapter != null) {
             InputMethodManager imm = InputMethodManager.peekInstance();
             if (imm != null) {
-                int N = mAdapter.getCount();
-                if (N > 20) N = 20;
-                CompletionInfo[] completions = new CompletionInfo[N];
-                for (int i = 0; i < N; i++) {
-                    Object item = mAdapter.getItem(i);
-                    long id = mAdapter.getItemId(i);
-                    completions[i] = new CompletionInfo(id, i,
-                            convertSelectionToString(item));
+                final int count = Math.min(adapter.getCount(), 20);
+                CompletionInfo[] completions = new CompletionInfo[count];
+                int realCount = 0;
+
+                for (int i = 0; i < count; i++) {
+                    if (adapter.isEnabled(i)) {
+                        realCount++;
+                        Object item = adapter.getItem(i);
+                        long id = adapter.getItemId(i);
+                        completions[i] = new CompletionInfo(id, i,
+                                convertSelectionToString(item));
+                    }
                 }
+                
+                if (realCount != count) {
+                    CompletionInfo[] tmp = new CompletionInfo[realCount];
+                    System.arraycopy(completions, 0, tmp, 0, realCount);
+                    completions = tmp;
+                }
+
                 imm.displayCompletions(this, completions);
             }
         }
@@ -1253,7 +1270,7 @@
 
             mDropDownList = new DropDownListView(context);
             mDropDownList.setSelector(mDropDownListHighlight);
-            mDropDownList.setAdapter(mAdapter);
+            mDropDownList.setAdapter(adapter);
             mDropDownList.setVerticalFadingEdgeEnabled(true);
             mDropDownList.setOnItemClickListener(mDropDownItemClickListener);
             mDropDownList.setFocusable(true);
@@ -1599,6 +1616,16 @@
             if (isPopupShowing()) {
                 // This will resize the popup to fit the new adapter's content
                 showDropDown();
+            } else if (mAdapter != null) {
+                // If the popup is not showing already, showing it will cause
+                // the list of data set observers attached to the adapter to
+                // change. We can't do it from here, because we are in the middle
+                // of iterating throught he list of observers.
+                post(new Runnable() {
+                    public void run() {
+                        updateDropDownForFilter(mAdapter.getCount());
+                    }
+                });
             }
         }
 
diff --git a/core/res/res/drawable-hdpi/ic_btn_search_go.png b/core/res/res/drawable-hdpi/ic_btn_search_go.png
new file mode 100644
index 0000000..8a3a402
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_search_go.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_search_play.png b/core/res/res/drawable-hdpi/ic_btn_search_play.png
deleted file mode 100644
index fb1b974..0000000
--- a/core/res/res/drawable-hdpi/ic_btn_search_play.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_btn_search_go.png b/core/res/res/drawable-mdpi/ic_btn_search_go.png
new file mode 100644
index 0000000..0ed9e8e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_btn_search_go.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_btn_search_play.png b/core/res/res/drawable-mdpi/ic_btn_search_play.png
deleted file mode 100644
index dc25dae..0000000
--- a/core/res/res/drawable-mdpi/ic_btn_search_play.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/layout-land/usb_storage_activity.xml b/core/res/res/layout-land/usb_storage_activity.xml
index d714479..50ca569 100644
--- a/core/res/res/layout-land/usb_storage_activity.xml
+++ b/core/res/res/layout-land/usb_storage_activity.xml
@@ -24,7 +24,7 @@
 
         <TextView android:id="@+id/banner"
             android:layout_centerHorizontal="true"
-            android:layout_below="@id/icon"
+            android:layout_alignParentTop="true"
             android:layout_marginTop="10dip"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -45,8 +45,8 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_centerHorizontal="true"
-            android:layout_below="@id/message"
-            android:layout_marginTop="20dip"
+            android:layout_alignParentBottom="true"
+            android:layout_marginBottom="20dip"
             >
 
             <Button android:id="@+id/mount_button" 
@@ -64,6 +64,13 @@
                 android:paddingRight="18dip"
                 android:text="@string/usb_storage_stop_button_mount"
                 />
+            <ProgressBar android:id="@+id/progress"
+                android:visibility="gone"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:indeterminate="true"
+                style="?android:attr/progressBarStyle"
+                />
 
         </RelativeLayout>
     </RelativeLayout>
diff --git a/core/res/res/layout/usb_storage_activity.xml b/core/res/res/layout/usb_storage_activity.xml
index 86bfadb..76c30fd 100644
--- a/core/res/res/layout/usb_storage_activity.xml
+++ b/core/res/res/layout/usb_storage_activity.xml
@@ -37,8 +37,8 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_centerHorizontal="true"
-        android:layout_below="@id/message"
-        android:layout_marginTop="20dip"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="20dip"
         >
 
         <Button android:id="@+id/mount_button" 
@@ -56,6 +56,13 @@
             android:paddingRight="18dip"
             android:text="@string/usb_storage_stop_button_mount"
             />
+        <ProgressBar android:id="@+id/progress"
+            android:visibility="gone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:indeterminate="true"
+            style="?android:attr/progressBarStyle"
+            />
 
     </RelativeLayout>
 </RelativeLayout>
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 7902212..815a367 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -72,6 +72,10 @@
 // 50 * ~20msecs = 1 second
 static const int8_t kMaxTrackRetries = 50;
 static const int8_t kMaxTrackStartupRetries = 50;
+// allow less retry attempts on direct output thread.
+// direct outputs can be a scarce resource in audio hardware and should
+// be released as quickly as possible.
+static const int8_t kMaxTrackRetriesDirect = 2;
 
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleep = 20000;
@@ -1794,6 +1798,9 @@
     uint32_t activeSleepTime = activeSleepTimeUs();
     uint32_t idleSleepTime = idleSleepTimeUs();
     uint32_t sleepTime = idleSleepTime;
+    // use shorter standby delay as on normal output to release
+    // hardware resources as soon as possible
+    nsecs_t standbyDelay = microseconds(activeSleepTime*2);
 
 
     while (!exitPending())
@@ -1810,6 +1817,7 @@
                 mixBufferSize = mFrameCount*mFrameSize;
                 activeSleepTime = activeSleepTimeUs();
                 idleSleepTime = idleSleepTimeUs();
+                standbyDelay = microseconds(activeSleepTime*2);
             }
 
             // put audio hardware into standby after short delay
@@ -1842,7 +1850,7 @@
                         }
                     }
 
-                    standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    standbyTime = systemTime() + standbyDelay;
                     sleepTime = idleSleepTime;
                     continue;
                 }
@@ -1896,7 +1904,7 @@
                     }
 
                     // reset retry count
-                    track->mRetryCount = kMaxTrackRetries;
+                    track->mRetryCount = kMaxTrackRetriesDirect;
                     activeTrack = t;
                     mixerStatus = MIXER_TRACKS_READY;
                 } else {
@@ -1949,7 +1957,7 @@
                 activeTrack->releaseBuffer(&buffer);
             }
             sleepTime = 0;
-            standbyTime = systemTime() + kStandbyTimeInNsecs;
+            standbyTime = systemTime() + standbyDelay;
         } else {
             if (sleepTime == 0) {
                 if (mixerStatus == MIXER_TRACKS_ENABLED) {
diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp
index a61221a..c8b3f48 100644
--- a/libs/audioflinger/AudioPolicyManagerBase.cpp
+++ b/libs/audioflinger/AudioPolicyManagerBase.cpp
@@ -458,11 +458,8 @@
     }
 #endif //AUDIO_POLICY_TEST
 
-    // open a direct output if:
-    // 1 a direct output is explicitely requested
-    // 2 the audio format is compressed
-    if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
-         (format !=0 && !AudioSystem::isLinearPCM(format))) {
+    // open a direct output if required by specified parameters
+    if (needsDirectOuput(stream, samplingRate, format, channels, flags, device)) {
 
         LOGV("getOutput() opening direct output device %x", device);
         AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
@@ -472,7 +469,7 @@
         outputDesc->mChannels = channels;
         outputDesc->mLatency = 0;
         outputDesc->mFlags = (AudioSystem::output_flags)(flags | AudioSystem::OUTPUT_FLAG_DIRECT);
-        outputDesc->mRefCount[stream] = 1;
+        outputDesc->mRefCount[stream] = 0;
         output = mpClientInterface->openOutput(&outputDesc->mDevice,
                                         &outputDesc->mSamplingRate,
                                         &outputDesc->mFormat,
@@ -609,6 +606,9 @@
             setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2);
         }
 #endif
+        if (output != mHardwareOutput) {
+            setOutputDevice(mHardwareOutput, getNewDevice(mHardwareOutput), true);
+        }
         return NO_ERROR;
     } else {
         LOGW("stopOutput() refcount is already 0 for output %d", output);
@@ -1550,10 +1550,10 @@
     }
 #ifdef WITH_A2DP
     // filter devices according to output selected
-    if (output == mHardwareOutput) {
-        device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP;
-    } else {
+    if (output == mA2dpOutput) {
         device &= AudioSystem::DEVICE_OUT_ALL_A2DP;
+    } else {
+        device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP;
     }
 #endif
 
@@ -1562,8 +1562,7 @@
     //  - the requestede device is 0
     //  - the requested device is the same as current device and force is not specified.
     // Doing this check here allows the caller to call setOutputDevice() without conditions
-    if (device == 0 ||
-        (device == prevDevice && !force)) {
+    if ((device == 0 || device == prevDevice) && !force) {
         LOGV("setOutputDevice() setting same device %x or null device for output %d", device, output);
         return;
     }
@@ -1666,7 +1665,7 @@
     int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin);
     volume = AudioSystem::linearToLog(volInt);
 
-    // if a heaset is connected, apply the following rules to ring tones and notifications
+    // if a headset is connected, apply the following rules to ring tones and notifications
     // to avoid sound level bursts in user's ears:
     // - always attenuate ring tones and notifications volume by 6dB
     // - if music is playing, always limit the volume to current music volume,
@@ -1825,6 +1824,17 @@
     }
 }
 
+bool AudioPolicyManagerBase::needsDirectOuput(AudioSystem::stream_type stream,
+                                    uint32_t samplingRate,
+                                    uint32_t format,
+                                    uint32_t channels,
+                                    AudioSystem::output_flags flags,
+                                    uint32_t device)
+{
+   return ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
+          (format !=0 && !AudioSystem::isLinearPCM(format)));
+}
+
 // --- AudioOutputDescriptor class implementation
 
 AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor()
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 4b364f2..5e6ce42 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -358,7 +358,7 @@
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     unsigned int result = 0;
     if (af == 0) return result;
-    if (ioHandle == NULL) return result;
+    if (ioHandle == 0) return result;
 
     result = af->getInputFramesLost(ioHandle);
     return result;
@@ -556,7 +556,18 @@
                                     output_flags flags)
 {
     audio_io_handle_t output = 0;
-    if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
+    // Do not use stream to output map cache if the direct output
+    // flag is set or if we are likely to use a direct output
+    // (e.g voice call stream @ 8kHz could use BT SCO device and be routed to
+    // a direct output on some platforms).
+    // TODO: the output cache and stream to output mapping implementation needs to
+    // be reworked for proper operation with direct outputs. This code is too specific
+    // to the first use case we want to cover (Voice Recognition and Voice Dialer over
+    // Bluetooth SCO
+    if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0 &&
+        ((stream != AudioSystem::VOICE_CALL && stream != AudioSystem::BLUETOOTH_SCO) ||
+         channels != AudioSystem::CHANNEL_OUT_MONO ||
+         (samplingRate != 8000 && samplingRate != 16000))) {
         Mutex::Autolock _l(gLock);
         output = AudioSystem::gStreamOutputMap.valueFor(stream);
         LOGV_IF((output != 0), "getOutput() read %d from cache for stream %d", output, stream);
diff --git a/services/java/com/android/server/status/UsbStorageActivity.java b/services/java/com/android/server/status/UsbStorageActivity.java
index c1c8c22..b3ee257 100644
--- a/services/java/com/android/server/status/UsbStorageActivity.java
+++ b/services/java/com/android/server/status/UsbStorageActivity.java
@@ -28,6 +28,7 @@
 import android.content.DialogInterface.OnCancelListener;
 import android.os.Bundle;
 import android.os.Environment;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
@@ -36,8 +37,10 @@
 import android.os.ServiceManager;
 import android.widget.ImageView;
 import android.widget.Button;
+import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.view.View;
+import android.view.Window;
 import android.util.Log;
 
 /**
@@ -48,8 +51,10 @@
 public class UsbStorageActivity extends Activity
         implements View.OnClickListener, OnCancelListener {
     private static final String TAG = "UsbStorageActivity";
+
     private Button mMountButton;
     private Button mUnmountButton;
+    private ProgressBar mProgressBar;
     private TextView mBanner;
     private TextView mMessage;
     private ImageView mIcon;
@@ -71,11 +76,8 @@
     private StorageEventListener mStorageListener = new StorageEventListener() {
         @Override
         public void onStorageStateChanged(String path, String oldState, String newState) {
-            if (newState.equals(Environment.MEDIA_SHARED)) {
-                switchDisplay(true);
-            } else {
-                switchDisplay(false);
-            }
+            final boolean on = newState.equals(Environment.MEDIA_SHARED);
+            switchDisplay(on);
         }
     };
     
@@ -90,6 +92,9 @@
             }
         }
 
+        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+        setProgressBarIndeterminateVisibility(true);
+
         setTitle(getString(com.android.internal.R.string.usb_storage_activity_title));
 
         setContentView(com.android.internal.R.layout.usb_storage_activity);
@@ -102,16 +107,19 @@
         mMountButton.setOnClickListener(this);
         mUnmountButton = (Button) findViewById(com.android.internal.R.id.unmount_button);
         mUnmountButton.setOnClickListener(this);
+        mProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress);
     }
 
     private void switchDisplay(boolean usbStorageInUse) {
         if (usbStorageInUse) {
+            mProgressBar.setVisibility(View.GONE);
             mUnmountButton.setVisibility(View.VISIBLE);
             mMountButton.setVisibility(View.GONE);
             mIcon.setImageResource(com.android.internal.R.drawable.usb_android_connected);
             mBanner.setText(com.android.internal.R.string.usb_storage_stop_title);
             mMessage.setText(com.android.internal.R.string.usb_storage_stop_message);
         } else {
+            mProgressBar.setVisibility(View.GONE);
             mUnmountButton.setVisibility(View.GONE);
             mMountButton.setVisibility(View.VISIBLE);
             mIcon.setImageResource(com.android.internal.R.drawable.usb_android);
@@ -189,6 +197,25 @@
         showDialog(id);
     }
 
+    private void switchUsbMassStorageAsync(boolean on) {
+        mUnmountButton.setVisibility(View.GONE);
+        mMountButton.setVisibility(View.GONE);
+
+        mProgressBar.setVisibility(View.VISIBLE);
+        // will be hidden once USB mass storage kicks in (or fails)
+        
+        final boolean _on = on;
+        new Thread() {
+            public void run() {
+                if (_on) {
+                    mStorageManager.enableUsbMassStorage();
+                } else {
+                    mStorageManager.disableUsbMassStorage();
+                }
+            }
+        }.start();
+    }
+
     private void checkStorageUsers() {
         IMountService ims = getMountService();
         if (ims == null) {
@@ -208,18 +235,17 @@
             showDialogInner(DLG_CONFIRM_KILL_STORAGE_USERS);
         } else {
             if (localLOGV) Log.i(TAG, "Enabling UMS");
-            mStorageManager.enableUsbMassStorage();
+            switchUsbMassStorageAsync(true);
         }
     }
 
     public void onClick(View v) {
-        Log.i(TAG, "Clicked button");
         if (v == mMountButton) {
            // Check for list of storage users and display dialog if needed.
             checkStorageUsers();
         } else if (v == mUnmountButton) {
             if (localLOGV) Log.i(TAG, "Disabling UMS");
-            mStorageManager.disableUsbMassStorage();
+            switchUsbMassStorageAsync(false);
         }
     }
 
diff --git a/tests/AndroidTests/src/com/android/unit_tests/internal/util/HanziToPinyinTest.java b/tests/AndroidTests/src/com/android/unit_tests/internal/util/HanziToPinyinTest.java
index 8e1ff0b..71a8ea7 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/internal/util/HanziToPinyinTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/internal/util/HanziToPinyinTest.java
@@ -17,6 +17,7 @@
 package com.android.unit_tests.internal.util;
 
 import java.text.Collator;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Locale;
 
@@ -37,6 +38,9 @@
 
     @SmallTest
     public void testGetToken() throws Exception {
+        if (!Arrays.asList(Collator.getAvailableLocales()).contains(Locale.CHINA)) {
+            return;
+        }
         ArrayList<Token> tokens = HanziToPinyin.getInstance().get(ONE_HANZI);
         assertEquals(tokens.size(), 1);
         assertEquals(tokens.get(0).type, Token.PINYIN);