Merge "Teach NetworkIdentity about roaming."
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 5df2343..2b9c082 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -81,4 +81,13 @@
 
     /* Clears default preferences and permissions for the package */
     void clearDefaults(String packageName);
+
+    /* Sets the current primary USB function. */
+    void setPrimaryFunction(String functions);
+
+    /* Sets the default primary USB function. */
+    void setDefaultFunction(String functions);
+
+    /* Sets the file path for USB mass storage backing file. */
+    void setMassStorageBackingFile(String path);
 }
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 5994c98..a828a23 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -22,12 +22,9 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.util.Log;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
 import java.util.HashMap;
 
 /**
@@ -50,7 +47,7 @@
      * This is a sticky broadcast for clients that includes USB connected/disconnected state,
      * <ul>
      * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected.
-     * <li> {@link #USB_CONFIGURATION} integer containing current USB configuration
+     * <li> {@link #USB_CONFIGURED} boolean indicating whether USB is configured.
      * currently zero if not configured, one for configured.
      * <li> {@link #USB_FUNCTION_MASS_STORAGE} boolean extra indicating whether the
      * mass storage function is enabled
@@ -128,12 +125,12 @@
     public static final String USB_CONNECTED = "connected";
 
     /**
-     * Integer extra containing currently set USB configuration.
+     * Boolean extra indicating whether USB is configured.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
      * {@hide}
      */
-    public static final String USB_CONFIGURATION = "configuration";
+    public static final String USB_CONFIGURED = "configured";
 
     /**
      * Name of the USB mass storage USB function.
@@ -388,21 +385,14 @@
         }
     }
 
-    private static File getFunctionEnableFile(String function) {
-        return new File("/sys/class/usb_composite/" + function + "/enable");
-    }
-
-    /**
-     * Returns true if the specified USB function is supported by the kernel.
-     * Note that a USB function maybe supported but disabled.
-     *
-     * @param function name of the USB function
-     * @return true if the USB function is supported.
-     *
-     * {@hide}
-     */
-    public static boolean isFunctionSupported(String function) {
-        return getFunctionEnableFile(function).exists();
+    private static boolean propertyContainsFunction(String property, String function) {
+        String functions = SystemProperties.get(property, "");
+        int index = functions.indexOf(function);
+        if (index < 0) return false;
+        if (index > 0 && functions.charAt(index - 1) != ',') return false;
+        int charAfter = index + function.length();
+        if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
+        return true;
     }
 
     /**
@@ -413,30 +403,52 @@
      *
      * {@hide}
      */
-    public static boolean isFunctionEnabled(String function) {
+    public boolean isFunctionEnabled(String function) {
+        return propertyContainsFunction("sys.usb.config", function);
+    }
+
+    /**
+     * Sets the primary USB function.
+     *
+     * @param function name of the USB function
+     *
+     * {@hide}
+     */
+    public void setPrimaryFunction(String function) {
         try {
-            FileInputStream stream = new FileInputStream(getFunctionEnableFile(function));
-            boolean enabled = (stream.read() == '1');
-            stream.close();
-            return enabled;
-        } catch (IOException e) {
-            return false;
+            mService.setPrimaryFunction(function);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in setPrimaryFunction", e);
         }
     }
 
     /**
-     * Enables or disables a USB function.
+     * Sets the default primary USB function.
+     *
+     * @param function name of the USB function
      *
      * {@hide}
      */
-    public static boolean setFunctionEnabled(String function, boolean enable) {
+    public void setDefaultFunction(String function) {
         try {
-            FileOutputStream stream = new FileOutputStream(getFunctionEnableFile(function));
-            stream.write(enable ? '1' : '0');
-            stream.close();
-            return true;
-        } catch (IOException e) {
-            return false;
+            mService.setDefaultFunction(function);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in setDefaultFunction", e);
+        }
+    }
+
+    /**
+     * Sets the file path for USB mass storage backing file.
+     *
+     * @param path backing file path
+     *
+     * {@hide}
+     */
+    public void setMassStorageBackingFile(String path) {
+        try {
+            mService.setMassStorageBackingFile(path);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in setDefaultFunction", e);
         }
     }
 }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 164c657..0421205 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -306,6 +306,8 @@
      * <p><strong>Do not</strong> invoke this method from a drawing method
      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
      * 
+     * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
+     * 
      * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface
      *         texture is not available or the width &lt;= 0 or the height &lt;= 0
      * 
@@ -328,6 +330,8 @@
      * <p><strong>Do not</strong> invoke this method from a drawing method
      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
      * 
+     * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
+     * 
      * @param width The width of the bitmap to create
      * @param height The height of the bitmap to create
      * 
@@ -354,6 +358,8 @@
      * <p><strong>Do not</strong> invoke this method from a drawing method
      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
      * 
+     * <p>If an error occurs, the bitmap is left unchanged.</p>
+     * 
      * @param bitmap The bitmap to copy the content of the surface texture into,
      *               cannot be null, all configurations are supported
      * 
@@ -447,5 +453,6 @@
         public void onSurfaceTextureDestroyed(SurfaceTexture surface);
     }
 
-    private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture, int width, int height);
+    private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture,
+            int width, int height);
 }
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index ba3ae58..afbedaf 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -4479,7 +4479,7 @@
                 ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
                 foundViews.clear();
 
-                View root = null;
+                View root;
                 if (accessibilityViewId != View.NO_ID) {
                     root = findViewByAccessibilityId(accessibilityViewId);
                 } else {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 9d8d361..290f90d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -96,6 +96,8 @@
     private LinearLayout mTitleLayout;
     private TextView mTitleView;
     private TextView mSubtitleView;
+    private View mTitleUpView;
+
     private Spinner mSpinner;
     private LinearLayout mListNavLayout;
     private ScrollingTabContainerView mTabScrollView;
@@ -152,6 +154,16 @@
         }
     };
 
+    private final OnClickListener mUpClickListener = new OnClickListener() {
+        public void onClick(View v) {
+            Context context = getContext();
+            if (context instanceof Activity) {
+                Activity activity = (Activity) context;
+                activity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
+            }
+        }
+    };
+
     public ActionBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -230,15 +242,7 @@
         a.recycle();
         
         mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
-        mHomeLayout.setOnClickListener(new OnClickListener() {
-            public void onClick(View v) {
-                Context context = getContext();
-                if (context instanceof Activity) {
-                    Activity activity = (Activity) context;
-                    activity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
-                }
-            }
-        });
+        mHomeLayout.setOnClickListener(mUpClickListener);
         mHomeLayout.setClickable(true);
         mHomeLayout.setFocusable(true);
     }
@@ -438,7 +442,8 @@
         }
 
         if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
-            final int vis = (options & ActionBar.DISPLAY_SHOW_HOME) != 0 ? VISIBLE : GONE;
+            final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
+            final int vis = showHome ? VISIBLE : GONE;
             mHomeLayout.setVisibility(vis);
 
             if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
@@ -458,6 +463,14 @@
                 }
             }
 
+            if ((flagsChanged &
+                    (ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME)) != 0) {
+                final boolean homeAsUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+                final boolean titleUp = homeAsUp && !showHome;
+                mTitleUpView.setVisibility(titleUp ? VISIBLE : GONE);
+                mTitleLayout.setEnabled(titleUp);
+            }
+
             if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
                 if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
                     addView(mCustomNavView);
@@ -641,6 +654,9 @@
         mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item, null);
         mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
         mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
+        mTitleUpView = (View) mTitleLayout.findViewById(R.id.up);
+
+        mTitleLayout.setOnClickListener(mUpClickListener);
 
         if (mTitleStyleRes != 0) {
             mTitleView.setTextAppearance(mContext, mTitleStyleRes);
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index fd49ae3..cbb110a 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -618,178 +618,20 @@
     }
 
     @Override
