Merge "API CHANGE: expose the backup-related ApplicationInfo flag masks"
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6849fd76..6d5686a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -227,6 +227,15 @@
             return true;
         }
 
+        case WILL_ACTIVITY_BE_VISIBLE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            boolean res = willActivityBeVisible(token);
+            reply.writeNoException();
+            reply.writeInt(res ? 1 : 0);
+            return true;
+        }
+
         case REGISTER_RECEIVER_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -1360,6 +1369,18 @@
         data.recycle();
         reply.recycle();
     }
+    public boolean willActivityBeVisible(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(WILL_ACTIVITY_BE_VISIBLE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean res = reply.readInt() != 0;
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
     public Intent registerReceiver(IApplicationThread caller,
             IIntentReceiver receiver,
             IntentFilter filter, String perm) throws RemoteException
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7b5b63e..35d1948 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3095,9 +3095,6 @@
 
                 r.paused = false;
                 r.stopped = false;
-                if (r.activity.mStartedActivity) {
-                    r.hideForNow = true;
-                }
                 r.state = null;
             } catch (Exception e) {
                 if (!mInstrumentation.onException(r.activity, e)) {
@@ -3132,7 +3129,15 @@
             // If the window hasn't yet been added to the window manager,
             // and this guy didn't finish itself or start another activity,
             // then go ahead and add the window.
-            if (r.window == null && !a.mFinished && !a.mStartedActivity) {
+            boolean willBeVisible = !a.mStartedActivity;
+            if (!willBeVisible) {
+                try {
+                    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
+                            a.getActivityToken());
+                } catch (RemoteException e) {
+                }
+            }
+            if (r.window == null && !a.mFinished && willBeVisible) {
                 r.window = r.activity.getWindow();
                 View decor = r.window.getDecorView();
                 decor.setVisibility(View.INVISIBLE);
@@ -3148,8 +3153,8 @@
 
             // If the window has already been added, but during resume
             // we started another activity, then don't yet make the
-            // window visisble.
-            } else if (a.mStartedActivity) {
+            // window visible.
+            } else if (!willBeVisible) {
                 if (localLOGV) Log.v(
                     TAG, "Launch " + r + " mStartedActivity set");
                 r.hideForNow = true;
@@ -3157,7 +3162,7 @@
 
             // The window is now visible if it has been added, we are not
             // simply finishing, and we are not starting another activity.
-            if (!r.activity.mFinished && !a.mStartedActivity
+            if (!r.activity.mFinished && willBeVisible
                     && r.activity.mDecor != null && !r.hideForNow) {
                 if (r.newConfig != null) {
                     if (DEBUG_CONFIGURATION) Log.v(TAG, "Resuming activity "
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3913ed5..14571de 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -97,6 +97,7 @@
     public boolean finishActivity(IBinder token, int code, Intent data)
             throws RemoteException;
     public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException;
+    public boolean willActivityBeVisible(IBinder token) throws RemoteException;
     public Intent registerReceiver(IApplicationThread caller,
             IIntentReceiver receiver, IntentFilter filter,
             String requiredPermission) throws RemoteException;
@@ -501,4 +502,5 @@
     int KILL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+102;
     int IS_USER_A_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+103;
     int START_ACTIVITY_AND_WAIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+104;
+    int WILL_ACTIVITY_BE_VISIBLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+105;
 }
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index 4b4cc05..84a57b5 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -51,31 +51,31 @@
  * The following code demonstrates an (ugly) custom screen layout. It has a list
  * with a green background, and an alternate red "no data" message.
  * </p>
- * 
+ *
  * <pre>
  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
  * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  *         android:orientation=&quot;vertical&quot;
- *         android:layout_width=&quot;match_parent&quot; 
+ *         android:layout_width=&quot;match_parent&quot;
  *         android:layout_height=&quot;match_parent&quot;
  *         android:paddingLeft=&quot;8dp&quot;
  *         android:paddingRight=&quot;8dp&quot;&gt;
- * 
+ *
  *     &lt;ListView android:id=&quot;@id/android:list&quot;
- *               android:layout_width=&quot;match_parent&quot; 
+ *               android:layout_width=&quot;match_parent&quot;
  *               android:layout_height=&quot;match_parent&quot;
  *               android:background=&quot;#00FF00&quot;
  *               android:layout_weight=&quot;1&quot;
  *               android:drawSelectorOnTop=&quot;false&quot;/&gt;
- * 
+ *
  *     &lt;TextView id=&quot;@id/android:empty&quot;
- *               android:layout_width=&quot;match_parent&quot; 
+ *               android:layout_width=&quot;match_parent&quot;
  *               android:layout_height=&quot;match_parent&quot;
  *               android:background=&quot;#FF0000&quot;
  *               android:text=&quot;No data&quot;/&gt;
  * &lt;/LinearLayout&gt;
  * </pre>
- * 
+ *
  * <p>
  * <strong>Row Layout</strong>
  * </p>
@@ -96,27 +96,27 @@
  * source for the resource two_line_list_item, which displays two data
  * fields,one above the other, for each list row.
  * </p>
- * 
+ *
  * <pre>
  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
  * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  *     android:layout_width=&quot;match_parent&quot;
  *     android:layout_height=&quot;wrap_content&quot;
  *     android:orientation=&quot;vertical&quot;&gt;
- * 
+ *
  *     &lt;TextView android:id=&quot;@+id/text1&quot;
  *         android:textSize=&quot;16sp&quot;
  *         android:textStyle=&quot;bold&quot;
  *         android:layout_width=&quot;match_parent&quot;
  *         android:layout_height=&quot;wrap_content&quot;/&gt;
- * 
+ *
  *     &lt;TextView android:id=&quot;@+id/text2&quot;
  *         android:textSize=&quot;16sp&quot;
  *         android:layout_width=&quot;match_parent&quot;
  *         android:layout_height=&quot;wrap_content&quot;/&gt;
  * &lt;/LinearLayout&gt;
  * </pre>
- * 
+ *
  * <p>
  * You must identify the data bound to each TextView object in this layout. The
  * syntax for this is discussed in the next section.
@@ -137,40 +137,40 @@
  * Contacts provider for all contacts, then binding the Name and Company fields
  * to a two line row layout in the activity's ListView.
  * </p>
- * 
+ *
  * <pre>
  * public class MyListAdapter extends ListActivity {
- * 
+ *
  *     &#064;Override
  *     protected void onCreate(Bundle savedInstanceState){
  *         super.onCreate(savedInstanceState);
- * 
+ *
  *         // We'll define a custom screen layout here (the one shown above), but
  *         // typically, you could just use the standard ListActivity layout.
  *         setContentView(R.layout.custom_list_activity_view);
- * 
+ *
  *         // Query for all people contacts using the {@link android.provider.Contacts.People} convenience class.
  *         // Put a managed wrapper around the retrieved cursor so we don't have to worry about
  *         // requerying or closing it as the activity changes state.
  *         mCursor = this.getContentResolver().query(People.CONTENT_URI, null, null, null, null);
  *         startManagingCursor(mCursor);
- * 
- *         // Now create a new list adapter bound to the cursor. 
+ *
+ *         // Now create a new list adapter bound to the cursor.
  *         // SimpleListAdapter is designed for binding to a Cursor.
  *         ListAdapter adapter = new SimpleCursorAdapter(
  *                 this, // Context.
- *                 android.R.layout.two_line_list_item,  // Specify the row template to use (here, two columns bound to the two retrieved cursor 
+ *                 android.R.layout.two_line_list_item,  // Specify the row template to use (here, two columns bound to the two retrieved cursor
  * rows).
  *                 mCursor,                                              // Pass in the cursor to bind to.
  *                 new String[] {People.NAME, People.COMPANY},           // Array of cursor columns to bind to.
  *                 new int[] {android.R.id.text1, android.R.id.text2});  // Parallel array of which template objects to bind to those columns.
- * 
+ *
  *         // Bind to our new adapter.
  *         setListAdapter(adapter);
  *     }
  * }
  * </pre>
- * 
+ *
  * @see #setListAdapter
  * @see android.widget.ListView
  */
@@ -194,13 +194,13 @@
             mList.focusableViewAvailable(mList);
         }
     };
-    
+
     /**
      * This method will be called when an item in the list is selected.
      * Subclasses should override. Subclasses can call
      * getListView().getItemAtPosition(position) if they need to access the
      * data associated with the selected item.
-     * 
+     *
      * @param l The ListView where the click happened
      * @param v The view that was clicked within the ListView
      * @param position The position of the view in the list
@@ -208,11 +208,11 @@
      */
     protected void onListItemClick(ListView l, View v, int position, long id) {
     }
-    
+
     /**
      * Ensures the list view has been created before Activity restores all
      * of the view states.
-     * 
+     *
      *@see Activity#onRestoreInstanceState(Bundle)
      */
     @Override
@@ -222,9 +222,18 @@
     }
 
     /**
+     * @see Activity#onDestroy()
+     */
+    @Override
+    protected void onDestroy() {
+        mHandler.removeCallbacks(mRequestFocus);
+        super.onDestroy();
+    }
+
+    /**
      * Updates the screen state (current list and other views) when the
      * content changes.
-     * 
+     *
      * @see Activity#onContentChanged()
      */
     @Override
@@ -262,7 +271,7 @@
     /**
      * Set the currently selected list item to the specified
      * position with the adapter's data
-     * 
+     *
      * @param position
      */
     public void setSelection(int position) {
@@ -290,7 +299,7 @@
         ensureList();
         return mList;
     }
-    
+
     /**
      * Get the ListAdapter associated with this activity's ListView.
      */
@@ -303,7 +312,7 @@
             return;
         }
         setContentView(com.android.internal.R.layout.list_content);
-        
+
     }
 
     private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
@@ -313,4 +322,3 @@
         }
     };
 }
