Merge "Ensure adapter is not null in AutoCompleteTextView"
diff --git a/api/current.xml b/api/current.xml
index 64f0c23..cd11b1d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -199698,6 +199698,8 @@
 >
 <implements name="android.widget.ExpandableListAdapter">
 </implements>
+<implements name="android.widget.HeterogeneousExpandableList">
+</implements>
 <constructor name="BaseExpandableListAdapter"
  type="android.widget.BaseExpandableListAdapter"
  static="false"
@@ -199717,6 +199719,32 @@
  visibility="public"
 >
 </method>
+<method name="getChildType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="groupPosition" type="int">
+</parameter>
+<parameter name="childPosition" type="int">
+</parameter>
+</method>
+<method name="getChildTypeCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getCombinedChildId"
  return="long"
  abstract="false"
@@ -199745,6 +199773,30 @@
 <parameter name="groupId" type="long">
 </parameter>
 </method>
+<method name="getGroupType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="groupPosition" type="int">
+</parameter>
+</method>
+<method name="getGroupTypeCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isEmpty"
  return="boolean"
  abstract="false"
@@ -203487,6 +203539,64 @@
 </parameter>
 </method>
 </class>
+<interface name="HeterogeneousExpandableList"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getChildType"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="groupPosition" type="int">
+</parameter>
+<parameter name="childPosition" type="int">
+</parameter>
+</method>
+<method name="getChildTypeCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getGroupType"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="groupPosition" type="int">
+</parameter>
+</method>
+<method name="getGroupTypeCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
 <class name="HorizontalScrollView"
  extends="android.widget.FrameLayout"
  abstract="false"
diff --git a/core/java/android/bluetooth/ScoSocket.java b/core/java/android/bluetooth/ScoSocket.java
index 116310a..b65a99a 100644
--- a/core/java/android/bluetooth/ScoSocket.java
+++ b/core/java/android/bluetooth/ScoSocket.java
@@ -86,14 +86,14 @@
     /** Connect this SCO socket to the given BT address.
      *  Does not block.
      */