-    public boolean onTouchEvent(MotionEvent motionEvent) {
+    public boolean onTouchEvent(MotionEvent event) {
         if (!mInputEnabled || !isEnabled()) {
             return false;
         }
 
-        final float x = motionEvent.getX();
-        final float y = motionEvent.getY();
-        Cell hitCell;
-        switch(motionEvent.getAction()) {
+        switch(event.getAction()) {
             case MotionEvent.ACTION_DOWN:
-                resetPattern();
-                hitCell = detectAndAddHit(x, y);
-                if (hitCell != null && mOnPatternListener != null) {
-                    mPatternInProgress = true;
-                    mPatternDisplayMode = DisplayMode.Correct;
-                    mOnPatternListener.onPatternStart();
-                } else if (mOnPatternListener != null) {
-                    mPatternInProgress = false;
-                    mOnPatternListener.onPatternCleared();
-                }
-                if (hitCell != null) {
-                    final float startX = getCenterXForColumn(hitCell.column);
-                    final float startY = getCenterYForRow(hitCell.row);
-
-                    final float widthOffset = mSquareWidth / 2f;
-                    final float heightOffset = mSquareHeight / 2f;
-
-                    invalidate((int) (startX - widthOffset), (int) (startY - heightOffset),
-                            (int) (startX + widthOffset), (int) (startY + heightOffset));
-                }
-                mInProgressX = x;
-                mInProgressY = y;
-                if (PROFILE_DRAWING) {
-                    if (!mDrawingProfilingStarted) {
-                        Debug.startMethodTracing("LockPatternDrawing");
-                        mDrawingProfilingStarted = true;
-                    }
-                }
+                handleActionDown(event);
                 return true;
             case MotionEvent.ACTION_UP:
-                // report pattern detected
-                if (!mPattern.isEmpty() && mOnPatternListener != null) {
-                    mPatternInProgress = false;
-                    mOnPatternListener.onPatternDetected(mPattern);
-                    invalidate();
-                }
-                if (PROFILE_DRAWING) {
-                    if (mDrawingProfilingStarted) {
-                        Debug.stopMethodTracing();
-                        mDrawingProfilingStarted = false;
-                    }
-                }
+                handleActionUp(event);
                 return true;
             case MotionEvent.ACTION_MOVE:
-                final int patternSizePreHitDetect = mPattern.size();
-                hitCell = detectAndAddHit(x, y);
-                final int patternSize = mPattern.size();
-                if (hitCell != null && (mOnPatternListener != null) && (patternSize == 1)) {
-                    mPatternInProgress = true;
-                    mOnPatternListener.onPatternStart();
-                }
-                // note current x and y for rubber banding of in progress
-                // patterns
-                final float dx = Math.abs(x - mInProgressX);
-                final float dy = Math.abs(y - mInProgressY);
-                if (dx + dy > mSquareWidth * 0.01f) {
-                    float oldX = mInProgressX;
-                    float oldY = mInProgressY;
-
-                    mInProgressX = x;
-                    mInProgressY = y;
-
-                    if (mPatternInProgress && patternSize > 0) {
-                        final ArrayList<Cell> pattern = mPattern;
-                        final float radius = mSquareWidth * mDiameterFactor * 0.5f;
-
-                        final Cell lastCell = pattern.get(patternSize - 1);
-
-                        float startX = getCenterXForColumn(lastCell.column);
-                        float startY = getCenterYForRow(lastCell.row);
-
-                        float left;
-                        float top;
-                        float right;
-                        float bottom;
-
-                        final Rect invalidateRect = mInvalidate;
-
-                        if (startX < x) {
-                            left = startX;
-                            right = x;
-                        } else {
-                            left = x;
-                            right = startX;
-                        }
-
-                        if (startY < y) {
-                            top = startY;
-                            bottom = y;
-                        } else {
-                            top = y;
-                            bottom = startY;
-                        }
-
-                        // Invalidate between the pattern's last cell and the current location
-                        invalidateRect.set((int) (left - radius), (int) (top - radius),
-                                (int) (right + radius), (int) (bottom + radius));
-
-                        if (startX < oldX) {
-                            left = startX;
-                            right = oldX;
-                        } else {
-                            left = oldX;
-                            right = startX;
-                        }
-
-                        if (startY < oldY) {
-                            top = startY;
-                            bottom = oldY;
-                        } else {
-                            top = oldY;
-                            bottom = startY;
-                        }
-
-                        // Invalidate between the pattern's last cell and the previous location
-                        invalidateRect.union((int) (left - radius), (int) (top - radius),
-                                (int) (right + radius), (int) (bottom + radius));
-
-                        // Invalidate between the pattern's new cell and the pattern's previous cell
-                        if (hitCell != null) {
-                            startX = getCenterXForColumn(hitCell.column);
-                            startY = getCenterYForRow(hitCell.row);
-
-                            if (patternSize >= 2) {
-                                // (re-using hitcell for old cell)
-                                hitCell = pattern.get(patternSize - 1 - (patternSize - patternSizePreHitDetect));
-                                oldX = getCenterXForColumn(hitCell.column);
-                                oldY = getCenterYForRow(hitCell.row);
-
-                                if (startX < oldX) {
-                                    left = startX;
-                                    right = oldX;
-                                } else {
-                                    left = oldX;
-                                    right = startX;
-                                }
-
-                                if (startY < oldY) {
-                                    top = startY;
-                                    bottom = oldY;
-                                } else {
-                                    top = oldY;
-                                    bottom = startY;
-                                }
-                            } else {
-                                left = right = startX;
-                                top = bottom = startY;
-                            }
-
-                            final float widthOffset = mSquareWidth / 2f;
-                            final float heightOffset = mSquareHeight / 2f;
-
-                            invalidateRect.set((int) (left - widthOffset),
-                                    (int) (top - heightOffset), (int) (right + widthOffset),
-                                    (int) (bottom + heightOffset));
-                        }
-
-                        invalidate(invalidateRect);
-                    } else {
-                        invalidate();
-                    }
-                }
+                handleActionMove(event);
                 return true;
             case MotionEvent.ACTION_CANCEL:
                 resetPattern();
@@ -808,6 +650,181 @@
         return false;
     }
 
+    private void handleActionMove(MotionEvent event) {
+        // Handle all recent motion events so we don't skip any cells even when the device
+        // is busy...
+        final int historySize = event.getHistorySize();
+        for (int i = 0; i < historySize + 1; i++) {
+            final float x = i < historySize ? event.getHistoricalX(i) : event.getX();
+            final float y = i < historySize ? event.getHistoricalY(i) : event.getY();
+            final int patternSizePreHitDetect = mPattern.size();
+            Cell hitCell = detectAndAddHit(x, y);
+            final int patternSize = mPattern.size();
+            if (hitCell != null && (mOnPatternListener != null) && (patternSize == 1)) {
+                mPatternInProgress = true;
+                mOnPatternListener.onPatternStart();
+            }
+            // note current x and y for rubber banding of in progress patterns
+            final float dx = Math.abs(x - mInProgressX);
+            final float dy = Math.abs(y - mInProgressY);
+            if (dx + dy > mSquareWidth * 0.01f) {
+                float oldX = mInProgressX;
+                float oldY = mInProgressY;
+
+                mInProgressX = x;
+                mInProgressY = y;
+
+                if (mPatternInProgress && patternSize > 0) {
+                    final ArrayList<Cell> pattern = mPattern;
+                    final float radius = mSquareWidth * mDiameterFactor * 0.5f;
+
+                    final Cell lastCell = pattern.get(patternSize - 1);
+
+                    float startX = getCenterXForColumn(lastCell.column);
+                    float startY = getCenterYForRow(lastCell.row);
+
+                    float left;
+                    float top;
+                    float right;
+                    float bottom;
+
+                    final Rect invalidateRect = mInvalidate;
+
+                    if (startX < x) {
+                        left = startX;
+                        right = x;
+                    } else {
+                        left = x;
+                        right = startX;
+                    }
+
+                    if (startY < y) {
+                        top = startY;
+                        bottom = y;
+                    } else {
+                        top = y;
+                        bottom = startY;
+                    }
+
+                    // Invalidate between the pattern's last cell and the current location
+                    invalidateRect.set((int) (left - radius), (int) (top - radius),
+                            (int) (right + radius), (int) (bottom + radius));
+
+                    if (startX < oldX) {
+                        left = startX;
+                        right = oldX;
+                    } else {
+                        left = oldX;
+                        right = startX;
+                    }
+
+                    if (startY < oldY) {
+                        top = startY;
+                        bottom = oldY;
+                    } else {
+                        top = oldY;
+                        bottom = startY;
+                    }
+
+                    // Invalidate between the pattern's last cell and the previous location
+                    invalidateRect.union((int) (left - radius), (int) (top - radius),
+                            (int) (right + radius), (int) (bottom + radius));
+
+                    // Invalidate between the pattern's new cell and the pattern's previous cell
+                    if (hitCell != null) {
+                        startX = getCenterXForColumn(hitCell.column);
+                        startY = getCenterYForRow(hitCell.row);
+
+                        if (patternSize >= 2) {
+                            // (re-using hitcell for old cell)
+                            hitCell = pattern.get(patternSize - 1 - (patternSize - patternSizePreHitDetect));
+                            oldX = getCenterXForColumn(hitCell.column);
+                            oldY = getCenterYForRow(hitCell.row);
+
+                            if (startX < oldX) {
+                                left = startX;
+                                right = oldX;
+                            } else {
+                                left = oldX;
+                                right = startX;
+                            }
+
+                            if (startY < oldY) {
+                                top = startY;
+                                bottom = oldY;
+                            } else {
+                                top = oldY;
+                                bottom = startY;
+                            }
+                        } else {
+                            left = right = startX;
+                            top = bottom = startY;
+                        }
+
+                        final float widthOffset = mSquareWidth / 2f;
+                        final float heightOffset = mSquareHeight / 2f;
+
+                        invalidateRect.set((int) (left - widthOffset),
+                                (int) (top - heightOffset), (int) (right + widthOffset),
+                                (int) (bottom + heightOffset));
+                    }
+
+                    invalidate(invalidateRect);
+                } else {
+                    invalidate();
+                }
+            }
+        }
+    }
+
+    private void handleActionUp(MotionEvent event) {
+        // report pattern detected
+        if (!mPattern.isEmpty() && mOnPatternListener != null) {
+            mPatternInProgress = false;
+            mOnPatternListener.onPatternDetected(mPattern);
+            invalidate();
+        }
+        if (PROFILE_DRAWING) {
+            if (mDrawingProfilingStarted) {
+                Debug.stopMethodTracing();
+                mDrawingProfilingStarted = false;
+            }
+        }
+    }
+
+    private void handleActionDown(MotionEvent event) {
+        resetPattern();
+        final float x = event.getX();
+        final float y = event.getY();
+        final Cell hitCell = detectAndAddHit(x, y);
+        if (hitCell != null && mOnPatternListener != null) {
+            mPatternInProgress = true;
+            mPatternDisplayMode = DisplayMode.Correct;
+            mOnPatternListener.onPatternStart();
+        } else if (mOnPatternListener != null) {
+            mPatternInProgress = false;
+            mOnPatternListener.onPatternCleared();
+        }
+        if (hitCell != null) {
+            final float startX = getCenterXForColumn(hitCell.column);
+            final float startY = getCenterYForRow(hitCell.row);
+
+            final float widthOffset = mSquareWidth / 2f;
+            final float heightOffset = mSquareHeight / 2f;
+
+            invalidate((int) (startX - widthOffset), (int) (startY - heightOffset),
+                    (int) (startX + widthOffset), (int) (startY + heightOffset));
+        }
+        mInProgressX = x;
+        mInProgressY = y;
+        if (PROFILE_DRAWING) {
+            if (!mDrawingProfilingStarted) {
+                Debug.startMethodTracing("LockPatternDrawing");
+                mDrawingProfilingStarted = true;
+            }
+        }
+    }
+
     private float getCenterXForColumn(int column) {
         return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f;
     }
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
index d8b729d..e803b26 100644
--- a/core/res/res/layout/action_bar_title_item.xml
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -17,17 +17,32 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
-              android:orientation="vertical"
-              android:paddingRight="32dip" >
-    <TextView android:id="@+id/action_bar_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:ellipsize="end" />
-    <TextView android:id="@+id/action_bar_subtitle"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:ellipsize="end"
-        android:visibility="gone" />
+              android:orientation="horizontal"
+              android:paddingRight="16dip"
+              android:background="?android:attr/selectableItemBackground"
+              android:enabled="false">
+
+    <ImageView android:id="@android:id/up"
+               android:src="?android:attr/homeAsUpIndicator"
+               android:layout_gravity="center_vertical|left"
+               android:visibility="gone"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content" />
+
+    <LinearLayout android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="center_vertical|left"
+                  android:orientation="vertical">
+        <TextView android:id="@+id/action_bar_title"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:singleLine="true"
+                  android:ellipsize="end" />
+        <TextView android:id="@+id/action_bar_subtitle"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:singleLine="true"
+                  android:ellipsize="end"
+                  android:visibility="gone" />
+    </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_holo.xml b/core/res/res/layout/alert_dialog_holo.xml
index 1a3573e..2185467 100644
--- a/core/res/res/layout/alert_dialog_holo.xml
+++ b/core/res/res/layout/alert_dialog_holo.xml
@@ -82,7 +82,9 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:paddingLeft="16dip"
-                android:paddingRight="16dip" />
+                android:paddingRight="16dip"
+                android:paddingTop="8dip"
+                android:paddingBottom="8dip"/>
         </ScrollView>
     </LinearLayout>
 
diff --git a/core/res/res/layout/keyguard_screen_status_land.xml b/core/res/res/layout/keyguard_screen_status_land.xml
index 259a3af..8a02e1f 100644
--- a/core/res/res/layout/keyguard_screen_status_land.xml
+++ b/core/res/res/layout/keyguard_screen_status_land.xml
@@ -133,16 +133,4 @@
         android:textAppearance="?android:attr/textAppearanceMedium"
         />
 
-    <TextView
-        android:id="@+id/propertyOf"
-        android:lineSpacingExtra="8dip"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textSize="17sp"
-        android:layout_marginTop="20dip"
-        android:singleLine="false"
-        android:textColor="@color/lockscreen_owner_info"
-        android:visibility="gone"
-        />
 </LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_status_port.xml b/core/res/res/layout/keyguard_screen_status_port.xml
index 680c073..1e87fb3 100644
--- a/core/res/res/layout/keyguard_screen_status_port.xml
+++ b/core/res/res/layout/keyguard_screen_status_port.xml
@@ -130,16 +130,4 @@
         android:textAppearance="?android:attr/textAppearanceMedium"
         />
 
-    <TextView
-        android:id="@+id/propertyOf"
-        android:lineSpacingExtra="8dip"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="20dip"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textSize="17sp"
-        android:singleLine="false"
-        android:visibility="gone"
-        android:textColor="@color/lockscreen_owner_info"
-        />
 </LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 0132b6c..4ffa3405 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -63,10 +63,8 @@
 
     <LinearLayout
         android:orientation="horizontal"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="0dip"
-        android:layout_marginLeft="12dip"
         android:layout_gravity="right">
 
         <TextView
@@ -114,8 +112,8 @@
 
     <com.android.internal.widget.LockPatternView
         android:id="@+id/lockPattern"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_width="300dip"
+        android:layout_height="300dip"
         android:layout_rowWeight="1"
         android:layout_marginTop="8dip"
         android:layout_marginRight="8dip"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d9e7dac..b5f4084 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2608,6 +2608,11 @@
     <!-- USB_STORAGE_ERROR dialog  ok button-->
     <string name="dlg_ok">OK</string>
 
+    <!-- USB_PREFERENCES: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across.  This is the title -->
+    <string name="usb_preferences_notification_title">USB connected</string>
+    <!-- See USB_PREFERENCES. This is the message. -->
+    <string name="usb_preferece_notification_message">Select to configure USB file transfer.</string>
+
     <!-- External media format dialog strings -->
     <!-- This is the label for the activity, and should never be visible to the user. -->
     <!-- See EXTMEDIA_FORMAT.  EXTMEDIA_FORMAT_DIALOG:  After the user selects the notification, a dialog is shown asking if he wants to format the SD card.  This is the title. [CHAR LIMIT=20] -->
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 596781e..e64d8ac 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -74,7 +74,7 @@
 
 struct CacheLogger {
     CacheLogger() {
-        LOGD("Creating OpenGL renderer caches");
+        INIT_LOGD("Creating OpenGL renderer caches");
     }
 }; // struct CacheLogger
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 146e789..77e63d7 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -326,12 +326,17 @@
             return false;
         }
 
+        SkAutoLockPixels alp(*bitmap);
+
         GLuint texture;
         GLuint previousFbo;
 
         GLenum format;
         GLenum type;
 
+        GLenum error = GL_NO_ERROR;
+        bool status = false;
+
         switch (bitmap->config()) {
             case SkBitmap::kA8_Config:
                 format = GL_ALPHA;
@@ -352,10 +357,18 @@
                 break;
         }
 
+        float alpha = layer->alpha;
+        SkXfermode::Mode mode = layer->mode;
+
+        layer->mode = SkXfermode::kSrc_Mode;
+        layer->alpha = 255;
+        layer->fbo = fbo;
+
         glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
 
         glGenTextures(1, &texture);
+        if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
         glActiveTexture(GL_TEXTURE0);
         glBindTexture(GL_TEXTURE_2D, texture);
@@ -368,39 +381,48 @@
 
         glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(),
                 0, format, type, NULL);
+        if ((error = glGetError()) != GL_NO_ERROR) goto error;
+
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                 GL_TEXTURE_2D, texture, 0);
+        if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
-        glBindTexture(GL_TEXTURE_2D, layer->texture);
+        {
+            LayerRenderer renderer(layer);
+            renderer.setViewport(bitmap->width(), bitmap->height());
+            renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
+                    bitmap->width(), bitmap->height(), !layer->blend);
+            if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
-        float alpha = layer->alpha;
-        SkXfermode::Mode mode = layer->mode;
+            {
+                Rect bounds;
+                bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height());
+                renderer.drawTextureLayer(layer, bounds);
 