-
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 17b0330..22e4325 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -359,7 +359,12 @@
             case Phone.APN_REQUEST_FAILED:
                 if (mPhoneService == null && mApnType == Phone.APN_TYPE_DEFAULT) {
                     // on startup we may try to talk to the phone before it's ready
-                    // just leave mEnabled as it is for the default apn.
+                    // since the phone will come up enabled, go with that.
+                    // TODO - this also comes up on telephony crash: if we think mobile data is
+                    // off and the telephony stuff crashes and has to restart it will come up
+                    // enabled (making a data connection).  We will then be out of sync.
+                    // A possible solution is a broadcast when telephony restarts.
+                    mEnabled = true;
                     return false;
                 }
                 // else fall through
diff --git a/core/java/android/pim/vcard/VCardEntryCommitter.java b/core/java/android/pim/vcard/VCardEntryCommitter.java
index 3cd64b0..2f99e4a 100644
--- a/core/java/android/pim/vcard/VCardEntryCommitter.java
+++ b/core/java/android/pim/vcard/VCardEntryCommitter.java
@@ -19,6 +19,8 @@
 import android.net.Uri;
 import android.util.Log;
 
+import java.util.ArrayList;
+
 /**
  * <P>
  * {@link VCardEntryHandler} implementation which commits the entry to ContentResolver.
@@ -35,7 +37,7 @@
 
     private final ContentResolver mContentResolver;
     private long mTimeToCommit;
-    private Uri mLastCreatedUri;
+    private ArrayList<Uri> mCreatedUris = new ArrayList<Uri>();
 
     public VCardEntryCommitter(ContentResolver resolver) {
         mContentResolver = resolver;
@@ -52,11 +54,21 @@
 
     public void onEntryCreated(final VCardEntry contactStruct) {
         long start = System.currentTimeMillis();
-        mLastCreatedUri = contactStruct.pushIntoContentResolver(mContentResolver);
+        mCreatedUris.add(contactStruct.pushIntoContentResolver(mContentResolver));
         mTimeToCommit += System.currentTimeMillis() - start;
     }
 
+    // TODO: Compatibility function to not break the build. Will be removed shortly
+    @Deprecated
     public Uri getLastCreatedUri() {
-        return mLastCreatedUri;
+        return mCreatedUris.size() == 0 ? null : mCreatedUris.get(mCreatedUris.size() - 1);
+    }
+
+    /**
+     * Returns the list of created Uris. This list should not be modified by the caller as it is
+     * not a clone.
+     */
+   public ArrayList<Uri> getCreatedUris() {
+        return mCreatedUris;
     }
 }
\ No newline at end of file
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index a5c85c1..4377a2b 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -363,7 +363,7 @@
                 str[i] = c.getString(0);
                 i++;
             }
-            c.deactivate();
+            c.close();
             return str;
         } catch (IllegalStateException e) {
             return new String[0];
@@ -402,7 +402,7 @@
                     if (!c.moveToNext()) break;
                 }
             }
-            c.deactivate();
+            c.close();
         } catch (IllegalStateException e) {
             Log.e(LOGTAG, "truncateHistory", e);
             return;
@@ -427,7 +427,7 @@
                 null
                 );
             boolean ret = c.moveToFirst();
-            c.deactivate();
+            c.close();
             return ret;
         } catch (IllegalStateException e) {
             return false;
@@ -462,7 +462,7 @@
                 null,
                 null);
             if (!c.moveToFirst()) {
-                c.deactivate();
+                c.close();
                 return;
             }
 
@@ -489,7 +489,7 @@
                     iconDb.releaseIconForPageUrl(url);
                 }
             } while (c.moveToNext());
-            c.deactivate();
+            c.close();
 
             if (!firstTime) {
                 ContentValues map = new ContentValues();
@@ -576,7 +576,7 @@
             } else {
                 cr.insert(SEARCHES_URI, map);
             }
-            c.deactivate();
+            c.close();
         } catch (IllegalStateException e) {
             Log.e(LOGTAG, "addSearchUrl", e);
             return;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index c06a1e2..40a408a 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -887,6 +887,25 @@
                 "as_vcard");
 
         /**
+         * Base {@link Uri} for referencing multiple {@link Contacts} entry,
+         * created by appending {@link #LOOKUP_KEY} using
+         * {@link Uri#withAppendedPath(Uri, String)}. The lookup keys have to be
+         * encoded and joined with the colon (":") seperator. The resulting string
+         * has to be encoded again. Provides
+         * {@link OpenableColumns} columns when queried, or returns the
+         * referenced contact formatted as a vCard when opened through
+         * {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
+         *
+         * This is private API because we do not have a well-defined way to
+         * specify several entities yet. The format of this Uri might change in the future
+         * or the Uri might be completely removed.
+         *
+         * @hide
+         */
+        public static final Uri CONTENT_MULTI_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
+                "as_multi_vcard");
+
+        /**
          * Builds a {@link #CONTENT_LOOKUP_URI} style {@link Uri} describing the
          * requested {@link Contacts} entry.
          *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 873e1a6f..503d8b8d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2900,6 +2900,15 @@
          */
         public static final String DROPBOX_TAG_PREFIX =
                 "dropbox:";