-    public synchronized boolean connect(String address) {
+    public synchronized boolean connect(String address, String name) {
         if (DBG) log("connect() " + this);
         if (mState != STATE_READY) {
             if (DBG) log("connect(): Bad state");
             return false;
         }
         acquireWakeLock();
-        if (connectNative(address)) {
+        if (connectNative(address, name)) {
             mState = STATE_CONNECTING;
             return true;
         } else {
@@ -102,7 +102,7 @@
             return false;
         }
     }
-    private native boolean connectNative(String address);
+    private native boolean connectNative(String address, String name);
 
     /** Accept incoming SCO connections.
      *  Does not block.
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 816f8a8..72ceb9b 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -139,7 +139,10 @@
             if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
                 Log.v(TAG, "** warning ** Finalized DbObj (id#" + nStatement + ")");
             }
-            Log.w(TAG, "finalizer should never be called on sql: " + mSqlStmt, mStackTrace);
+            int len = mSqlStmt.length();
+            Log.w(TAG, "Releasing statement in a finalizer. Please ensure " +
+                    "that you explicitly call close() on your cursor: " +
+                    mSqlStmt.substring(0, (len > 100) ? 100 : len), mStackTrace);
             releaseSqlStatement();
         } finally {
             super.finalize();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 622d22d..37c43b8 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3133,7 +3133,7 @@
                 mOverScrollBackground = new Paint();
                 Bitmap bm = BitmapFactory.decodeResource(
                         mContext.getResources(),
-                        com.android.internal.R.drawable.pattern_underwear);
+                        com.android.internal.R.drawable.status_bar_background);
                 mOverScrollBackground.setShader(new BitmapShader(bm,
                         Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
             }
diff --git a/core/java/android/widget/BaseExpandableListAdapter.java b/core/java/android/widget/BaseExpandableListAdapter.java
index 1bba7f0..396b7ae 100644
--- a/core/java/android/widget/BaseExpandableListAdapter.java
+++ b/core/java/android/widget/BaseExpandableListAdapter.java
@@ -18,7 +18,6 @@
 
 import android.database.DataSetObservable;
 import android.database.DataSetObserver;
-import android.view.KeyEvent;
 
 /**
  * Base class for a {@link ExpandableListAdapter} used to provide data and Views
@@ -31,7 +30,8 @@
  * @see SimpleExpandableListAdapter
  * @see SimpleCursorTreeAdapter
  */
-public abstract class BaseExpandableListAdapter implements ExpandableListAdapter {
+public abstract class BaseExpandableListAdapter implements ExpandableListAdapter, 
+        HeterogeneousExpandableList {
     private final DataSetObservable mDataSetObservable = new DataSetObservable();
     
     public void registerDataSetObserver(DataSetObserver observer) {
@@ -102,5 +102,37 @@
     public boolean isEmpty() {
         return getGroupCount() == 0;
     }
-    
+
+
+    /**
+     * {@inheritDoc}
+     * @return 0 for any group or child position, since only one child type count is declared.
+     */
+    public int getChildType(int groupPosition, int childPosition) {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return 1 as a default value in BaseExpandableListAdapter.
+     */
+    public int getChildTypeCount() {
+        return 1;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return 0 for any groupPosition, since only one group type count is declared.
+     */
+    public int getGroupType(int groupPosition) {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return 1 as a default value in BaseExpandableListAdapter.
+     */
+    public int getGroupTypeCount() {
+        return 1;
+    }
 }
diff --git a/core/java/android/widget/ExpandableListAdapter.java b/core/java/android/widget/ExpandableListAdapter.java
index b75983c..7f6781b 100644
--- a/core/java/android/widget/ExpandableListAdapter.java
+++ b/core/java/android/widget/ExpandableListAdapter.java
@@ -17,7 +17,6 @@
 package android.widget;
 
 import android.database.DataSetObserver;
-import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -108,7 +107,7 @@
     /**
      * Gets a View that displays the given group. This View is only for the
      * group--the Views for the group's children will be fetched using
-     * getChildrenView.
+     * {@link #getChildView(int, int, boolean, View, ViewGroup)}.
      * 
      * @param groupPosition the position of the group for which the View is
      *            returned
diff --git a/core/java/android/widget/ExpandableListConnector.java b/core/java/android/widget/ExpandableListConnector.java
index 01d3a4a..2ff6b70 100644
--- a/core/java/android/widget/ExpandableListConnector.java
+++ b/core/java/android/widget/ExpandableListConnector.java
@@ -442,8 +442,8 @@
 
         View retValue;
         if (posMetadata.position.type == ExpandableListPosition.GROUP) {
-            retValue = mExpandableListAdapter.getGroupView(posMetadata.position.groupPos, posMetadata
-                    .isExpanded(), convertView, parent);
+            retValue = mExpandableListAdapter.getGroupView(posMetadata.position.groupPos,
+                    posMetadata.isExpanded(), convertView, parent);
         } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
             final boolean isLastChild = posMetadata.groupMetadata.lastChildFlPos == flatListPos;
             
@@ -464,10 +464,21 @@
         final ExpandableListPosition pos = getUnflattenedPos(flatListPos).position;
 
         int retValue;
-        if (pos.type == ExpandableListPosition.GROUP) {
-            retValue = 0;
+        if (mExpandableListAdapter instanceof HeterogeneousExpandableList) {
+            HeterogeneousExpandableList adapter =
+                    (HeterogeneousExpandableList) mExpandableListAdapter;
+            if (pos.type == ExpandableListPosition.GROUP) {
+                retValue = adapter.getGroupType(pos.groupPos);
+            } else {
+                final int childType = adapter.getChildType(pos.groupPos, pos.childPos);
+                retValue = adapter.getGroupTypeCount() + childType;
+            }
         } else {
-            retValue = 1;
+            if (pos.type == ExpandableListPosition.GROUP) {
+                retValue = 0;
+            } else {
+                retValue = 1;
+            }
         }
         
         pos.recycle();
@@ -477,7 +488,13 @@
 
     @Override
     public int getViewTypeCount() {
-        return 2;
+        if (mExpandableListAdapter instanceof HeterogeneousExpandableList) {
+            HeterogeneousExpandableList adapter =
+                    (HeterogeneousExpandableList) mExpandableListAdapter;
+            return adapter.getGroupTypeCount() + adapter.getChildTypeCount();
+        } else {
+            return 2;
+        }
     }
     
     @Override
diff --git a/core/java/android/widget/HeterogeneousExpandableList.java b/core/java/android/widget/HeterogeneousExpandableList.java
new file mode 100644
index 0000000..1292733
--- /dev/null
+++ b/core/java/android/widget/HeterogeneousExpandableList.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Additional methods that when implemented make an
+ * {@link ExpandableListAdapter} take advantage of the {@link Adapter} view type
+ * mechanism.
+ * 
+ * An {@link ExpandableListAdapter} declares one view type for its group items
+ * and one view type for its child items. Although adapted for most {@link ExpandableListView}s,
+ * these values should be tuned heterogeneous {@link ExpandableListView}s. Lists that contain
+ * different types of group and/or child item views, should use an adapter that implements this
+ * interface. This way, the recycled views that will be provided to
+ * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+ * and
+ * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+ * will be of the appropriate group or child type, resulting in a more efficient reuse of the
+ * previously created views.
+ */
+public interface HeterogeneousExpandableList {
+    /**
+     * Get the type of group View that will be created by
+     * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+     * . for the specified group item.
+     * 
+     * @param groupPosition the position of the group for which the type should be returned.
+     * @return An integer representing the type of group View. Two group views should share the same
+     *         type if one can be converted to the other in
+     *         {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+     *         . Note: Integers must be in the range 0 to {@link #getGroupTypeCount} - 1.
+     *         {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
+     * @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
+     * @see getGroupTypeCount()
+     */
+    int getGroupType(int groupPosition);
+
+    /**
+     * Get the type of child View that will be created by
+     * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+     * for the specified child item.
+     * 
+     * @param groupPosition the position of the group that the child resides in
+     * @param childPosition the position of the child with respect to other children in the group
+     * @return An integer representing the type of child View. Two child views should share the same
+     *         type if one can be converted to the other in
+     *         {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+     *         Note: Integers must be in the range 0 to {@link #getChildTypeCount} - 1.
+     *         {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
+     * @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
+     * @see getChildTypeCount()
+     */
+    int getChildType(int groupPosition, int childPosition);
+
+    /**
+     * <p>
+     * Returns the number of types of group Views that will be created by
+     * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+     * . Each type represents a set of views that can be converted in
+     * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
+     * . If the adapter always returns the same type of View for all group items, this method should
+     * return 1.
+     * </p>
+     * <p>
+     * This method will only be called when the adapter is set on the {@link AdapterView}.
+     * </p>
+     * 
+     * @return The number of types of group Views that will be created by this adapter.
+     * @see getChildTypeCount()
+     * @see getGroupType()
+     */
+    int getGroupTypeCount();
+
+    /**
+     * <p>
+     * Returns the number of types of child Views that will be created by
+     * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+     * . Each type represents a set of views that can be converted in
+     * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
+     * , for any group. If the adapter always returns the same type of View for
+     * all child items, this method should return 1.
+     * </p>
+     * <p>
+     * This method will only be called when the adapter is set on the {@link AdapterView}.
+     * </p>
+     * 
+     * @return The total number of types of child Views that will be created by this adapter.
+     * @see getGroupTypeCount()
+     * @see getChildType()
+     */
+    int getChildTypeCount();
+}
diff --git a/core/jni/android_bluetooth_ScoSocket.cpp b/core/jni/android_bluetooth_ScoSocket.cpp
index 3afe5f5..8588bc2 100644
--- a/core/jni/android_bluetooth_ScoSocket.cpp
+++ b/core/jni/android_bluetooth_ScoSocket.cpp
@@ -37,6 +37,23 @@
 #ifdef HAVE_BLUETOOTH
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sco.h>
+#include <bluetooth/hci.h>
+
+#define MAX_LINE 255
+
+/*
+ * Defines the module strings used in the blacklist file.
+ * These are used by consumers of the blacklist file to see if the line is
+ * used by that module.
+ */
+#define SCO_BLACKLIST_MODULE_NAME "scoSocket"
+
+
+/* Define the type strings used in the blacklist file. */
+#define BLACKLIST_BY_NAME "name"
+#define BLACKLIST_BY_PARTIAL_NAME "partial_name"
+#define BLACKLIST_BY_OUI "vendor_oui"
+
 #endif
 
 /* Ideally, blocking I/O on a SCO socket would return when another thread
@@ -67,11 +84,28 @@
 
 struct thread_data_t;
 static void *work_thread(void *arg);
-static int connect_work(const char *address);
+static int connect_work(const char *address, uint16_t sco_pkt_type);
 static int accept_work(int signal_sk);
 static void wait_for_close(int sk, int signal_sk);
 static void closeNative(JNIEnv *env, jobject object);
 
+static void parseBlacklist(void);
+static uint16_t getScoType(char *address, const char *name);
+
+#define COMPARE_STRING(key, s) (!strncmp(key, s, strlen(s)))
+
+/* Blacklist data */
+typedef struct scoBlacklist {
+    int fieldType;
+    char *value;
+    uint16_t scoType;
+    struct scoBlacklist *next;
+} scoBlacklist_t;
+
+#define BL_TYPE_NAME 1   // Field type is name string
+
+static scoBlacklist_t *blacklist = NULL;
+
 /* shared native data - protected by mutex */
 typedef struct {
     pthread_mutex_t mutex;
@@ -87,11 +121,144 @@
     bool is_accept;        // accept (listening) or connect (outgoing) thread
     int signal_sk;         // socket for thread to listen for unblock signal
     char address[BTADDR_SIZE];  // BT addres as string
+    uint16_t sco_pkt_type;   // SCO packet types supported
 };
 
 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
     return (native_data_t *)(env->GetIntField(object, field_mNativeData));
 }
+
+static uint16_t str2scoType (char *key) {
+    LOGV("%s: key = %s", __FUNCTION__, key);
+    if (COMPARE_STRING(key, "ESCO_HV1"))
+        return ESCO_HV1;
+    if (COMPARE_STRING(key, "ESCO_HV2"))
+        return ESCO_HV2;
+    if (COMPARE_STRING(key, "ESCO_HV3"))
+        return ESCO_HV3;
+    if (COMPARE_STRING(key, "ESCO_EV3"))
+        return ESCO_EV3;
+    if (COMPARE_STRING(key, "ESCO_EV4"))
+        return ESCO_EV4;
+    if (COMPARE_STRING(key, "ESCO_EV5"))
+        return ESCO_EV5;
+    if (COMPARE_STRING(key, "ESCO_2EV3"))
+        return ESCO_2EV3;
+    if (COMPARE_STRING(key, "ESCO_3EV3"))
+        return ESCO_3EV3;
+    if (COMPARE_STRING(key, "ESCO_2EV5"))
+        return ESCO_2EV5;
+    if (COMPARE_STRING(key, "ESCO_3EV5"))
+        return ESCO_3EV5;
+    if (COMPARE_STRING(key, "SCO_ESCO_MASK"))
+        return SCO_ESCO_MASK;
+    if (COMPARE_STRING(key, "EDR_ESCO_MASK"))
+        return EDR_ESCO_MASK;
+    if (COMPARE_STRING(key, "ALL_ESCO_MASK"))
+        return ALL_ESCO_MASK;
+    LOGE("Unknown SCO Type (%s) skipping",key);
+    return 0;
+}
+
+static void parseBlacklist(void) {
+    const char *filename = "/etc/bluetooth/blacklist.conf";
+    char line[MAX_LINE];
+    scoBlacklist_t *list = NULL;
+    scoBlacklist_t *newelem;
+
+    LOGV(__FUNCTION__);
+
+    /* Open file */
+    FILE *fp = fopen(filename, "r");
+    if(!fp) {
+        LOGE("Error(%s)opening blacklist file", strerror(errno));
+        return;
+    }
+
+    while (fgets(line, MAX_LINE, fp) != NULL) {
+        if ((COMPARE_STRING(line, "//")) || (!strcmp(line, "")))
+            continue;
+        char *module = strtok(line,":");
+        if (COMPARE_STRING(module, SCO_BLACKLIST_MODULE_NAME)) {
+            newelem = (scoBlacklist_t *)calloc(1, sizeof(scoBlacklist_t));
+            if (newelem == NULL) {
+                LOGE("%s: out of memory!", __FUNCTION__);
+                return;
+            }
+            // parse line
+            char *type = strtok(NULL, ",");
+            char *valueList = strtok(NULL, ",");
+            char *paramList = strtok(NULL, ",");
+            if (COMPARE_STRING(type, BLACKLIST_BY_NAME)) {
+                // Extract Name from Value list
+                newelem->fieldType = BL_TYPE_NAME;
+                newelem->value = (char *)calloc(1, strlen(valueList));
+                if (newelem->value == NULL) {
+                    LOGE("%s: out of memory!", __FUNCTION__);
+                    continue;
+                }
+                valueList++;  // Skip open quote
+                strncpy(newelem->value, valueList, strlen(valueList) - 1);
+
+                // Get Sco Settings from Parameters
+                char *param = strtok(paramList, ";");
+                uint16_t scoTypes = 0;
+                while (param != NULL) {
+                    uint16_t sco;
+                    if (param[0] == '-') {
+                        param++;
+                        sco = str2scoType(param);
+                        if (sco != 0)
+                            scoTypes &= ~sco;
+                    } else if (param[0] == '+') {
+                        param++;
+                        sco = str2scoType(param);
+                        if (sco != 0)
+                            scoTypes |= sco;
+                    } else if (param[0] == '=') {
+                        param++;
+                        sco = str2scoType(param);
+                        if (sco != 0)
+                            scoTypes = sco;
+                    } else {
+                        LOGE("Invalid SCO type must be =, + or -");
+                    }
+                    param = strtok(NULL, ";");
+                }
+                newelem->scoType = scoTypes;
+            } else {
+                LOGE("Unknown SCO type entry in Blacklist file");
+                continue;
+            }
+            if (list) {
+                list->next = newelem;
+                list = newelem;
+            } else {
+                blacklist = list = newelem;
+            }
+            LOGI("Entry name = %s ScoTypes = 0x%x", newelem->value,
+                 newelem->scoType);
+        }
+    }
+    fclose(fp);
+    return;
+}
+static uint16_t getScoType(char *address, const char *name) {
+    uint16_t ret = 0;
+    scoBlacklist_t *list = blacklist;
+
+    while (list != NULL) {
+        if (list->fieldType == BL_TYPE_NAME) {
+            if (COMPARE_STRING(name, list->value)) {
+                ret = list->scoType;
+                break;
+            }
+        }
+        list = list->next;
+    }
+    LOGI("%s %s - 0x%x",  __FUNCTION__, name, ret);
+    return ret;
+}
 #endif
 
 static void classInitNative(JNIEnv* env, jclass clazz) {
@@ -104,6 +271,9 @@
     method_onAccepted = env->GetMethodID(clazz, "onAccepted", "(I)V");
     method_onConnected = env->GetMethodID(clazz, "onConnected", "(I)V");
     method_onClosed = env->GetMethodID(clazz, "onClosed", "()V");
+
+    /* Read the blacklist file in here */
+    parseBlacklist();
 #endif
 }
 
@@ -192,7 +362,9 @@
     return JNI_FALSE;
 }
 
-static jboolean connectNative(JNIEnv *env, jobject object, jstring address) {
+static jboolean connectNative(JNIEnv *env, jobject object, jstring address,
+        jstring name) {
+
     LOGV(__FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
@@ -200,6 +372,7 @@
     pthread_t thread;
     struct thread_data_t *data;
     const char *c_address;
+    const char *c_name;
 
     pthread_mutex_lock(&nat->mutex);
     if (nat->signal_sk != -1) {
@@ -231,6 +404,11 @@
     env->ReleaseStringUTFChars(address, c_address);
     data->is_accept = false;
 
+    c_name = env->GetStringUTFChars(name, NULL);
+    /* See if this device is in the black list */
+    data->sco_pkt_type = getScoType(data->address, c_name);
+    env->ReleaseStringUTFChars(name, c_name);
+
     if (pthread_create(&thread, NULL, &work_thread, (void *)data) < 0) {
         LOGE("%s: pthread_create() failed: %s", __FUNCTION__, strerror(errno));
         return JNI_FALSE;
@@ -282,7 +460,7 @@
         sk = accept_work(data->signal_sk);
         LOGV("SCO OBJECT %p END ACCEPT *****", data->nat->object);
     } else {
-        sk = connect_work(data->address);
+        sk = connect_work(data->address, data->sco_pkt_type);
     }
 
     /* callback with connection result */
@@ -426,7 +604,7 @@
     return -1;
 }
 
-static int connect_work(const char *address) {
+static int connect_work(const char *address, uint16_t sco_pkt_type) {
     LOGV(__FUNCTION__);
     struct sockaddr_sco addr;
     int sk = -1;
@@ -449,6 +627,7 @@
     memset(&addr, 0, sizeof(addr));
     addr.sco_family = AF_BLUETOOTH;
     get_bdaddr(address, &addr.sco_bdaddr);
+    addr.sco_pkt_type = sco_pkt_type;
     LOGI("Connecting to socket");
     while (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
         if (errno != EINTR) {
@@ -493,7 +672,7 @@
     {"classInitNative", "()V", (void*)classInitNative},
     {"initNative", "()V", (void *)initNative},
     {"destroyNative", "()V", (void *)destroyNative},
-    {"connectNative", "(Ljava/lang/String;)Z", (void *)connectNative},
+    {"connectNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)connectNative},
     {"acceptNative", "()Z", (void *)acceptNative},
     {"closeNative", "()V", (void *)closeNative},
 };
diff --git a/core/res/res/drawable/pattern_underwear.png b/core/res/res/drawable/pattern_underwear.png
deleted file mode 100644
index 651212f..0000000
--- a/core/res/res/drawable/pattern_underwear.png
+++ /dev/null
Binary files differ
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index e9bcafe..f845fec1 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -634,12 +634,12 @@
             } else if (MediaFile.isImageFileType(mFileType)) {
                 // FIXME - add DESCRIPTION
             } else if (MediaFile.isAudioFileType(mFileType)) {
-                String artist = mArtist != null && mArtist.length() > 0 ?
-                        mArtist : MediaStore.UNKNOWN_STRING;
-                map.put(Audio.Media.ARTIST, artist);
-                map.put(Audio.Media.ALBUM_ARTIST, mAlbumArtist != null &&
-                        mAlbumArtist.length() > 0 ? mAlbumArtist : artist);
-                map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaStore.UNKNOWN_STRING));
+                map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ?
+                        mArtist : MediaStore.UNKNOWN_STRING);
+                map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null &&
+                        mAlbumArtist.length() > 0) ? mAlbumArtist : null);
+                map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ?
+                        mAlbum : MediaStore.UNKNOWN_STRING);
                 map.put(Audio.Media.COMPOSER, mComposer);
                 if (mYear != 0) {
                     map.put(Audio.Media.YEAR, mYear);
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index ee6b89c..63d50c7 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -121,6 +121,10 @@
  * -e class com.android.foo.FooTest,com.android.foo.TooTest
  * com.android.foo/android.test.InstrumentationTestRunner
  * <p/>
+ * <b>Running all tests in a java package:</b> adb shell am instrument -w
+ * -e package com.android.foo.subpkg
+ *  com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
  * <b>Including performance tests:</b> adb shell am instrument -w
  * -e perf true
  * com.android.foo/android.test.InstrumentationTestRunner