-        layer->mode = SkXfermode::kSrc_Mode;
-        layer->alpha = 255;
-        layer->fbo = fbo;
+                glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
+                        type, bitmap->getPixels());
 
-        LayerRenderer renderer(layer);
-        renderer.setViewport(bitmap->width(), bitmap->height());
-        renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
-                bitmap->width(), bitmap->height(), !layer->blend);
+                if ((error = glGetError()) != GL_NO_ERROR) goto error;
+            }
 
-        Rect bounds;
-        bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height());
-        renderer.drawTextureLayer(layer, bounds);
+            status = true;
+        }
 
-        SkAutoLockPixels alp(*bitmap);
-        glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels());
+error:
+#if DEBUG_OPENGL
+        if (error != GL_NO_ERROR) {
+            LOGD("GL error while copying layer into bitmap = 0x%x", error);
+        }
+#endif
 
         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-
         layer->mode = mode;
         layer->alpha = alpha;
         layer->fbo = 0;
         glDeleteTextures(1, &texture);
         caches.fboCache.put(fbo);
 
-        return true;
+        return status;
     }
     return false;
 }
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5343a05..88774c6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -151,7 +151,6 @@
     mSaveCount = 1;
 
     glViewport(0, 0, mWidth, mHeight);
-
     glDisable(GL_DITHER);
 
     glEnable(GL_SCISSOR_TEST);
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index c9e0f6f..4e271c7 100644
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -92,13 +92,18 @@
     };
     private static final String ID_WHERE = Files.FileColumns._ID + "=?";
     private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
-    private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
-    private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
+
+    private static final String STORAGE_WHERE = Files.FileColumns.STORAGE_ID + "=?";
+    private static final String FORMAT_WHERE = Files.FileColumns.PARENT + "=?";
+    private static final String PARENT_WHERE = Files.FileColumns.FORMAT + "=?";
+    private static final String STORAGE_FORMAT_WHERE = STORAGE_WHERE + " AND "
                                             + Files.FileColumns.FORMAT + "=?";