+        /**
+         * Lines of logcat to include with system crash/ANR/etc. reports,
+         * as a prefix of the dropbox tag of the report type.
+         * For example, "logcat_for_system_server_anr" controls the lines
+         * of logcat captured with system server ANR reports.  0 to disable.
+         * @hide
+         */
+        public static final String ERROR_LOGCAT_PREFIX =
+                "logcat_for_";
 
 
         /**
diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java
index f320701..2f429ff 100644
--- a/core/java/android/text/style/LeadingMarginSpan.java
+++ b/core/java/android/text/style/LeadingMarginSpan.java
@@ -68,7 +68,20 @@
                                   boolean first, Layout layout);
 
 
+    /**
+     * An extended version of {@link LeadingMarginSpan}, which allows
+     * the implementor to specify the number of lines of text to which
+     * this object is attached that the "first line of paragraph" margin
+     * width will be applied to.
+     */
     public interface LeadingMarginSpan2 extends LeadingMarginSpan, WrapTogetherSpan {
+        /**
+         * Returns the number of lines of text to which this object is
+         * attached that the "first line" margin will apply to.
+         * Note that if this returns N, the first N lines of the region,
+         * not the first N lines of each paragraph, will be given the
+         * special margin width.
+         */
         public int getLeadingMarginLineCount();
     };
 
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index d8b6d1f..ff34f4a 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.util.DisplayMetrics;
+import android.util.FloatMath;
 
 /**
  * Detects transformation gestures involving more than one pointer ("multitouch")
@@ -96,14 +97,16 @@
      * A convenience class to extend when you only want to listen for a subset
      * of scaling-related events. This implements all methods in
      * {@link OnScaleGestureListener} but does nothing.
-     * {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} and
-     * {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} return
+     * {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} returns
+     * {@code false} so that a subclass can retrieve the accumulated scale
+     * factor in an overridden onScaleEnd.
+     * {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} returns
      * {@code true}. 
      */
     public static class SimpleOnScaleGestureListener implements OnScaleGestureListener {
 
         public boolean onScale(ScaleGestureDetector detector) {
-            return true;
+            return false;
         }
 
         public boolean onScaleBegin(ScaleGestureDetector detector) {
@@ -115,10 +118,19 @@
         }
     }
 
+    /**
+     * This value is the threshold ratio between our previous combined pressure
+     * and the current combined pressure. We will only fire an onScale event if
+     * the computed ratio between the current and previous event pressures is
+     * greater than this value. When pressure decreases rapidly between events
+     * the position values can often be imprecise, as it usually indicates
+     * that the user is in the process of lifting a pointer off of the device.
+     * Its value was tuned experimentally.
+     */
     private static final float PRESSURE_THRESHOLD = 0.67f;
 
-    private Context mContext;
-    private OnScaleGestureListener mListener;
+    private final Context mContext;
+    private final OnScaleGestureListener mListener;
     private boolean mGestureInProgress;
 
     private MotionEvent mPrevEvent;
@@ -137,7 +149,7 @@
     private float mPrevPressure;
     private long mTimeDelta;
     
-    private float mEdgeSlop;
+    private final float mEdgeSlop;
     private float mRightSlopEdge;
     private float mBottomSlopEdge;
     private boolean mSloppyGesture;
@@ -410,7 +422,7 @@
         if (mCurrLen == -1) {
             final float cvx = mCurrFingerDiffX;
             final float cvy = mCurrFingerDiffY;
-            mCurrLen = (float)Math.sqrt(cvx*cvx + cvy*cvy);
+            mCurrLen = FloatMath.sqrt(cvx*cvx + cvy*cvy);
         }
         return mCurrLen;
     }
@@ -425,7 +437,7 @@
         if (mPrevLen == -1) {
             final float pvx = mPrevFingerDiffX;
             final float pvy = mPrevFingerDiffY;
-            mPrevLen = (float)Math.sqrt(pvx*pvx + pvy*pvy);
+            mPrevLen = FloatMath.sqrt(pvx*pvx + pvy*pvy);
         }
         return mPrevLen;
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 54c805f..e83b9b5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1775,6 +1775,7 @@
 
     private CheckForLongPress mPendingCheckForLongPress;
     private CheckForTap mPendingCheckForTap = null;
+    private PerformClick mPerformClick;
     
     private UnsetPressedState mUnsetPressedState;
 
@@ -4330,7 +4331,15 @@
 
                             // Only perform take click actions if we were in the pressed state
                             if (!focusTaken) {
-                                performClick();
+                                // Use a Runnable and post this rather than calling
+                                // performClick directly. This lets other visual state
+                                // of the view update before click actions start.
+                                if (mPerformClick == null) {
+                                    mPerformClick = new PerformClick();
+                                }
+                                if (!post(mPerformClick)) {
+                                    performClick();
+                                }
                             }
                         }
 
@@ -8965,6 +8974,12 @@
         }
     }
 
+    private final class PerformClick implements Runnable {
+        public void run() {
+            performClick();
+        }
+    }
+
     /**
      * Interface definition for a callback to be invoked when a key event is
      * dispatched to this view. The callback will be invoked before the key
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 390550f..c5a4e9e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -535,9 +535,10 @@
     static final int SET_ROOT_LAYER_MSG_ID              = 124;
     static final int RETURN_LABEL                       = 125;
     static final int FIND_AGAIN                         = 126;
+    static final int CENTER_FIT_RECT                    = 127;
 
     private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
-    private static final int LAST_PACKAGE_MSG_ID = FIND_AGAIN;
+    private static final int LAST_PACKAGE_MSG_ID = CENTER_FIT_RECT;
 
     static final String[] HandlerPrivateDebugString = {
         "REMEMBER_PASSWORD", //              = 1;
@@ -578,7 +579,8 @@
         "IMMEDIATE_REPAINT_MSG_ID", //       = 123;
         "SET_ROOT_LAYER_MSG_ID", //          = 124;
         "RETURN_LABEL", //                   = 125;
-        "FIND_AGAIN" //                      = 126;
+        "FIND_AGAIN", //                     = 126;
+        "CENTER_FIT_RECT" //                 = 127;
     };
 
     // If the site doesn't use the viewport meta tag to specify the viewport,
@@ -5737,49 +5739,50 @@
     }
 
     /*
-     * Maximize and center the view inside the WebView. If the zoom doesn't need
-     * to be changed, do an animated scroll to center it. If the zoom needs to
-     * be changed, find the zoom center and do a smooth zoom transition.
+     * Maximize and center the rectangle, specified in the document coordinate
+     * space, inside the WebView. If the zoom doesn't need to be changed, do an
+     * animated scroll to center it. If the zoom needs to be changed, find the
+     * zoom center and do a smooth zoom transition.
      */