-    private static final String PARENT_STORAGE_WHERE = PARENT_WHERE + " AND "
-                                            + Files.FileColumns.STORAGE_ID + "=?";
-    private static final String PARENT_STORAGE_FORMAT_WHERE = PARENT_STORAGE_WHERE + " AND "
-                                            + Files.FileColumns.FORMAT + "=?";
+    private static final String STORAGE_PARENT_WHERE = STORAGE_WHERE + " AND "
+                                            + Files.FileColumns.PARENT + "=?";
+    private static final String FORMAT_PARENT_WHERE = FORMAT_WHERE + " AND "
+                                            + Files.FileColumns.PARENT + "=?";
+    private static final String STORAGE_FORMAT_PARENT_WHERE = STORAGE_FORMAT_WHERE + " AND "
+                                            + Files.FileColumns.PARENT + "=?";
 
     private final MediaScanner mMediaScanner;
 
@@ -249,26 +254,67 @@
     }
 
     private Cursor createObjectQuery(int storageID, int format, int parent) throws RemoteException {
-        if (storageID != 0) {
-            if (format != 0) {
-                return mMediaProvider.query(mObjectsUri, ID_PROJECTION,
-                        PARENT_STORAGE_FORMAT_WHERE,
-                        new String[] { Integer.toString(parent), Integer.toString(storageID),
-                                Integer.toString(format) }, null);
+        if (storageID == 0xFFFFFFFF) {
+            // query all stores
+            if (format == 0) {
+                // query all formats
+                if (parent == 0) {
+                    // query all objects
+                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, null, null, null);
+                }
+                if (parent == 0xFFFFFFFF) {
+                    // all objects in root of store
+                    parent = 0;
+                }
+                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, PARENT_WHERE,
+                        new String[] { Integer.toString(parent) }, null);
             } else {
-                return mMediaProvider.query(mObjectsUri, ID_PROJECTION,
-                        PARENT_STORAGE_WHERE, new String[]
-                                { Integer.toString(parent), Integer.toString(storageID) }, null);
+                // query specific format
+                if (parent == 0) {
+                    // query all objects
+                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_WHERE,
+                            new String[] { Integer.toString(format) }, null);
+                }
+                if (parent == 0xFFFFFFFF) {
+                    // all objects in root of store
+                    parent = 0;
+                }
+                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_PARENT_WHERE,
+                        new String[] { Integer.toString(format), Integer.toString(parent) }, null);
             }
         } else {
-            if (format != 0) {
-                return mMediaProvider.query(mObjectsUri, ID_PROJECTION,
-                            PARENT_FORMAT_WHERE,
-                            new String[] { Integer.toString(parent), Integer.toString(format) },
-                             null);
+            // query specific store
+            if (format == 0) {
+                // query all formats
+                if (parent == 0) {
+                    // query all objects
+                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_WHERE,
+                            new String[] { Integer.toString(storageID) }, null);
+                }
+                if (parent == 0xFFFFFFFF) {
+                    // all objects in root of store
+                    parent = 0;
+                }
+                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_PARENT_WHERE,
+                        new String[] { Integer.toString(storageID), Integer.toString(parent) },
+                        null);
             } else {
-                return mMediaProvider.query(mObjectsUri, ID_PROJECTION,
-                            PARENT_WHERE, new String[] { Integer.toString(parent) }, null);
+                // query specific format
+                if (parent == 0) {
+                    // query all objects
+                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_WHERE,
+                            new String[] {  Integer.toString(storageID), Integer.toString(format) },
+                            null);
+                }
+                if (parent == 0xFFFFFFFF) {
+                    // all objects in root of store
+                    parent = 0;
+                }
+                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_PARENT_WHERE,
+                        new String[] { Integer.toString(storageID),
+                                       Integer.toString(format),
+                                       Integer.toString(parent) },
+                        null);
             }
         }
     }
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 4a8fd3e..9ec73c4 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -533,12 +533,10 @@
     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
-                                                            // 0x00000000 for all objects?
+                                                            // 0x00000000 for all objects
 
     if (!hasStorage(storageID))
         return MTP_RESPONSE_INVALID_STORAGE_ID;
-    if (parent == 0xFFFFFFFF)
-        parent = 0;
 
     MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
     mData.putAUInt32(handles);
@@ -552,11 +550,9 @@
     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
-                                                            // 0x00000000 for all objects?
+                                                            // 0x00000000 for all objects
     if (!hasStorage(storageID))
         return MTP_RESPONSE_INVALID_STORAGE_ID;
-    if (parent == 0xFFFFFFFF)
-        parent = 0;
 
     int count = mDatabase->getNumObjects(storageID, format, parent);
     if (count >= 0) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 55f5280..6d8eab6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -25,6 +25,10 @@
             android:exported="true"
             />
 
+        <activity android:name=".usb.UsbPreferenceActivity"
+             android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+             android:excludeFromRecents="true">
+        </activity>
         <activity android:name=".usb.UsbStorageActivity"
                 android:excludeFromRecents="true">
         </activity>
diff --git a/packages/SystemUI/res/layout/usb_preference_buttons.xml b/packages/SystemUI/res/layout/usb_preference_buttons.xml
new file mode 100644
index 0000000..babe07e
--- /dev/null
+++ b/packages/SystemUI/res/layout/usb_preference_buttons.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<!-- Check box that is displayed in the activity resolver UI for the user
+     to make their selection the preferred activity. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingLeft="14dip"
+    android:paddingRight="15dip"
+    android:orientation="vertical">
+
+    <Button
+        android:id="@+id/mtp_ptp_button"
+        android:text="@string/use_ptp_button_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="true"
+        android:clickable="true" />
+
+    <Button
+        android:id="@+id/installer_cd_button"
+        android:text="@string/installer_cd_button_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="true"
+        android:clickable="true" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8945da5..86e0cd0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -156,4 +156,13 @@
 
     <!-- Compatibility mode help screen: body text. [CHAR LIMIT=150] -->
     <string name="compat_mode_help_body">When an app was designed for a smaller screen, a zoom control will appear by the clock.</string>
+
+    <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
+    <string name="usb_preference_title">USB file transfer options</string>
+    <!-- Label for the MTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+    <string name="use_mtp_button_title">Mount as a media player (MTP)</string>
+    <!-- Label for the PTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+    <string name="use_ptp_button_title">Mount as a camera (PTP)</string>
+    <!-- Label for the installer CD image option in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+    <string name="installer_cd_button_title">Install Android File Transfer application for Mac</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
new file mode 100644
index 0000000..3ed44e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
@@ -0,0 +1,91 @@
+/*

+ * Copyright (C) 2011 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 com.android.systemui.usb;

+

+import android.app.Activity;

+import android.app.AlertDialog;

+import android.content.Context;

+import android.content.DialogInterface;

+import android.hardware.usb.UsbManager;

+import android.os.Bundle;

+import android.view.LayoutInflater;

+import android.view.View;

+import android.util.Log;

+import android.widget.Button;

+

+import java.io.File;

+

+import com.android.systemui.R;

+

+public class UsbPreferenceActivity extends Activity implements View.OnClickListener  {

+

+    private static final String TAG = "UsbPreferenceActivity";

+

+    private UsbManager mUsbManager;

+    private String mCurrentFunction;

+    private String[] mFunctions;

+    private String mInstallerImagePath;

+    private Button mMtpPtpButton;

+    private Button mInstallerCdButton;

+    private boolean mPtpActive;

+

+    @Override

+    public void onCreate(Bundle icicle) {

+        super.onCreate(icicle);

+

+        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);

+

+        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);

+        dialogBuilder.setTitle(getString(R.string.usb_preference_title));

+

+        LayoutInflater inflater = (LayoutInflater)getSystemService(

+                Context.LAYOUT_INFLATER_SERVICE);

+        View buttonView = inflater.inflate(R.layout.usb_preference_buttons, null);

+        dialogBuilder.setView(buttonView);

+        mMtpPtpButton = (Button)buttonView.findViewById(R.id.mtp_ptp_button);

+        mInstallerCdButton = (Button)buttonView.findViewById(R.id.installer_cd_button);

+        mMtpPtpButton.setOnClickListener(this);

+        mInstallerCdButton.setOnClickListener(this);

+

+        mPtpActive = mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP);

+        if (mPtpActive) {

+            mMtpPtpButton.setText(R.string.use_mtp_button_title);

+        }

+

+        mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath);

+        if (!(new File(mInstallerImagePath)).exists()) {

+            mInstallerCdButton.setVisibility(View.GONE);

+        }

+

+        dialogBuilder.show();

+    }

+

+    public void onClick(View v) {

+        if (v.equals(mMtpPtpButton)) {

+            if (mPtpActive) {

+                mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MTP);

+            } else {

+                mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_PTP);

+            }

+        } else if (v.equals(mInstallerCdButton)) {

+            mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MASS_STORAGE);

+            mUsbManager.setMassStorageBackingFile(mInstallerImagePath);

+        }

+

+        finish();

+    }

+}

diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index c86f962..d3244ec 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -33,6 +33,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.hardware.usb.UsbManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Environment;
@@ -152,7 +153,6 @@
          * 600 series - Unsolicited broadcasts.
          */
         public static final int VolumeStateChange              = 605;
-        public static final int ShareAvailabilityChange        = 620;
         public static final int VolumeDiskInserted             = 630;
         public static final int VolumeDiskRemoved              = 631;
         public static final int VolumeBadRemoval               = 632;
@@ -167,6 +167,7 @@
     private String                                mExternalStoragePath;
     private PackageManagerService                 mPms;
     private boolean                               mUmsEnabling;