-    private void centerPluginOnScreen(ViewManager.ChildView child) {
+    private void centerFitRect(int docX, int docY, int docWidth, int docHeight) {
         int viewWidth = getViewWidth();
         int viewHeight = getViewHeightWithTitle();
-        float scale = Math.min((float) viewWidth / child.width,
-                (float) viewHeight / child.height);
+        float scale = Math.min((float) viewWidth / docWidth, (float) viewHeight
+                / docHeight);
         if (scale < mMinZoomScale) {
             scale = mMinZoomScale;
         } else if (scale > mMaxZoomScale) {
             scale = mMaxZoomScale;
         }
         if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_INCREMENT) {
-            pinScrollTo(
-                    contentToViewX(child.x + child.width / 2) - viewWidth / 2,
-                    contentToViewY(child.y + child.height / 2) - viewHeight / 2,
+            pinScrollTo(contentToViewX(docX + docWidth / 2) - viewWidth / 2,
+                    contentToViewY(docY + docHeight / 2) - viewHeight / 2,
                     true, 0);
         } else {
-            int oldScreenX = contentToViewX(child.x) - mScrollX;
-            int newPluginX = (int) (child.x * scale);
-            int newPluginWidth = (int) (child.width * scale);
+            int oldScreenX = contentToViewX(docX) - mScrollX;
+            int rectViewX = (int) (docX * scale);
+            int rectViewWidth = (int) (docWidth * scale);
             int newMaxWidth = (int) (mContentWidth * scale);
-            int newScreenX = (viewWidth - newPluginWidth) / 2;
+            int newScreenX = (viewWidth - rectViewWidth) / 2;
             // pin the newX to the WebView
-            if (newScreenX > newPluginX) {
-                newScreenX = newPluginX;
-            } else if (newScreenX > (newMaxWidth - newPluginX - newPluginWidth)) {
-                newScreenX = viewWidth - (newMaxWidth - newPluginX);
+            if (newScreenX > rectViewX) {
+                newScreenX = rectViewX;
+            } else if (newScreenX > (newMaxWidth - rectViewX - rectViewWidth)) {
+                newScreenX = viewWidth - (newMaxWidth - rectViewX);
             }
             mZoomCenterX = (oldScreenX * scale - newScreenX * mActualScale)
                     / (scale - mActualScale);
-            int oldScreenY = contentToViewY(child.y) - mScrollY;
-            int newPluginY = (int) (child.y * scale) + getTitleHeight();
-            int newPluginHeight = (int) (child.height * scale);
-            int newMaxHeight = (int) (mContentHeight * scale) + getTitleHeight();
-            int newScreenY = (viewHeight - newPluginHeight) / 2;
+            int oldScreenY = contentToViewY(docY) - mScrollY;
+            int rectViewY = (int) (docY * scale) + getTitleHeight();
+            int rectViewHeight = (int) (docHeight * scale);
+            int newMaxHeight = (int) (mContentHeight * scale)
+                    + getTitleHeight();
+            int newScreenY = (viewHeight - rectViewHeight) / 2;
             // pin the newY to the WebView
-            if (newScreenY > newPluginY) {
-                newScreenY = newPluginY;
-            } else if (newScreenY > (newMaxHeight - newPluginY - newPluginHeight)) {
-                newScreenY = viewHeight - (newMaxHeight - newPluginY);
+            if (newScreenY > rectViewY) {
+                newScreenY = rectViewY;
+            } else if (newScreenY > (newMaxHeight - rectViewY - rectViewHeight)) {
+                newScreenY = viewHeight - (newMaxHeight - rectViewY);
             }
             mZoomCenterY = (oldScreenY * scale - newScreenY * mActualScale)
                     / (scale - mActualScale);
@@ -5825,7 +5828,7 @@
                         true);
             } else {
                 mInZoomOverview = false;
-                centerPluginOnScreen(plugin);
+                centerFitRect(plugin.x, plugin.y, plugin.width, plugin.height);
             }
             return;
         }
@@ -6642,6 +6645,12 @@
                     }
                     break;
 
+                case CENTER_FIT_RECT:
+                    Rect r = (Rect)msg.obj;
+                    mInZoomOverview = false;
+                    centerFitRect(r.left, r.top, r.width(), r.height());
+                    break;
+
                 default:
                     super.handleMessage(msg);
                     break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 27c7208..a274378 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2462,6 +2462,15 @@
         }
     }
 
+    // called by JNI
+    private void centerFitRect(int x, int y, int width, int height) {
+        if (mWebView == null) {
+            return;
+        }
+        mWebView.mPrivateHandler.obtainMessage(WebView.CENTER_FIT_RECT,
+                new Rect(x, y, x + width, y + height)).sendToTarget();
+    }
+
     private native void nativePause();
     private native void nativeResume();
     private native void nativeFreeMemory();
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index baed020..b3f8830 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -1,21 +1,12 @@
 page.title=Designing for Performance
 @jd:body
 
-<p>An Android application should be <em>efficient</em>. It will run on a mobile
-device with limited computing power and storage, a smaller screen, and
-constrained battery life. Battery life is one reason you might want to
-optimize your app even if it already seems to run "fast enough". Battery life
-is important to users, and Android's battery usage breakdown means users will
-know if your app is responsible draining their battery.</p>
-
-<p>One of the trickiest problems you'll face when optimizing Android apps is
-that it's not generally the case that you can say "device X is a factor F
-faster/slower than device Y".
-This is especially true if one of the devices is the emulator, or one of the
-devices has a JIT. If you want to know how your app performs on a given device,
-you need to test it on that device. Drawing conclusions from the emulator is
-particularly dangerous, as is attempting to compare JIT versus non-JIT
-performance: the performance <em>profiles</em> can differ wildly.</p>
+<p>An Android application will run on a mobile device with limited computing
+power and storage, and constrained battery life. Because of
+this, it should be <em>efficient</em>. Battery life is one reason you might
+want to optimize your app even if it already seems to run "fast enough".
+Battery life is important to users, and Android's battery usage breakdown
+means users will know if your app is responsible draining their battery.</p>
 
 <p>This document covers these topics: </p>
 <ul>
@@ -32,15 +23,18 @@
     <li><a href="#avoidfloat">Use Floating-Point Judiciously</a> </li>
     <li><a href="#library">Know And Use The Libraries</a></li>
     <li><a href="#native_methods">Use Native Methods Judiciously</a></li>
-    <li><a href="#samples">Some Sample Performance Numbers</a> </li>
     <li><a href="#closing_notes">Closing Notes</a></li>
 </ul>
 
+<p>Note that although this document primarily covers micro-optimizations,
+these will almost never make or break your software. Choosing the right
+algorithms and data structures should always be your priority, but is
+outside the scope of this document.</p>
+
 <a name="intro" id="intro"></a>
 <h2>Introduction</h2>
 
 <p>There are two basic rules for writing efficient code:</p>
-
 <ul>
     <li>Don't do work that you don't need to do.</li>
     <li>Don't allocate memory if you can avoid it.</li>
@@ -221,6 +215,16 @@
 
 </blockquote>
 
+<p>One of the trickiest problems you'll face when micro-optimizing Android
+apps is that the "if you will be running your program on ... multiple hardware
+platforms" clause above is always true. And it's not even generally the case
+that you can say "device X is a factor F faster/slower than device Y".
+This is especially true if one of the devices is the emulator, or one of the
+devices has a JIT. If you want to know how your app performs on a given device,
+you need to test it on that device. Drawing conclusions from the emulator is
+particularly dangerous, as is attempting to compare JIT versus non-JIT
+performance: the performance <em>profiles</em> can differ wildly.</p>
+
 <a name="object_creation"></a>
 <h2>Avoid Creating Objects</h2>
 
@@ -529,91 +533,36 @@
 <a name="native_methods" id="native_methods"></a>
 <h2>Use Native Methods Judiciously</h2>
 
-<p>Native code isn't necessarily more efficient than Java. There's a cost
-associated with the Java-native transition, it can be significantly more
-difficult to arrange timely collection of your native resources, and you
+<p>Native code isn't necessarily more efficient than Java. For one thing,
+there's a cost associated with the Java-native transition, and the JIT can't
+optimize across these boundaries. If you're allocating native resources (memory
+on the native heap, file descriptors, or whatever), it can be significantly
+more difficult to arrange timely collection of these resources. You also
 need to compile your code for each architecture you wish to run on (rather
-than rely on it having a JIT).</p>
+than rely on it having a JIT). You may even have to compile multiple versions
+for what you consider the same architecture: native code compiled for the ARM
+processor in the G1 can't take full advantage of the ARM in the Nexus One, and
+code compiled for the ARM in the Nexus One won't run on the ARM in the G1.</p>
+
+<p>Native code is primarily useful when you have an existing native codebase
+that you want to port to Android, not for "speeding up" parts of a Java app.</p>
 
 <p>(See also <em>Effective Java</em> item 54.)</p>
 