+    private boolean                               mUmsAvailable = false;
     // Used as a lock for methods that register/unregister listeners.
     final private ArrayList<MountServiceBinderListener> mListeners =
             new ArrayList<MountServiceBinderListener>();
@@ -525,6 +526,10 @@
                         }
                     }
                 }.start();
+            } else if (action.equals(UsbManager.ACTION_USB_STATE)) {
+                boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) &&
+                        intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false));
+                notifyShareAvailabilityChange(available);
             }
         }
     };
@@ -654,12 +659,6 @@
                     updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);
                 }
 
-                try {
-                    boolean avail = doGetShareMethodAvailable("ums");
-                    notifyShareAvailabilityChange("ums", avail);
-                } catch (Exception ex) {
-                    Slog.w(TAG, "Failed to get share availability");
-                }
                 /*
                  * Now that we've done our initialization, release
                  * the hounds!
@@ -694,13 +693,6 @@
             notifyVolumeStateChange(
                     cooked[2], cooked[3], Integer.parseInt(cooked[7]),
                             Integer.parseInt(cooked[10]));
-        } else if (code == VoldResponseCode.ShareAvailabilityChange) {
-            // FMT: NNN Share method <method> now <available|unavailable>
-            boolean avail = false;
-            if (cooked[5].equals("available")) {
-                avail = true;
-            }
-            notifyShareAvailabilityChange(cooked[3], avail);
         } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
                    (code == VoldResponseCode.VolumeDiskRemoved) ||
                    (code == VoldResponseCode.VolumeBadRemoval)) {
@@ -835,42 +827,6 @@
         }
     }
 
-    private boolean doGetShareMethodAvailable(String method) {
-        ArrayList<String> rsp;
-        try {
-            rsp = mConnector.doCommand("share status " + method);
-        } catch (NativeDaemonConnectorException ex) {
-            Slog.e(TAG, "Failed to determine whether share method " + method + " is available.");
-            return false;
-        }
-
-        for (String line : rsp) {
-            String[] tok = line.split(" ");
-            if (tok.length < 3) {
-                Slog.e(TAG, "Malformed response to share status " + method);
-                return false;
-            }
-
-            int code;
-            try {
-                code = Integer.parseInt(tok[0]);
-            } catch (NumberFormatException nfe) {
-                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
-                return false;
-            }
-            if (code == VoldResponseCode.ShareStatusResult) {
-                if (tok[2].equals("available"))
-                    return true;
-                return false;
-            } else {
-                Slog.e(TAG, String.format("Unexpected response code %d", code));
-                return false;
-            }
-        }
-        Slog.e(TAG, "Got an empty response");
-        return false;
-    }
-
     private int doMountVolume(String path) {
         int rc = StorageResultCode.OperationSucceeded;
 
@@ -1018,13 +974,9 @@
         return false;
     }
 
-    private void notifyShareAvailabilityChange(String method, final boolean avail) {
-        if (!method.equals("ums")) {
-           Slog.w(TAG, "Ignoring unsupported share method {" + method + "}");
-           return;
-        }
-
+    private void notifyShareAvailabilityChange(final boolean avail) {
         synchronized (mListeners) {
+            mUmsAvailable = avail;
             for (int i = mListeners.size() -1; i >= 0; i--) {
                 MountServiceBinderListener bl = mListeners.get(i);
                 try {
@@ -1189,8 +1141,13 @@
         // XXX: This will go away soon in favor of IMountServiceObserver
         mPms = (PackageManagerService) ServiceManager.getService("package");
 
-        mContext.registerReceiver(mBroadcastReceiver,
-                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+        // don't bother monitoring USB if mass storage is not supported on our primary volume
+        if (mPrimaryVolume != null && mPrimaryVolume.allowMassStorage()) {
+            filter.addAction(UsbManager.ACTION_USB_STATE);
+        }
+        mContext.registerReceiver(mBroadcastReceiver, filter, null, null);
 
         mHandlerThread = new HandlerThread("MountService");
         mHandlerThread.start();
@@ -1323,7 +1280,9 @@
         if (getUmsEnabling()) {
             return true;
         }
-        return doGetShareMethodAvailable("ums");
+        synchronized (mListeners) {
+            return mUmsAvailable;
+        }
     }
 
     public void setUsbMassStorageEnabled(boolean enable) {
@@ -1419,7 +1378,7 @@
         return doFormatVolume(path);
     }
 
-    public int []getStorageUsers(String path) {
+    public int[] getStorageUsers(String path) {
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
         waitForReady();
         try {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2769004..a23bacf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -406,8 +406,8 @@
             }
 
             try {
-                Slog.i(TAG, "USB Observer");
-                // Listen for USB changes
+                Slog.i(TAG, "USB Service");
+                // Manage USB host and device support
                 usb = new UsbService(context);
                 ServiceManager.addService(Context.USB_SERVICE, usb);
             } catch (Throwable e) {
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index ca8a184..b7f9d5c 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -19,7 +19,6 @@
 import android.app.PendingIntent;
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -33,10 +32,16 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.FileUtils;
 import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Parcelable;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
 import android.os.SystemProperties;
 import android.os.UEventObserver;
 import android.provider.Settings;
@@ -46,7 +51,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
-import java.io.FileReader;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -55,77 +60,110 @@
  * UsbDeviceManager manages USB state in device mode.
  */
 public class UsbDeviceManager {
+
     private static final String TAG = UsbDeviceManager.class.getSimpleName();
     private static final boolean LOG = false;
 
-    private static final String USB_CONNECTED_MATCH =
-            "DEVPATH=/devices/virtual/switch/usb_connected";
-    private static final String USB_CONFIGURATION_MATCH =
-            "DEVPATH=/devices/virtual/switch/usb_configuration";
-    private static final String USB_FUNCTIONS_MATCH =
-            "DEVPATH=/devices/virtual/usb_composite/";
-    private static final String USB_CONNECTED_PATH =
-            "/sys/class/switch/usb_connected/state";
-    private static final String USB_CONFIGURATION_PATH =
-            "/sys/class/switch/usb_configuration/state";
-    private static final String USB_COMPOSITE_CLASS_PATH =
-            "/sys/class/usb_composite";
+    private static final String USB_STATE_MATCH =
+            "DEVPATH=/devices/virtual/android_usb/android0";
+    private static final String ACCESSORY_START_MATCH =
+            "DEVPATH=/devices/virtual/misc/usb_accessory";
+    private static final String FUNCTIONS_PATH =
+            "/sys/class/android_usb/android0/functions";
+    private static final String STATE_PATH =
+            "/sys/class/android_usb/android0/state";
+    private static final String MASS_STORAGE_FILE_PATH =
+            "/sys/class/android_usb/f_mass_storage/lun/file";
 
     private static final int MSG_UPDATE_STATE = 0;
-    private static final int MSG_FUNCTION_ENABLED = 1;
-    private static final int MSG_FUNCTION_DISABLED = 2;
+    private static final int MSG_ENABLE_ADB = 1;
+    private static final int MSG_SET_PRIMARY_FUNCTION = 2;
+    private static final int MSG_SET_DEFAULT_FUNCTION = 3;
+    private static final int MSG_SYSTEM_READY = 4;
 
     // Delay for debouncing USB disconnects.
     // We often get rapid connect/disconnect events when enabling USB functions,
     // which need debouncing.
     private static final int UPDATE_DELAY = 1000;
 
-    // current connected and configuration state
-    private int mConnected;
-    private int mConfiguration;
-
-    // last broadcasted connected and configuration state
-    private int mLastConnected = -1;
-    private int mLastConfiguration = -1;
-
-    // lists of enabled and disabled USB functions
-    private final ArrayList<String> mEnabledFunctions = new ArrayList<String>();
-
+    private UsbHandler mHandler;
     private boolean mSystemReady;
 
-    private UsbAccessory mCurrentAccessory;
-    // USB functions that are enabled by default, to restore after exiting accessory mode
-    private final ArrayList<String> mDefaultFunctions = new ArrayList<String>();
-
     private final Context mContext;
-    ContentResolver mContentResolver;
-    private final Object mLock = new Object();
+    private final ContentResolver mContentResolver;
     private final UsbSettingsManager mSettingsManager;
     private NotificationManager mNotificationManager;
     private final boolean mHasUsbAccessory;
 
-    // for adb connected notifications
-    private boolean mAdbNotificationShown = false;
+    // for USB connected notification
+    private boolean mUsbNotificationShown;
+    private boolean mUseUsbNotification;
+    private Notification mUsbNotification;
+
+    // for adb connected notification
+    private boolean mAdbNotificationShown;
     private Notification mAdbNotification;
     private boolean mAdbEnabled;
 
+
     private class AdbSettingsObserver extends ContentObserver {
         public AdbSettingsObserver() {
             super(null);
         }
         @Override
         public void onChange(boolean selfChange) {
-            mAdbEnabled = (Settings.Secure.getInt(mContentResolver,
-                Settings.Secure.ADB_ENABLED, 0) > 0);
-            // setting this secure property will start or stop adbd
-           SystemProperties.set("persist.service.adb.enable", mAdbEnabled ? "1" : "0");
-           updateAdbNotification();
+            boolean enable = (Settings.Secure.getInt(mContentResolver,
+                    Settings.Secure.ADB_ENABLED, 0) > 0);
+            mHandler.sendMessage(MSG_ENABLE_ADB, enable);
         }
     }
 
-    private void updateAdbNotification() {
+    private void updateUsbNotification(boolean connected) {
+        if (mNotificationManager == null || !mUseUsbNotification) return;
+        if (connected) {
+            if (!mUsbNotificationShown) {
+                Resources r = mContext.getResources();
+                CharSequence title = r.getText(
+                        com.android.internal.R.string.usb_preferences_notification_title);
+                CharSequence message = r.getText(
+                        com.android.internal.R.string.usb_preferece_notification_message);
+
+                if (mUsbNotification == null) {
+                    mUsbNotification = new Notification();
+                    mUsbNotification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
+                    mUsbNotification.when = 0;
+                    mUsbNotification.flags = Notification.FLAG_ONGOING_EVENT;
+                    mUsbNotification.tickerText = title;
+                    mUsbNotification.defaults = 0; // please be quiet
+                    mUsbNotification.sound = null;
+                    mUsbNotification.vibrate = null;
+                }
+
+                Intent intent = new Intent();
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+                        Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                intent.setClassName("com.android.systemui",
+                        "com.android.systemui.usb.UsbPreferenceActivity");
+                PendingIntent pi = PendingIntent.getActivity(mContext, 0,
+                        intent, 0);
+
+                mUsbNotification.setLatestEventInfo(mContext, title, message, pi);
+
+                mUsbNotificationShown = true;
+                mNotificationManager.notify(
+                        com.android.internal.R.string.usb_preferences_notification_title,
+                        mUsbNotification);
+            }
+
+        } else if (mUsbNotificationShown) {
+            mUsbNotificationShown = false;
+            mNotificationManager.cancel(
+                    com.android.internal.R.string.usb_preferences_notification_title);
+        }
+    }
+
+    private void updateAdbNotification(boolean adbEnabled) {
         if (mNotificationManager == null) return;
-        boolean adbEnabled = mAdbEnabled && (mConnected == 1);
         if (adbEnabled) {
             if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
 
@@ -173,38 +211,6 @@
         }
     }
 
-    private final void readCurrentAccessoryLocked() {
-        if (mHasUsbAccessory) {
-            String[] strings = nativeGetAccessoryStrings();
-            if (strings != null) {
-                mCurrentAccessory = new UsbAccessory(strings);
-                Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
-                if (mSystemReady) {
-                    mSettingsManager.accessoryAttached(mCurrentAccessory);
-                }
-            } else {
-                Log.e(TAG, "nativeGetAccessoryStrings failed");
-            }
-        }
-    }
-
-    /*
-     * Handles USB function enable/disable events
-     */
-    private final void functionEnabledLocked(String function, boolean enabled) {
-        if (enabled) {
-            if (!mEnabledFunctions.contains(function)) {
-                mEnabledFunctions.add(function);
-            }
-
-            if (UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) {
-                readCurrentAccessoryLocked();
-            }
-        } else {
-            mEnabledFunctions.remove(function);
-        }
-    }
-
     /*
      * Listens for uevent messages from the kernel to monitor the USB state
      */
@@ -215,53 +221,13 @@
                 Slog.v(TAG, "USB UEVENT: " + event.toString());
             }
 
-            synchronized (mLock) {
-                String name = event.get("SWITCH_NAME");
-                String state = event.get("SWITCH_STATE");
-                if (name != null && state != null) {
-                    try {
-                        int intState = Integer.parseInt(state);
-                        if ("usb_connected".equals(name)) {
-                            mConnected = intState;
-                            // trigger an Intent broadcast
-                            if (mSystemReady) {
-                                // debounce disconnects to avoid problems bringing up USB tethering
-                                update(mConnected == 0);
-                            }
-                        } else if ("usb_configuration".equals(name)) {
-                            mConfiguration = intState;
-                            // trigger an Intent broadcast
-                            if (mSystemReady) {
-                                update(mConnected == 0);
-                            }
-                        }
-                    } catch (NumberFormatException e) {
-                        Slog.e(TAG, "Could not parse switch state from event " + event);
-                    }
-                } else {
-                    String function = event.get("FUNCTION");
-                    String enabledStr = event.get("ENABLED");
-                    if (function != null && enabledStr != null) {
-                        // Note: we do not broadcast a change when a function is enabled or disabled.
-                        // We just record the state change for the next broadcast.
-                        int what = ("1".equals(enabledStr) ?
-                                MSG_FUNCTION_ENABLED : MSG_FUNCTION_DISABLED);
-                        Message msg = Message.obtain(mHandler, what);
-                        msg.obj = function;
-                        mHandler.sendMessage(msg);
-                    }
-                }
-            }
-        }
-    };
-
-   private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            // handle accessories attached at boot time
-            synchronized (mLock) {
-                if (mCurrentAccessory != null) {
-                    mSettingsManager.accessoryAttached(mCurrentAccessory);
-                }
+            String state = event.get("USB_STATE");
+            String accessory = event.get("ACCESSORY");
+            if (state != null) {
+                mHandler.updateState(state);
+            } else if ("START".equals(accessory)) {
+                Slog.d(TAG, "got accessory start");
+                setPrimaryFunction(UsbManager.USB_FUNCTION_ACCESSORY);
             }
         }
     };