-<a name="samples" id="samples"></a>
-<h2>Some Sample Performance Numbers</h2>
-
-<p>To illustrate some of our ideas, here is a table listing the approximate
-run times for a few basic actions. Note that these values should NOT be taken
-as absolute numbers: they are a combination of CPU and wall clock time, and
-will change as improvements are made to the system. However, it is worth
-noting how these values apply relative to each other &mdash; for example,
-adding a member variable currently takes about four times as long as adding a
-local variable.</p>
-
-<table>
-    <tr>
-        <th>Action</th>
-        <th>Time</th>
-    </tr>
-    <tr>
-        <td>Add a local variable </td>
-        <td>1</td>
-    </tr>
-    <tr class="alt">
-        <td>Add a member variable </td>
-        <td>4</td>
-    </tr>
-    <tr>
-        <td>Call String.length()</td>
-        <td>5</td>
-    </tr>
-    <tr class="alt">
-        <td>Call empty static native method</td>
-        <td>5</td>
-    </tr>
-    <tr>
-        <td>Call empty static method </td>
-        <td>12</td>
-    </tr>
-    <tr class="alt">
-        <td>Call empty virtual method </td>
-        <td>12.5</td>
-    </tr>
-    <tr>
-        <td>Call empty interface method </td>
-        <td>15</td>
-    </tr>
-    <tr class="alt">
-        <td>Call Iterator:next() on a HashMap </td>
-        <td>165</td>
-    </tr>
-    <tr>
-        <td>Call put() on a HashMap</td>
-        <td>600</td>
-    </tr>
-    <tr class="alt">
-        <td>Inflate 1 View from XML </td>
-        <td>22,000</td>
-    </tr>
-    <tr>
-        <td>Inflate 1 LinearLayout containing 1 TextView </td>
-        <td>25,000</td>
-    </tr>
-    <tr class="alt">
-        <td>Inflate 1 LinearLayout containing 6 View objects </td>
-        <td>100,000</td>
-    </tr>
-    <tr>
-        <td>Inflate 1 LinearLayout containing 6 TextView objects </td>
-        <td>135,000</td>
-    </tr>
-    <tr class="alt">
-        <td>Launch an empty activity </td>
-        <td>3,000,000</td>
-    </tr>
-</table>
-
 <a name="closing_notes" id="closing_notes"></a>
 <h2>Closing Notes</h2>
 
 <p>One last thing: always measure. Before you start optimizing, make sure you
 have a problem. Make sure you can accurately measure your existing performance,
 or you won't be able to measure the benefit of the alternatives you try.</p>
+
+<p>Every claim made in this document is backed up by a benchmark. The source
+to these benchmarks can be found in the <a href="http://code.google.com/p/dalvik/source/browse/#svn/trunk/benchmarks">code.google.com "dalvik" project</a>.</p>
+
+<p>The benchmarks are built with the
+<a href="http://code.google.com/p/caliper/">Caliper</a> microbenchmarking
+framework for Java. Microbenchmarks are hard to get right, so Caliper goes out
+of its way to do the hard work for you, and even detect some cases where you're
+not measuring what you think you're measuring (because, say, the VM has
+managed to optimize all your code away). We highly recommend you use Caliper
+to run your own microbenchmarks.</p>
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index ff8757d..13cb460 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -19,6 +19,8 @@
 #include <utils/Log.h>
 
 #include <dlfcn.h>
+#include <linux/prctl.h>
+#include <sys/resource.h>
 
 #include "../include/OMX.h"
 #include "OMXRenderer.h"
@@ -29,6 +31,7 @@
 #include <binder/IMemory.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/VideoRenderer.h>
+#include <utils/threads.h>
 
 #include "OMXMaster.h"
 
@@ -91,6 +94,7 @@
 
 void OMX::CallbackDispatcher::post(const omx_message &msg) {
     Mutex::Autolock autoLock(mLock);
+
     mQueue.push_back(msg);
     mQueueChanged.signal();
 }