@@ -273,229 +239,378 @@
         PackageManager pm = mContext.getPackageManager();
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
 
-        synchronized (mLock) {
-            init();  // set initial status
-
-            // make sure the ADB_ENABLED setting value matches the secure property value
-            mAdbEnabled = "1".equals(SystemProperties.get("persist.service.adb.enable"));
-            Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED,
-                    mAdbEnabled ? 1 : 0);
-
-            // register observer to listen for settings changes
-            mContentResolver.registerContentObserver(
-                    Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
-                            false, new AdbSettingsObserver());
-
-            // Watch for USB configuration changes
-            if (mConfiguration >= 0) {
-                mUEventObserver.startObserving(USB_CONNECTED_MATCH);
-                mUEventObserver.startObserving(USB_CONFIGURATION_MATCH);
-                mUEventObserver.startObserving(USB_FUNCTIONS_MATCH);
+        // create a thread for our Handler
+        HandlerThread thread = new HandlerThread("UsbDeviceManager",
+                Process.THREAD_PRIORITY_BACKGROUND) {
+            protected void onLooperPrepared() {
+                mHandler = new UsbHandler();
             }
-        }
-    }
-
-    private final void init() {
-        char[] buffer = new char[1024];
-        boolean inAccessoryMode = false;
-
-        // Read initial USB state
-        mConfiguration = -1;
-        try {
-            FileReader file = new FileReader(USB_CONNECTED_PATH);
-            int len = file.read(buffer, 0, 1024);
-            file.close();
-            mConnected = Integer.valueOf((new String(buffer, 0, len)).trim());
-
-            file = new FileReader(USB_CONFIGURATION_PATH);
-            len = file.read(buffer, 0, 1024);
-            file.close();
-            mConfiguration = Integer.valueOf((new String(buffer, 0, len)).trim());
-
-        } catch (FileNotFoundException e) {
-            Slog.i(TAG, "This kernel does not have USB configuration switch support");
-        } catch (Exception e) {
-            Slog.e(TAG, "" , e);
-        }
-        if (mConfiguration < 0) {
-            // This may happen in the emulator or devices without USB device mode support
-            return;
-        }
-
-        // Read initial list of enabled and disabled functions (device mode)
-        try {
-            File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles();
-            for (int i = 0; i < files.length; i++) {
-                File file = new File(files[i], "enable");
-                FileReader reader = new FileReader(file);
-                int len = reader.read(buffer, 0, 1024);
-                reader.close();
-                int value = Integer.valueOf((new String(buffer, 0, len)).trim());
-                String functionName = files[i].getName();
-                if (value == 1) {
-                    mEnabledFunctions.add(functionName);
-                if (UsbManager.USB_FUNCTION_ACCESSORY.equals(functionName)) {
-                        // The USB accessory driver is on by default, but it might have been
-                        // enabled before the USB service has initialized.
-                        inAccessoryMode = true;
-                    } else if (!UsbManager.USB_FUNCTION_ADB.equals(functionName)) {
-                        // adb is enabled/disabled automatically by the adbd daemon,
-                        // so don't treat it as a default function.
-                        mDefaultFunctions.add(functionName);
-                    }
-                }
-            }
-        } catch (FileNotFoundException e) {
-            Slog.w(TAG, "This kernel does not have USB composite class support");
-        } catch (Exception e) {
-            Slog.e(TAG, "" , e);
-        }
-
-        // handle the case where an accessory switched the driver to accessory mode
-        // before the framework finished booting
-        if (inAccessoryMode) {
-            readCurrentAccessoryLocked();
-
-            // FIXME - if we booted in accessory mode, then we have no way to figure out
-            // which functions are enabled by default.
-            // For now, assume that MTP or mass storage are the only possibilities
-            if (!mEnabledFunctions.contains(UsbManager.USB_FUNCTION_MTP)) {
-                mDefaultFunctions.add(UsbManager.USB_FUNCTION_MTP);
-            } else if (!mEnabledFunctions.contains(UsbManager.USB_FUNCTION_MASS_STORAGE)) {
-                mDefaultFunctions.add(UsbManager.USB_FUNCTION_MASS_STORAGE);
-            }
-        }
+        };
+        thread.start();
     }
 
     public void systemReady() {
-        synchronized (mLock) {
-                mNotificationManager = (NotificationManager)
-                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        mSystemReady = true;
 
-            update(false);
-            if (mCurrentAccessory != null) {
-                Log.d(TAG, "accessoryAttached at systemReady");
-                // its still too early to handle accessories, so add a BOOT_COMPLETED receiver
-                // to handle this later.
-                mContext.registerReceiver(mBootCompletedReceiver,
-                        new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
-            }
-            mSystemReady = true;
+        mNotificationManager = (NotificationManager)
+                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+
+        // We do not show the USB notification if the primary volume supports mass storage.
+        // The legacy mass storage UI will be used instead.
+        boolean massStorageSupported = false;
+        StorageManager storageManager = (StorageManager)
+                mContext.getSystemService(Context.STORAGE_SERVICE);
+        StorageVolume[] volumes = storageManager.getVolumeList();
+        if (volumes.length > 0) {
+            massStorageSupported = volumes[0].allowMassStorage();
         }
+        mUseUsbNotification = !massStorageSupported;
+
+        // make sure the ADB_ENABLED setting value matches the current state
+        Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED, mAdbEnabled ? 1 : 0);
+
+        mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
     }
 
-    /*
-     * Sends a message to update the USB connected and configured state (device mode).
-     * If delayed is true, then we add a small delay in sending the message to debounce
-     * the USB connection when enabling USB tethering.
-     */
-    private final void update(boolean delayed) {
-        mHandler.removeMessages(MSG_UPDATE_STATE);
-        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATE, delayed ? UPDATE_DELAY : 0);
-    }
-
-    /* returns the currently attached USB accessory (device mode) */
-    public UsbAccessory getCurrentAccessory() {
-        return mCurrentAccessory;
-    }
-
-    /* opens the currently attached USB accessory (device mode) */
-    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
-        synchronized (mLock) {
-            if (mCurrentAccessory == null) {
-                throw new IllegalArgumentException("no accessory attached");
+     private static String addFunction(String functions, String function) {
+        if (!containsFunction(functions, function)) {
+            if (functions.length() > 0) {
+                functions += ",";
             }
-            if (!mCurrentAccessory.equals(accessory)) {
-                Log.e(TAG, accessory.toString() + " does not match current accessory "
-                        + mCurrentAccessory);
-                throw new IllegalArgumentException("accessory not attached");
-            }
-            mSettingsManager.checkPermission(mCurrentAccessory);
-            return nativeOpenAccessory();
+            functions += function;
         }
+        return functions;
     }
 
-    /*
-     * This handler is for deferred handling of events related to device mode and accessories.
-     */
-    private final Handler mHandler = new Handler() {
+    private static String removeFunction(String functions, String function) {
+        String[] split = functions.split(",");
+        for (int i = 0; i < split.length; i++) {
+            if (function.equals(split[i])) {
+                split[i] = null;
+            }
+        }
+        StringBuilder builder = new StringBuilder();
+         for (int i = 0; i < split.length; i++) {
+            String s = split[i];
+            if (s != null) {
+                if (builder.length() > 0) {
+                    builder.append(",");
+                }
+                builder.append(s);
+            }
+        }
+        return builder.toString();
+    }
 
-        @Override
-        public void handleMessage(Message msg) {
-            synchronized (mLock) {
-                switch (msg.what) {
-                    case MSG_UPDATE_STATE:
-                        if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) {
-                            updateAdbNotification();
-                            if (mConnected == 0) {
-                                if (UsbManager.isFunctionEnabled(
-                                            UsbManager.USB_FUNCTION_ACCESSORY)) {
-                                    // make sure accessory mode is off, and restore default functions
-                                    Log.d(TAG, "exited USB accessory mode");
-                                    if (!UsbManager.setFunctionEnabled
-                                            (UsbManager.USB_FUNCTION_ACCESSORY, false)) {
-                                        Log.e(TAG, "could not disable accessory function");
-                                    }
-                                    int count = mDefaultFunctions.size();
-                                    for (int i = 0; i < count; i++) {
-                                        String function = mDefaultFunctions.get(i);
-                                        if (!UsbManager.setFunctionEnabled(function, true)) {
-                                            Log.e(TAG, "could not reenable function " + function);
-                                        }
-                                    }
+    private static boolean containsFunction(String functions, String function) {
+        int index = functions.indexOf(function);
+        if (index < 0) return false;
+        if (index > 0 && functions.charAt(index - 1) != ',') return false;
+        int charAfter = index + function.length();
+        if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
+        return true;
+    }
 
-                                    if (mCurrentAccessory != null) {
-                                        mSettingsManager.accessoryDetached(mCurrentAccessory);
-                                        mCurrentAccessory = null;
-                                    }
-                                }
-                            }
+    private final class UsbHandler extends Handler {
 
-                            final ContentResolver cr = mContext.getContentResolver();
-                            if (Settings.Secure.getInt(cr,
-                                    Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
-                                Slog.i(TAG, "Device not provisioned, skipping USB broadcast");
-                                return;
-                            }
+        // current USB state
+        private boolean mConnected;
+        private boolean mConfigured;
+        private String mCurrentFunctions;
+        private String mDefaultFunctions;
+        private UsbAccessory mCurrentAccessory;
+        private boolean mDeferAccessoryAttached;
 
-                            mLastConnected = mConnected;
-                            mLastConfiguration = mConfiguration;
+        public UsbHandler() {
+            // Read initial USB state
+            try {
+                mCurrentFunctions = FileUtils.readTextFile(
+                        new File(FUNCTIONS_PATH), 0, null).trim();
+                mDefaultFunctions = mCurrentFunctions;
+                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
+                updateState(state);
 
-                            // send a sticky broadcast containing current USB state
-                            Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
-                            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-                            intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0);
-                            intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration);
-                            for (int i = 0; i < mEnabledFunctions.size(); i++) {
-                                intent.putExtra(mEnabledFunctions.get(i), true);
-                            }
-                            mContext.sendStickyBroadcast(intent);
-                        }
-                        break;
-                    case MSG_FUNCTION_ENABLED:
-                    case MSG_FUNCTION_DISABLED:
-                        functionEnabledLocked((String)msg.obj, msg.what == MSG_FUNCTION_ENABLED);
-                        break;
+                mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
+
+                // Upgrade step for previous versions that used persist.service.adb.enable
+                String value = SystemProperties.get("persist.service.adb.enable", "");
+                if (value.length() > 0) {
+                    char enable = value.charAt(0);
+                    if (enable == '1') {
+                        setAdbEnabled(true);
+                    } else if (enable == '0') {
+                        setAdbEnabled(false);
+                    }
+                    SystemProperties.set("persist.service.adb.enable", "");
+                }
+
+                // register observer to listen for settings changes
+                mContentResolver.registerContentObserver(
+                        Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
+                                false, new AdbSettingsObserver());
+
+                // Watch for USB configuration changes
+                mUEventObserver.startObserving(USB_STATE_MATCH);
+                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
+            } catch (Exception e) {
+                Slog.e(TAG, "Error initializing UsbHandler", e);
+            }
+        }
+
+        public void sendMessage(int what, boolean arg) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.arg1 = (arg ? 1 : 0);
+            sendMessage(m);
+        }
+
+        public void sendMessage(int what, Object arg) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.obj = arg;
+            sendMessage(m);
+        }
+
+        public void updateState(String state) {
+            int connected, configured;
+
+            if ("DISCONNECTED".equals(state)) {
+                connected = 0;
+                configured = 0;
+            } else if ("CONNECTED".equals(state)) {
+                connected = 1;
+                configured = 0;
+            } else if ("CONFIGURED".equals(state)) {
+                connected = 1;
+                configured = 1;
+            } else {
+                Slog.e(TAG, "unknown state " + state);
+                return;
+            }
+            removeMessages(MSG_UPDATE_STATE);
+            Message msg = Message.obtain(this, MSG_UPDATE_STATE);
+            msg.arg1 = connected;
+            msg.arg2 = configured;
+            // debounce disconnects to avoid problems bringing up USB tethering
+            sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
+        }
+
+        private boolean setUsbConfig(String config) {
+            // set the new configuration
+            SystemProperties.set("sys.usb.config", config);
+            // wait for the transition to complete.
+            // give up after 1 second.
+            for (int i = 0; i < 20; i++) {
+                // State transition is done when sys.usb.conf.done is set to the new configuration
+                if (config.equals(SystemProperties.get("sys.usb.state"))) return true;
+                try {
+                    // try again in 50ms
+                    Thread.sleep(50);
+                } catch (InterruptedException e) {
+                }
+            }
+            return false;
+        }
+
+        private void setCurrentFunctions(String functions) {
+            if (!mCurrentFunctions.equals(functions)) {
+                if (!setUsbConfig("none") || !setUsbConfig(functions)) {
+                    Log.e(TAG, "Failed to switch USB configuration to " + functions);
+                    // revert to previous configuration if we fail
+                    setUsbConfig(mCurrentFunctions);
+                } else {
+                    mCurrentFunctions = functions;
                 }
             }
         }
-    };
+
+        private void setAdbEnabled(boolean enable) {
+            if (enable != mAdbEnabled) {
+                mAdbEnabled = enable;
+                String functions;
+                if (enable) {
+                    functions = addFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
+                    mDefaultFunctions = addFunction(mDefaultFunctions,
+                            UsbManager.USB_FUNCTION_ADB);
+                } else {
+                    functions = removeFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
+                    mDefaultFunctions = removeFunction(mDefaultFunctions,
+                            UsbManager.USB_FUNCTION_ADB);
+                }
+                SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
+                setCurrentFunctions(functions);
+                updateAdbNotification(mAdbEnabled && mConnected);
+            }
+        }
+
+        private void setEnabledFunctions(String functionList) {
+            if (mAdbEnabled) {
+                functionList = addFunction(functionList, UsbManager.USB_FUNCTION_ADB);
+            } else {
+                functionList = removeFunction(functionList, UsbManager.USB_FUNCTION_ADB);
+            }
+            setCurrentFunctions(functionList);
+        }
+
+        private void updateCurrentAccessory() {
+            if (!mHasUsbAccessory) return;
+
+            if (mConfigured) {
+                String[] strings = nativeGetAccessoryStrings();
+                if (strings != null) {
+                    mCurrentAccessory = new UsbAccessory(strings);
+                    Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
+                    // defer accessoryAttached if system is not ready
+                    if (mSystemReady) {
+                        mSettingsManager.accessoryAttached(mCurrentAccessory);
+                    } else {
+                        mDeferAccessoryAttached = true;
+                    }
+                } else {
+                    Log.e(TAG, "nativeGetAccessoryStrings failed");
+                }
+            } else if (!mConnected) {
+                // make sure accessory mode is off
+                // and restore default functions
+                Log.d(TAG, "exited USB accessory mode");
+                setEnabledFunctions(mDefaultFunctions);
+
+                if (mCurrentAccessory != null) {
+                    if (mSystemReady) {
+                        mSettingsManager.accessoryDetached(mCurrentAccessory);
+                    }
+                    mCurrentAccessory = null;
+                }
+            }
+        }
+
+        private void updateUsbState() {
+            // send a sticky broadcast containing current USB state
+            Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+            intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
+            intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
+
+            if (mCurrentFunctions != null) {
+                String[] functions = mCurrentFunctions.split(",");
+                for (int i = 0; i < functions.length; i++) {
+                    intent.putExtra(functions[i], true);
+                }
+            }
+
+            mContext.sendStickyBroadcast(intent);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            String function;
+
+            switch (msg.what) {
+                case MSG_UPDATE_STATE:
+                    mConnected = (msg.arg1 == 1);
+                    mConfigured = (msg.arg2 == 1);
+                    updateUsbNotification(mConnected);
+                    updateAdbNotification(mAdbEnabled && mConnected);
+                    if (containsFunction(mCurrentFunctions,
+                            UsbManager.USB_FUNCTION_ACCESSORY)) {
+                        updateCurrentAccessory();
+                    }
+
+                    if (!mConnected) {
+                        // restore defaults when USB is disconnected
+                        setCurrentFunctions(mDefaultFunctions);
+                    }
+                    if (mSystemReady) {
+                        updateUsbState();
+                    }
+                    break;
+                case MSG_ENABLE_ADB:
+                    setAdbEnabled(msg.arg1 == 1);
+                    break;
+                case MSG_SET_PRIMARY_FUNCTION:
+                    function = (String)msg.obj;
+                    if (function == null) {
+                        function = mDefaultFunctions;
+                    }
+                    setEnabledFunctions(function);
+                    break;
+                case MSG_SET_DEFAULT_FUNCTION:
+                    function = (String)msg.obj;
+                    if (mAdbEnabled) {
+                        function = addFunction(function, UsbManager.USB_FUNCTION_ADB);
+                    }
+                    SystemProperties.set("persist.sys.usb.config", function);
+                    mDefaultFunctions = function;
+                    break;
+                case MSG_SYSTEM_READY:
+                    updateUsbNotification(mConnected);
+                    updateAdbNotification(mAdbEnabled && mConnected);
+                    updateUsbState();
+                    if (mCurrentAccessory != null && mDeferAccessoryAttached) {
+                        mSettingsManager.accessoryAttached(mCurrentAccessory);
+                    }
+                    break;
+            }
+        }
+
+        public UsbAccessory getCurrentAccessory() {
+            return mCurrentAccessory;
+        }
+
+        public void dump(FileDescriptor fd, PrintWriter pw) {
+            pw.println("  USB Device State:");
+            pw.println("    Current Functions: " + mCurrentFunctions);
+            pw.println("    Default Functions: " + mDefaultFunctions);
+            pw.println("    mConnected: " + mConnected);
+            pw.println("    mConfigured: " + mConfigured);
+            pw.println("    mCurrentAccessory: " + mCurrentAccessory);
+        }
+    }
+
+    /* returns the currently attached USB accessory */
+    public UsbAccessory getCurrentAccessory() {
+        return mHandler.getCurrentAccessory();
+    }
+
+    /* opens the currently attached USB accessory */
+        public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+            UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
+            if (currentAccessory == null) {
+                throw new IllegalArgumentException("no accessory attached");
+            }
+            if (!currentAccessory.equals(accessory)) {
+                String error = accessory.toString()
+                        + " does not match current accessory "
+                        + currentAccessory;
+                throw new IllegalArgumentException(error);
+            }
+            mSettingsManager.checkPermission(accessory);
+            return nativeOpenAccessory();
+        }
+
+    public void setPrimaryFunction(String function) {
+        mHandler.sendMessage(MSG_SET_PRIMARY_FUNCTION, function);
+    }
+
+    public void setDefaultFunction(String function) {
+        if (function == null) {
+            throw new NullPointerException();
+        }
+        mHandler.sendMessage(MSG_SET_DEFAULT_FUNCTION, function);
+    }
+
+    public void setMassStorageBackingFile(String path) {
+        if (path == null) path = "";
+        try {
+            FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path);
+        } catch (IOException e) {
+           Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH);
+        }
+    }
 
     public void dump(FileDescriptor fd, PrintWriter pw) {
-        synchronized (mLock) {
-            pw.println("  USB Device State:");
-            pw.print("    Enabled Functions: ");
-            for (int i = 0; i < mEnabledFunctions.size(); i++) {
-                pw.print(mEnabledFunctions.get(i) + " ");
-            }
-            pw.println("");
-            pw.print("    Default Functions: ");
-            for (int i = 0; i < mDefaultFunctions.size(); i++) {
-                pw.print(mDefaultFunctions.get(i) + " ");
-            }
-            pw.println("");
-            pw.println("    mConnected: " + mConnected + ", mConfiguration: " + mConfiguration);
-            pw.println("    mCurrentAccessory: " + mCurrentAccessory);
+        if (mHandler != null) {
+            mHandler.dump(fd, pw);
         }
     }
 
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 21e5997c..193638f 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -50,7 +50,7 @@
         if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
             mHostManager = new UsbHostManager(context, mSettingsManager);
         }