@@ -112,6 +116,9 @@
 }
 
 void OMX::CallbackDispatcher::threadEntry() {
+    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+    prctl(PR_SET_NAME, (unsigned long)"OMXCallbackDisp", 0, 0, 0);
+
     for (;;) {
         omx_message msg;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
index ddf5e0b..8489a67 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
@@ -49,7 +49,7 @@
     private final String TAG = "MediaMimeTest";
     private Context mContext;
     private final String MP3_FILE = "/sdcard/media_api/music/SHORTMP3.mp3";
-    private final String MEDIA_PLAYBACK_NAME = "com.android.music.MediaPlaybackActivity";
+    private final String MEDIA_PLAYBACK_NAME = "com.android.music.MediaPlaybackActivityStarter";
 
     public MediaMimeTest() {
         super("com.android.mediaframeworktest", MediaFrameworkTest.class);
@@ -77,7 +77,7 @@
         assertMediaPlaybackActivityHandles("audio/mp3");
     }
 
-    @MediumTest
+    @Suppress
     // Checks the MediaPlaybackActivity handles audio/*.
     public void testCheckMediaPlaybackHandlesAudio() throws Exception {
         assertMediaPlaybackActivityHandles("audio/*");
@@ -86,7 +86,7 @@
     // TODO: temporarily remove from medium suite because it hangs whole suite 
     // @MediumTest
     // Checks the MediaPlaybackActivity handles application/itunes. Some servers
-    // set the Content-type header to application/iTunes (with capital T, but
+    // set the Content-type hadb ieader to application/iTunes (with capital T, but
     // the download manager downcasts it) for their MP3 podcasts. This is non
     // standard but we try to support it anyway.
     // See bug 1401491
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index a3bbb74..8202efd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -395,10 +395,10 @@
         Thread.sleep(10000);
         mEndPid = getMediaserverPid();
         int memDiff = mEndMemory - startMemory;
-        if (memDiff < 0)
+        if (memDiff < 0) {
             memDiff = 0;
-        else
-            output.write("The total diff = " + memDiff);
+        }
+        output.write("The total diff = " + memDiff);
         output.write("\n\n");
         // mediaserver crash
         if (startPid != mEndPid) {
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index fa25fa9..9407bd5 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -1488,7 +1488,7 @@
         height = cbSurface.height - y;
 
     int err = copyPixels(c,
-            surface, xoffset, yoffset,
+            txSurface, xoffset, yoffset,
             cbSurface, x, y, width, height);
     if (err) {
         ogles_error(c, err);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index fc20d96..81b8d40 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -81,8 +81,6 @@
      */
     private List mNetRequestersPids[];
 
-    private WifiWatchdogService mWifiWatchdogService;
-
     // priority order of the nettrackers
     // (excluding dynamically set mNetworkPreference)
     // TODO - move mNetworkTypePreference into this
@@ -298,11 +296,10 @@
                 WifiStateTracker wst = new WifiStateTracker(context, mHandler);
                 WifiService wifiService = new WifiService(context, wst);
                 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
+                wifiService.startWifi();
                 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
                 wst.startMonitoring();
 
-                // Constructing this starts it too
-                mWifiWatchdogService = new WifiWatchdogService(context, wst);
                 break;
             case ConnectivityManager.TYPE_MOBILE:
                 mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 248f579..97a4329 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -124,6 +124,7 @@
 
     private INetworkManagementService nwService;
     ConnectivityManager mCm;
+    private WifiWatchdogService mWifiWatchdogService = null;
     private String[] mWifiRegexs;
 
     /**
@@ -217,8 +218,6 @@
 
         mWifiStateTracker.setWifiState(WIFI_STATE_DISABLED);
         mWifiApState = WIFI_AP_STATE_DISABLED;
-        boolean wifiEnabled = getPersistedWifiEnabled();
-        boolean wifiAPEnabled = wifiEnabled ? false : getPersistedWifiApEnabled();
 
         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
         Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
@@ -240,9 +239,6 @@
                 }
         );
 
-        Slog.i(TAG, "WifiService starting up with Wi-Fi " +
-                (wifiEnabled ? "enabled" : "disabled"));
-
         mContext.registerReceiver(
                 new BroadcastReceiver() {
                     @Override
@@ -267,7 +263,17 @@
 
                 }
             },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+    }
 
+    /**
+     * Check if Wi-Fi needs to be enabled and start
+     * if needed
+     */
+    public void startWifi() {
+        boolean wifiEnabled = getPersistedWifiEnabled();
+        boolean wifiAPEnabled = wifiEnabled ? false : getPersistedWifiApEnabled();
+        Slog.i(TAG, "WifiService starting up with Wi-Fi " +
+                (wifiEnabled ? "enabled" : "disabled"));
         setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
         setWifiApEnabledBlocking(wifiAPEnabled, true, Process.myUid(), null);
     }
@@ -446,6 +452,7 @@
 
             registerForBroadcasts();
             mWifiStateTracker.startEventLoop();
+
         } else {
 
             mContext.unregisterReceiver(mReceiver);
@@ -1803,6 +1810,9 @@
             switch (msg.what) {
 
                 case MESSAGE_ENABLE_WIFI:
+                    if (mWifiWatchdogService == null) {
+                        mWifiWatchdogService = new WifiWatchdogService(mContext, mWifiStateTracker);
+                    }
                     setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
                     sWakeLock.release();
                     break;
@@ -1821,6 +1831,10 @@
                     // a non-zero msg.arg1 value means the "enabled" setting
                     // should be persisted
                     setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2);
+                    if (mWifiWatchdogService != null) {
+                        mWifiWatchdogService.quit();
+                        mWifiWatchdogService = null;
+                    }
                     sWakeLock.release();
                     break;
 
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index e50b317..e2c523d 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -89,6 +89,8 @@
      */
     private WifiWatchdogHandler mHandler;
 
+    private ContentObserver mContentObserver;
+
     /**
      * The current watchdog state. Only written from the main thread!
      */
@@ -132,7 +134,7 @@
         ContentResolver contentResolver = mContext.getContentResolver();
         contentResolver.registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON), false,
-                new ContentObserver(mHandler) {
+                mContentObserver = new ContentObserver(mHandler) {
             @Override
             public void onChange(boolean selfChange) {
                 if (isWatchdogEnabled()) {
@@ -272,6 +274,16 @@
     }
 
     /**
+     * Unregister broadcasts and quit the watchdog thread
+     */
+    public void quit() {
+        unregisterForWifiBroadcasts();
+        mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+        mHandler.removeAllActions();
+        mHandler.getLooper().quit();
+    }
+
+    /**
      * Waits for the main watchdog thread to create the handler.
      */
     private void waitForHandlerCreation() {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8866bbd..a437d95 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -111,6 +111,7 @@
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.lang.IllegalStateException;
 import java.lang.ref.WeakReference;
@@ -3515,7 +3516,7 @@
             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                     + " in new task " + r.task);
             newTask = true;
-            addRecentTask(r.task);
+            addRecentTaskLocked(r.task);
             
         } else if (sourceRecord != null) {
             if (!addingToTask &&
@@ -3890,7 +3891,7 @@
         }
     }
 
-    private final void addRecentTask(TaskRecord task) {
+    private final void addRecentTaskLocked(TaskRecord task) {
         // Remove any existing entries that are the same kind of task.
         int N = mRecentTasks.size();
         for (int i=0; i<N; i++) {
@@ -4267,6 +4268,22 @@
         }
     }
 
+    public boolean willActivityBeVisible(IBinder token) {
+        synchronized(this) {
+            int i;
+            for (i=mHistory.size()-1; i>=0; i--) {
+                HistoryRecord r = (HistoryRecord)mHistory.get(i);
+                if (r == token) {
+                    return true;
+                }
+                if (r.fullscreen && !r.finishing) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+    
     public void overridePendingTransition(IBinder token, String packageName,
             int enterAnim, int exitAnim) {
         synchronized(this) {
@@ -4922,9 +4939,11 @@
                 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
                         Uri.fromParts("package", packageName, null));
                 intent.putExtra(Intent.EXTRA_UID, pkgUid);
-                broadcastIntentLocked(null, null, intent,
-                        null, null, 0, null, null, null,
-                        false, false, MY_PID, Process.SYSTEM_UID);
+                synchronized (this) {
+                    broadcastIntentLocked(null, null, intent,
+                            null, null, 0, null, null, null,
+                            false, false, MY_PID, Process.SYSTEM_UID);
+                }
             } catch (RemoteException e) {
             }
         } finally {
@@ -6984,7 +7003,7 @@
                             taskTopI = -1;
                         }
                         replyChainEnd = -1;
-                        addRecentTask(target.task);
+                        addRecentTaskLocked(target.task);
                     } else if (forceReset || finishOnTaskLaunch
                             || clearWhenTaskReset) {
                         // If the activity should just be removed -- either
@@ -7206,7 +7225,7 @@
                 moved.add(0, r);
                 top--;
                 if (first) {
-                    addRecentTask(r.task);
+                    addRecentTaskLocked(r.task);
                     first = false;
                 }
             }
@@ -7231,11 +7250,11 @@
             mWindowManager.validateAppTokens(mHistory);
         }
 
-        finishTaskMove(task);
+        finishTaskMoveLocked(task);
         EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
     }
 
-    private final void finishTaskMove(int task) {
+    private final void finishTaskMoveLocked(int task) {
         resumeTopActivityLocked(null);
     }
 
@@ -7353,7 +7372,7 @@
             mWindowManager.validateAppTokens(mHistory);
         }
 
-        finishTaskMove(task);
+        finishTaskMoveLocked(task);
         return true;
     }
 
@@ -7985,19 +8004,24 @@
     }
 
     public static final void installSystemProviders() {
-        ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
-        List providers = mSelf.generateApplicationProvidersLocked(app);
-        if (providers != null) {
-            for (int i=providers.size()-1; i>=0; i--) {
-                ProviderInfo pi = (ProviderInfo)providers.get(i);
-                if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
-                    Slog.w(TAG, "Not installing system proc provider " + pi.name
-                            + ": not system .apk");
-                    providers.remove(i);
+        List providers;
+        synchronized (mSelf) {
+            ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
+            providers = mSelf.generateApplicationProvidersLocked(app);
+            if (providers != null) {
+                for (int i=providers.size()-1; i>=0; i--) {
+                    ProviderInfo pi = (ProviderInfo)providers.get(i);
+                    if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+                        Slog.w(TAG, "Not installing system proc provider " + pi.name
+                                + ": not system .apk");
+                        providers.remove(i);
+                    }
                 }
             }
         }
-        mSystemThread.installSystemProviders(providers);
+        if (providers != null) {
+            mSystemThread.installSystemProviders(providers);
+        }
     }
 
     // =========================================================
@@ -8280,11 +8304,15 @@
     }
     
     public void registerActivityWatcher(IActivityWatcher watcher) {
-        mWatchers.register(watcher);
+        synchronized (this) {
+            mWatchers.register(watcher);
+        }
     }
 
     public void unregisterActivityWatcher(IActivityWatcher watcher) {
-        mWatchers.unregister(watcher);
+        synchronized (this) {
+            mWatchers.unregister(watcher);
+        }
     }
 
     public final void enterSafeMode() {
@@ -8960,77 +8988,122 @@
      * @param crashInfo giving an application stack trace, null if absent
      */
     public void addErrorToDropBox(String eventType,
-            ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
-            String subject, String report, File logFile,
-            ApplicationErrorReport.CrashInfo crashInfo) {
+            ProcessRecord process, HistoryRecord activity, HistoryRecord parent, String subject,
+            final String report, final File logFile,
+            final ApplicationErrorReport.CrashInfo crashInfo) {
         // NOTE -- this must never acquire the ActivityManagerService lock,
         // otherwise the watchdog may be prevented from resetting the system.
 
-        String dropboxTag;
+        String prefix;
         if (process == null || process.pid == MY_PID) {
-            dropboxTag = "system_server_" + eventType;
+            prefix = "system_server_";
         } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-            dropboxTag = "system_app_" + eventType;
+            prefix = "system_app_";
         } else {
-            dropboxTag = "data_app_" + eventType;
+            prefix = "data_app_";
         }
 
-        DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
-        if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
-            StringBuilder sb = new StringBuilder(1024);
-            if (process == null || process.pid == MY_PID) {
-                sb.append("Process: system_server\n");
-            } else {
-                sb.append("Process: ").append(process.processName).append("\n");
-            }
-            if (process != null) {
-                int flags = process.info.flags;
-                IPackageManager pm = ActivityThread.getPackageManager();
-                sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
-                for (String pkg : process.pkgList) {
-                    sb.append("Package: ").append(pkg);
-                    try {
-                        PackageInfo pi = pm.getPackageInfo(pkg, 0);
-                        if (pi != null) {
-                            sb.append(" v").append(pi.versionCode);
-                            if (pi.versionName != null) {
-                                sb.append(" (").append(pi.versionName).append(")");
-                            }
-                        }
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Error getting package info: " + pkg, e);
-                    }
-                    sb.append("\n");
-                }
-            }
-            if (activity != null) {
-                sb.append("Activity: ").append(activity.shortComponentName).append("\n");
-            }
-            if (parent != null && parent.app != null && parent.app.pid != process.pid) {
-                sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
-            }
-            if (parent != null && parent != activity) {
-                sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
-            }
-            if (subject != null) {
-                sb.append("Subject: ").append(subject).append("\n");
-            }
-            sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
-            sb.append("\n");
-            if (report != null) {
-                sb.append(report);
-            }
-            if (logFile != null) {
+        final String dropboxTag = prefix + eventType;
+        final DropBoxManager dbox = (DropBoxManager)
+                mContext.getSystemService(Context.DROPBOX_SERVICE);
+
+        // Exit early if the dropbox isn't configured to accept this report type.
+        if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
+
+        final StringBuilder sb = new StringBuilder(1024);
+        if (process == null || process.pid == MY_PID) {
+            sb.append("Process: system_server\n");
+        } else {
+            sb.append("Process: ").append(process.processName).append("\n");
+        }
+        if (process != null) {
+            int flags = process.info.flags;
+            IPackageManager pm = ActivityThread.getPackageManager();
+            sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
+            for (String pkg : process.pkgList) {
+                sb.append("Package: ").append(pkg);
                 try {
-                    sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
-                } catch (IOException e) {
-                    Slog.e(TAG, "Error reading " + logFile, e);
+                    PackageInfo pi = pm.getPackageInfo(pkg, 0);
+                    if (pi != null) {
+                        sb.append(" v").append(pi.versionCode);
+                        if (pi.versionName != null) {
+                            sb.append(" (").append(pi.versionName).append(")");
+                        }
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error getting package info: " + pkg, e);
                 }
+                sb.append("\n");
             }
-            if (crashInfo != null && crashInfo.stackTrace != null) {
-                sb.append(crashInfo.stackTrace);
+        }
+        if (activity != null) {
+            sb.append("Activity: ").append(activity.shortComponentName).append("\n");
+        }
+        if (parent != null && parent.app != null && parent.app.pid != process.pid) {
+            sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
+        }
+        if (parent != null && parent != activity) {
+            sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
+        }
+        if (subject != null) {
+            sb.append("Subject: ").append(subject).append("\n");
+        }
+        sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
+        sb.append("\n");
+
+        // Do the rest in a worker thread to avoid blocking the caller on I/O
+        // (After this point, we shouldn't access AMS internal data structures.)
+        Thread worker = new Thread("Error dump: " + dropboxTag) {
+            @Override
+            public void run() {
+                if (report != null) {
+                    sb.append(report);
+                }
+                if (logFile != null) {
+                    try {
+                        sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Error reading " + logFile, e);
+                    }
+                }
+                if (crashInfo != null && crashInfo.stackTrace != null) {
+                    sb.append(crashInfo.stackTrace);
+                }
+
+                String setting = Settings.Secure.ERROR_LOGCAT_PREFIX + dropboxTag;
+                int lines = Settings.Secure.getInt(mContext.getContentResolver(), setting, 0);
+                if (lines > 0) {
+                    sb.append("\n");
+
+                    // Merge several logcat streams, and take the last N lines
+                    InputStreamReader input = null;
+                    try {
+                        java.lang.Process logcat = new ProcessBuilder("/system/bin/logcat",
+                                "-v", "time", "-b", "events", "-b", "system", "-b", "main",
+                                "-t", String.valueOf(lines)).redirectErrorStream(true).start();
+
+                        try { logcat.getOutputStream().close(); } catch (IOException e) {}
+                        try { logcat.getErrorStream().close(); } catch (IOException e) {}
+                        input = new InputStreamReader(logcat.getInputStream());
+
+                        int num;
+                        char[] buf = new char[8192];
+                        while ((num = input.read(buf)) > 0) sb.append(buf, 0, num);
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Error running logcat", e);
+                    } finally {
+                        if (input != null) try { input.close(); } catch (IOException e) {}
+                    }
+                }
+
+                dbox.addText(dropboxTag, sb.toString());
             }
-            dbox.addText(dropboxTag, sb.toString());
+        };
+
+        if (process == null || process.pid == MY_PID) {
+            worker.run();  // We may be about to die -- need to run this synchronously
+        } else {
+            worker.start();
         }
     }
 
@@ -11875,7 +11948,7 @@
     // BROADCASTS
     // =========================================================
 
-    private final List getStickies(String action, IntentFilter filter,
+    private final List getStickiesLocked(String action, IntentFilter filter,
             List cur) {
         final ContentResolver resolver = mContext.getContentResolver();
         final ArrayList<Intent> list = mStickyBroadcasts.get(action);
@@ -11927,10 +12000,10 @@
             if (actions != null) {
                 while (actions.hasNext()) {
                     String action = (String)actions.next();
-                    allSticky = getStickies(action, filter, allSticky);
+                    allSticky = getStickiesLocked(action, filter, allSticky);
                 }
             } else {
-                allSticky = getStickies(null, filter, allSticky);
+                allSticky = getStickiesLocked(null, filter, allSticky);
             }
 
             // The first sticky in the list is returned directly back to
@@ -13778,7 +13851,7 @@
     /**
      * Returns true if things are idle enough to perform GCs.
      */
-    private final boolean canGcNow() {
+    private final boolean canGcNowLocked() {
         return mParallelBroadcasts.size() == 0
                 && mOrderedBroadcasts.size() == 0
                 && (mSleeping || (mResumedActivity != null &&
@@ -13794,7 +13867,7 @@
         if (N <= 0) {
             return;
         }
-        if (canGcNow()) {
+        if (canGcNowLocked()) {
             while (mProcessesToGc.size() > 0) {
                 ProcessRecord proc = mProcessesToGc.remove(0);
                 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
@@ -13822,7 +13895,7 @@
      * If all looks good, perform GCs on all processes waiting for them.
      */
     final void performAppGcsIfAppropriateLocked() {
-        if (canGcNow()) {
+        if (canGcNowLocked()) {
             performAppGcsLocked();
             return;
         }
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 25f123c..ccb5fc6 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -123,17 +123,21 @@
         mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
         mTetherMasterSM.start();
 
-        // TODO - remove this hack after real USB connections are detected.
+        mStateReceiver = new StateReceiver();
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+        mContext.registerReceiver(mStateReceiver, filter);
+
+        filter = new IntentFilter();
         filter.addAction(Intent.ACTION_MEDIA_SHARED);
         filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
+        filter.addDataScheme("file");
+        mContext.registerReceiver(mStateReceiver, filter);
+
         mUsbMassStorageOff = !Environment.MEDIA_SHARED.equals(
                 Environment.getExternalStorageState());
-        mStateReceiver = new StateReceiver();
-        mContext.registerReceiver(mStateReceiver, filter);
 
         mDhcpRange = context.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_dhcp_range);
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 521072e..70fdadf 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -135,15 +135,26 @@
     }
 
     /**
+     * An instance used for notification of blockingReset.
+     * TODO: Remove when blockingReset is removed.
+     */
+    class ResetSynchronouslyLock {
+    }
+
+    /**
      * Used internally for saving disconnecting parameters.
      */
     protected static class DisconnectParams {
         public DisconnectParams(Message onCompletedMsg) {
             this.onCompletedMsg = onCompletedMsg;
         }
+        public DisconnectParams(ResetSynchronouslyLock lockObj) {
+            this.lockObj = lockObj;
+        }
 
         public int tag;
         public Message onCompletedMsg;
+        public ResetSynchronouslyLock lockObj;
     }
 
     /**
@@ -339,11 +350,18 @@
     private void notifyDisconnectCompleted(DisconnectParams dp) {
         if (DBG) log("NotifyDisconnectCompleted");
 
-        Message msg = dp.onCompletedMsg;
-        log(String.format("msg.what=%d msg.obj=%s",
-                msg.what, ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
-        AsyncResult.forMessage(msg);
-        msg.sendToTarget();
+        if (dp.onCompletedMsg != null) {
+            Message msg = dp.onCompletedMsg;
+            log(String.format("msg.what=%d msg.obj=%s",
+                    msg.what, ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
+            AsyncResult.forMessage(msg);
+            msg.sendToTarget();
+        }
+        if (dp.lockObj != null) {
+            synchronized(dp.lockObj) {
+                dp.lockObj.notify();
+            }
+        }
 
         clearSettings();
     }
@@ -778,6 +796,23 @@
     }
 
     /**
+     * Reset the connection and wait for it to complete.
+     * TODO: Remove when all callers only need the asynchronous
+     * reset defined above.
+     */
+    public void resetSynchronously() {
+        ResetSynchronouslyLock lockObj = new ResetSynchronouslyLock();
+        synchronized(lockObj) {
+            sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(lockObj)));
+            try {
+                lockObj.wait();
+            } catch (InterruptedException e) {
+                log("blockingReset: unexpected interrupted of wait()");
+            }
+        }
+    }
+
+    /**
      * Connect to the apn and return an AsyncResult in onCompletedMsg.
      * Used for cellular networks that use Acess Point Names (APN) such
      * as GSM networks.
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 9218715..af9c652 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -386,18 +386,19 @@
                 if (tearDown) {
                     if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
                     conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason));
+                    notificationDeferred = true;
                 } else {
-                    if (DBG) log("cleanUpConnection: !tearDown, call conn.reset");
-                    conn.reset(obtainMessage(EVENT_RESET_DONE, reason));
+                    if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
+                    conn.resetSynchronously();
+                    notificationDeferred = false;
                 }
-                notificationDeferred = true;
             }
         }
 
         stopNetStatPoll();
 
         if (!notificationDeferred) {
-            if (DBG) log("cleanupConnection: !tearDown && !resettingConn");
+            if (DBG) log("cleanupConnection: !notificationDeferred");
             gotoIdleAndNotifyDataConnection(reason);
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index f26e54e..f968652 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -507,16 +507,17 @@
             if (tearDown) {
                 if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
                 conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason));
+                notificationDeferred = true;
             } else {
-                if (DBG) log("cleanUpConnection: !tearDown, call conn.reset");
-                conn.reset(obtainMessage(EVENT_RESET_DONE, reason));
+                if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
+                conn.resetSynchronously();
+                notificationDeferred = false;
             }
-            notificationDeferred = true;
         }
         stopNetStatPoll();
 
         if (!notificationDeferred) {
-            if (DBG) log("cleanupConnection: !tearDown && !resettingConn");
+            if (DBG) log("cleanupConnection: !notificationDeferred");
             gotoIdleAndNotifyDataConnection(reason);
         }
     }
diff --git a/test-runner/src/android/test/BundlePrinter.java b/test-runner/src/android/test/BundlePrinter.java
index 96213e7..3c47379 100644
--- a/test-runner/src/android/test/BundlePrinter.java
+++ b/test-runner/src/android/test/BundlePrinter.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.test;
 
 import java.io.PrintStream;
diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java
index f093598..b483b82 100644
--- a/test-runner/src/android/test/IsolatedContext.java
+++ b/test-runner/src/android/test/IsolatedContext.java
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
 package android.test;
 
 import com.google.android.collect.Lists;
diff --git a/test-runner/src/android/test/ProviderTestCase.java b/test-runner/src/android/test/ProviderTestCase.java
index 668e9f7..e1172cf 100644
--- a/test-runner/src/android/test/ProviderTestCase.java
+++ b/test-runner/src/android/test/ProviderTestCase.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.test;
 
 import android.content.ContentProvider;
diff --git a/test-runner/src/android/test/ProviderTestCase2.java b/test-runner/src/android/test/ProviderTestCase2.java
index f3655fc..28ecee5 100644
--- a/test-runner/src/android/test/ProviderTestCase2.java
+++ b/test-runner/src/android/test/ProviderTestCase2.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.test;
 
 import android.content.ContentProvider;
diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 0ea43ab..973b9f2 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.test;
 
 import com.google.android.collect.Sets;
@@ -230,4 +246,4 @@
 //        }
 //        return files.toArray(new String[]{});
 //    }
-}
\ No newline at end of file
+}
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index f2414dd..3c471ca 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -359,7 +359,7 @@
 
     const char* errorMsg = NULL;
     int errorPixel = -1;
-    const char* errorEdge = "";
+    const char* errorEdge = NULL;
 
     int colorIndex = 0;
 
@@ -463,6 +463,14 @@
     if (yDivs[numYDivs - 1] == H) {
         numRows--;
     }
+
+    // Make sure the amount of rows and columns will fit in the number of
+    // colors we can use in the 9-patch format.
+    if (numRows * numCols > 0x7F) {
+        errorMsg = "Too many rows and columns in 9-patch perimeter";
+        goto getout;
+    }
+
     numColors = numRows * numCols;
     image->info9Patch.numColors = numColors;
     image->info9Patch.colors = (uint32_t*)malloc(numColors * sizeof(uint32_t));
@@ -533,12 +541,14 @@
         fprintf(stderr,
             "ERROR: 9-patch image %s malformed.\n"
             "       %s.\n", imageName, errorMsg);
-        if (errorPixel >= 0) {
-            fprintf(stderr,
-            "       Found at pixel #%d along %s edge.\n", errorPixel, errorEdge);
-        } else {
-            fprintf(stderr,
-            "       Found along %s edge.\n", errorEdge);
+        if (errorEdge != NULL) {
+            if (errorPixel >= 0) {
+                fprintf(stderr,
+                    "       Found at pixel #%d along %s edge.\n", errorPixel, errorEdge);
+            } else {
+                fprintf(stderr,
+                    "       Found along %s edge.\n", errorEdge);
+            }
         }
         return UNKNOWN_ERROR;
     }
@@ -613,7 +623,7 @@
     } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
         bpp = 2;
     } else if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
-	    // We use a padding byte even when there is no alpha
+        // We use a padding byte even when there is no alpha
         bpp = 4;
     } else {
         printf("Unknown color type %d.\n", color_type);