-        if (new File("/sys/class/usb_composite").exists()) {
+        if (new File("/sys/class/android_usb").exists()) {
             mDeviceManager = new UsbDeviceManager(context, mSettingsManager);
         }
     }
@@ -92,7 +92,7 @@
     /* opens the currently attached USB accessory (device mode) */
     public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
         if (mDeviceManager != null) {
-            return openAccessory(accessory);
+            return mDeviceManager.openAccessory(accessory);
         } else {
             return null;
         }
@@ -146,6 +146,33 @@
         mSettingsManager.clearDefaults(packageName);
     }
 
+    public void setPrimaryFunction(String function) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+        if (mDeviceManager != null) {
+            mDeviceManager.setPrimaryFunction(function);
+        } else {
+            throw new IllegalStateException("USB device mode not supported");
+        }
+    }
+
+    public void setDefaultFunction(String function) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+        if (mDeviceManager != null) {
+            mDeviceManager.setDefaultFunction(function);
+        } else {
+            throw new IllegalStateException("USB device mode not supported");
+        }
+    }
+
+    public void setMassStorageBackingFile(String path) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+        if (mDeviceManager != null) {
+            mDeviceManager.setMassStorageBackingFile(path);
+        } else {
+            throw new IllegalStateException("USB device mode not supported");
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index d5dcd4e..c650021 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -31,6 +31,15 @@
         android:hardwareAccelerated="true">
 
         <activity
+                android:name="GetBitmapActivity"
+                android:label="_GetBitmap">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <activity
                 android:name="SmallCircleActivity"
                 android:label="_SmallCircle">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java
new file mode 100644
index 0000000..2e23aaa
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011 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 com.android.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.os.Bundle;
+import android.os.Environment;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class GetBitmapActivity extends Activity implements TextureView.SurfaceTextureListener {
+    private Camera mCamera;
+    private TextureView mTextureView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FrameLayout content = new FrameLayout(this);
+
+        mTextureView = new TextureView(this);
+        mTextureView.setSurfaceTextureListener(this);
+
+        Button button = new Button(this);
+        button.setText("Copy bitmap to /sdcard/textureview.png");
+        button.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Bitmap b = mTextureView.getBitmap();
+                try {
+                    FileOutputStream out = new FileOutputStream(
+                            Environment.getExternalStorageDirectory() + "/textureview.png");
+                    try {
+                        b.compress(Bitmap.CompressFormat.PNG, 100, out);
+                    } finally {
+                        try {
+                            out.close();
+                        } catch (IOException e) {
+                            // Ignore
+                        }
+                    }
+                } catch (FileNotFoundException e) {
+                    // Ignore
+                }
+            }
+        });
+
+        content.addView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+        content.addView(button, new FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT,
+                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
+        setContentView(content);
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+        mCamera = Camera.open();
+
+        try {
+            mCamera.setPreviewTexture(surface);
+        } catch (IOException t) {
+            android.util.Log.e("TextureView", "Cannot set preview texture target!", t);
+        }
+
+        mCamera.startPreview();
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+        // Ignored, the Camera does all the work for us
+    }
+
+    @Override
+    public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        mCamera.stopPreview();
+        mCamera.release();
+    }
+}