Merge "Add new Activity.finishAffinity() method." into jb-dev
diff --git a/api/current.txt b/api/current.txt
index be8e139..9303937 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27843,6 +27843,7 @@
 
   public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable {
     ctor public RemoteViews(java.lang.String, int);
+    ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews);
     ctor public RemoteViews(android.os.Parcel);
     method public void addView(int, android.widget.RemoteViews);
     method public android.view.View apply(android.content.Context, android.view.ViewGroup);
@@ -27984,7 +27985,11 @@
   public class SearchView extends android.widget.LinearLayout implements android.view.CollapsibleActionView {
     ctor public SearchView(android.content.Context);
     ctor public SearchView(android.content.Context, android.util.AttributeSet);
+    method public int getImeOptions();
+    method public int getInputType();
+    method public int getMaxWidth();
     method public java.lang.CharSequence getQuery();
+    method public java.lang.CharSequence getQueryHint();
     method public android.widget.CursorAdapter getSuggestionsAdapter();
     method public boolean isIconfiedByDefault();
     method public boolean isIconified();
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 018785b..2782dca 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3049,6 +3049,13 @@
      * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating social
      * stream items requires android.permission.WRITE_SOCIAL_STREAM permission.
      * </p>
+     * <h3>Account check</h3>
+     * <p>
+     * The content URIs to the insert, update and delete operations are required to have the account
+     * information matching that of the owning raw contact as query parameters, namely
+     * {@link RawContacts#ACCOUNT_TYPE} and {@link RawContacts#ACCOUNT_NAME}.
+     * {@link RawContacts#DATA_SET} isn't required.
+     * </p>
      * <h3>Operations</h3>
      * <dl>
      * <dt><b>Insert</b></dt>
@@ -3063,9 +3070,12 @@
      * values.put(StreamItems.TEXT, "Breakfasted at Tiffanys");
      * values.put(StreamItems.TIMESTAMP, timestamp);
      * values.put(StreamItems.COMMENTS, "3 people reshared this");
-     * Uri streamItemUri = getContentResolver().insert(
-     *     Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
-     *         RawContacts.StreamItems.CONTENT_DIRECTORY), values);
+     * Uri.Builder builder = RawContacts.CONTENT_URI.buildUpon();
+     * ContentUris.appendId(builder, rawContactId);
+     * builder.appendEncodedPath(RawContacts.StreamItems.CONTENT_DIRECTORY);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
+     * Uri streamItemUri = getContentResolver().insert(builder.build(), values);
      * long streamItemId = ContentUris.parseId(streamItemUri);
      * </pre>
      * </dd>
@@ -3077,7 +3087,10 @@
      * values.put(StreamItems.TEXT, "Breakfasted at Tiffanys");
      * values.put(StreamItems.TIMESTAMP, timestamp);
      * values.put(StreamItems.COMMENTS, "3 people reshared this");
-     * Uri streamItemUri = getContentResolver().insert(StreamItems.CONTENT_URI, values);
+     * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
+     * Uri streamItemUri = getContentResolver().insert(builder.build(), values);
      * long streamItemId = ContentUris.parseId(streamItemUri);
      *</pre>
      * </dd>
@@ -3410,6 +3423,13 @@
      * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating
      * social stream photos requires android.permission.WRITE_SOCIAL_STREAM permission.
      * </p>
+     * <h3>Account check</h3>
+     * <p>
+     * The content URIs to the insert, update and delete operations are required to have the account
+     * information matching that of the owning raw contact as query parameters, namely
+     * {@link RawContacts#ACCOUNT_TYPE} and {@link RawContacts#ACCOUNT_NAME}.
+     * {@link RawContacts#DATA_SET} isn't required.
+     * </p>
      * <h3>Operations</h3>
      * <dl>
      * <dt><b>Insert</b></dt>
@@ -3426,9 +3446,12 @@
      * ContentValues values = new ContentValues();
      * values.put(StreamItemPhotos.SORT_INDEX, 1);
      * values.put(StreamItemPhotos.PHOTO, photoData);
-     * Uri photoUri = getContentResolver().insert(Uri.withAppendedPath(
-     *     ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId)
-     *     StreamItems.StreamItemPhotos#CONTENT_DIRECTORY), values);
+     * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
+     * ContentUris.appendId(builder, streamItemId);
+     * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
+     * Uri photoUri = getContentResolver().insert(builder.build(), values);
      * long photoId = ContentUris.parseId(photoUri);
      * </pre>
      * </dd>
@@ -3439,7 +3462,10 @@
      * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
      * values.put(StreamItemPhotos.SORT_INDEX, 1);
      * values.put(StreamItemPhotos.PHOTO, photoData);
-     * Uri photoUri = getContentResolver().insert(StreamItems.CONTENT_PHOTO_URI, values);
+     * Uri.Builder builder = StreamItems.CONTENT_PHOTO_URI.buildUpon();
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
+     * Uri photoUri = getContentResolver().insert(builder.build(), values);
      * long photoId = ContentUris.parseId(photoUri);
      * </pre>
      * </dd>
@@ -3459,12 +3485,13 @@
      * <pre>
      * ContentValues values = new ContentValues();
      * values.put(StreamItemPhotos.PHOTO, newPhotoData);
-     * getContentResolver().update(
-     *     ContentUris.withAppendedId(
-     *         Uri.withAppendedPath(
-     *             ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId)
-     *             StreamItems.StreamItemPhotos#CONTENT_DIRECTORY),
-     *         streamItemPhotoId), values, null, null);
+     * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
+     * ContentUris.appendId(builder, streamItemId);
+     * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
+     * ContentUris.appendId(builder, streamItemPhotoId);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
+     * getContentResolver().update(builder.build(), values, null, null);
      * </pre>
      * </dd>
      * <dt>Via the {@link ContactsContract.StreamItems#CONTENT_PHOTO_URI} URI:</dt>
@@ -3473,7 +3500,10 @@
      * ContentValues values = new ContentValues();
      * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
      * values.put(StreamItemPhotos.PHOTO, newPhotoData);
-     * getContentResolver().update(StreamItems.CONTENT_PHOTO_URI, values);
+     * Uri.Builder builder = StreamItems.CONTENT_PHOTO_URI.buildUpon();
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
+     * getContentResolver().update(builder.build(), values);
      * </pre>
      * </dd>
      * </dl>
@@ -3489,21 +3519,24 @@
      * </dt>
      * <dd>
      * <pre>
-     * getContentResolver().delete(
-     *     ContentUris.withAppendedId(
-     *         Uri.withAppendedPath(
-     *             ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId)
-     *             StreamItems.StreamItemPhotos#CONTENT_DIRECTORY),
-     *         streamItemPhotoId), null, null);
+     * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
+     * ContentUris.appendId(builder, streamItemId);
+     * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
+     * ContentUris.appendId(builder, streamItemPhotoId);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
+     * getContentResolver().delete(builder.build(), null, null);
      * </pre>
      * </dd>
      * <dt>Deleting all photos under a stream item</dt>
      * <dd>
      * <pre>
-     * getContentResolver().delete(
-     *     Uri.withAppendedPath(
-     *         ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId)
-     *         StreamItems.StreamItemPhotos#CONTENT_DIRECTORY), null, null);
+     * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
+     * ContentUris.appendId(builder, streamItemId);
+     * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
+     * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
+     * getContentResolver().delete(builder.build(), null, null);
      * </pre>
      * </dd>
      * </dl>
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 214775a..e628bc1 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
@@ -87,7 +88,32 @@
      */
     private MemoryUsageCounter mMemoryUsageCounter;
 
-    
+    /**
+     * Maps bitmaps to unique indicies to avoid Bitmap duplication.
+     */
+    private BitmapCache mBitmapCache;
+
+    /**
+     * Indicates whether or not this RemoteViews object is contained as a child of any other
+     * RemoteViews.
+     */
+    private boolean mIsRoot = true;
+
+    /**
+     * Constants to whether or not this RemoteViews is composed of a landscape and portrait
+     * RemoteViews.
+     */
+    private static final int MODE_NORMAL = 0;
+    private static final int MODE_HAS_LANDSCAPE_AND_PORTRAIT = 1;
+
+    /**
+     * Used in conjunction with the special constructor
+     * {@link #RemoteViews(RemoteViews, RemoteViews)} to keep track of the landscape and portrait
+     * RemoteViews.
+     */
+    private RemoteViews mLandscape = null;
+    private RemoteViews mPortrait = null;
+
     /**
      * This flag indicates whether this RemoteViews object is being created from a
      * RemoteViewsService for use as a child of a widget collection. This flag is used
@@ -163,6 +189,10 @@
             }
             return true;
         }
+
+        public void setBitmapCache(BitmapCache bitmapCache) {
+            // Do nothing
+        }
     }
 
     private class SetEmptyView extends Action {
@@ -643,6 +673,112 @@
         }
     }
 
+    private static class BitmapCache {
+        ArrayList<Bitmap> mBitmaps;
+
+        public BitmapCache() {
+            mBitmaps = new ArrayList<Bitmap>();
+        }
+
+        public BitmapCache(Parcel source) {
+            int count = source.readInt();
+            mBitmaps = new ArrayList<Bitmap>();
+            for (int i = 0; i < count; i++) {
+                Bitmap b = Bitmap.CREATOR.createFromParcel(source);
+                mBitmaps.add(b);
+            }
+        }
+
+        public int getBitmapId(Bitmap b) {
+            if (b == null) {
+                return -1;
+            } else {
+                if (mBitmaps.contains(b)) {
+                    return mBitmaps.indexOf(b);
+                } else {
+                    mBitmaps.add(b);
+                    return (mBitmaps.size() - 1);
+                }
+            }
+        }
+
+        public Bitmap getBitmapForId(int id) {
+            if (id == -1 || id >= mBitmaps.size()) {
+                return null;
+            } else {
+                return mBitmaps.get(id);
+            }
+        }
+
+        public void writeBitmapsToParcel(Parcel dest, int flags) {
+            int count = mBitmaps.size();
+            dest.writeInt(count);
+            for (int i = 0; i < count; i++) {
+                mBitmaps.get(i).writeToParcel(dest, flags);
+            }
+        }
+
+        public void assimilate(BitmapCache bitmapCache) {
+            ArrayList<Bitmap> bitmapsToBeAdded = bitmapCache.mBitmaps;
+            int count = bitmapsToBeAdded.size();
+            for (int i = 0; i < count; i++) {
+                Bitmap b = bitmapsToBeAdded.get(i);
+                if (!mBitmaps.contains(b)) {
+                    mBitmaps.add(b);
+                }
+            }
+        }
+
+        public void addBitmapMemory(MemoryUsageCounter memoryCounter) {
+            for (int i = 0; i < mBitmaps.size(); i++) {
+                memoryCounter.addBitmapMemory(mBitmaps.get(i));
+            }
+        }
+    }
+
+    private class BitmapReflectionAction extends Action {
+        int bitmapId;
+        int viewId;
+        Bitmap bitmap;
+        String methodName;
+
+        BitmapReflectionAction(int viewId, String methodName, Bitmap bitmap) {
+            this.bitmap = bitmap;
+            this.viewId = viewId;
+            this.methodName = methodName;
+            bitmapId = mBitmapCache.getBitmapId(bitmap);
+        }
+
+        BitmapReflectionAction(Parcel in) {
+            viewId = in.readInt();
+            methodName = in.readString();
+            bitmapId = in.readInt();
+            bitmap = mBitmapCache.getBitmapForId(bitmapId);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(TAG);
+            dest.writeInt(viewId);
+            dest.writeString(methodName);
+            dest.writeInt(bitmapId);
+        }
+
+        @Override
+        public void apply(View root, ViewGroup rootParent) throws ActionException {
+            ReflectionAction ra = new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP,
+                    bitmap);
+            ra.apply(root, rootParent);
+        }
+
+        @Override
+        public void setBitmapCache(BitmapCache bitmapCache) {
+            bitmapId = bitmapCache.getBitmapId(bitmap);
+        }
+
+        public final static int TAG = 12;
+    }
+
     /**
      * Base class for the reflection actions.
      */
@@ -894,24 +1030,7 @@
                 case BITMAP:
                     if (this.value != null) {
                         final Bitmap b = (Bitmap) this.value;
-                        final Bitmap.Config c = b.getConfig();
-                        // If we don't know, be pessimistic and assume 4
-                        int bpp = 4;
-                        if (c != null) {
-                            switch (c) {
-                            case ALPHA_8:
-                                bpp = 1;
-                                break;
-                            case RGB_565:
-                            case ARGB_4444:
-                                bpp = 2;
-                                break;
-                            case ARGB_8888:
-                                bpp = 4;
-                                break;
-                            }
-                        }
-                        counter.bitmapIncrement(b.getWidth() * b.getHeight() * bpp);
+                        counter.addBitmapMemory(b);
                     }
                     break;
                 default:
@@ -920,6 +1039,16 @@
         }
     }
 
+    private void configureRemoteViewsAsChild(RemoteViews rv) {
+        mBitmapCache.assimilate(rv.mBitmapCache);
+        rv.setBitmapCache(mBitmapCache);
+        rv.setNotRoot();
+    }
+
+    void setNotRoot() {
+        mIsRoot = false;
+    }
+
     /**
      * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
      * given {@link RemoteViews}, or calling {@link ViewGroup#removeAllViews()}
@@ -929,17 +1058,31 @@
         public ViewGroupAction(int viewId, RemoteViews nestedViews) {
             this.viewId = viewId;
             this.nestedViews = nestedViews;
+            if (nestedViews != null) {
+                configureRemoteViewsAsChild(nestedViews);
+            }
         }
 
-        public ViewGroupAction(Parcel parcel) {
+        public ViewGroupAction(Parcel parcel, BitmapCache bitmapCache) {
             viewId = parcel.readInt();
-            nestedViews = parcel.readParcelable(null);
+            boolean nestedViewsNull = parcel.readInt() == 0;
+            if (!nestedViewsNull) {
+                nestedViews = new RemoteViews(parcel, bitmapCache);
+            } else {
+                nestedViews = null;
+            }
         }
 
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(TAG);
             dest.writeInt(viewId);
-            dest.writeParcelable(nestedViews, 0 /* no flags */);
+            if (nestedViews != null) {
+                dest.writeInt(1);
+                nestedViews.writeToParcel(dest, flags);
+            } else {
+                // signifies null
+                dest.writeInt(0);
+            }
         }
 
         @Override
@@ -959,7 +1102,14 @@
         @Override
         public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
             if (nestedViews != null) {
-                counter.bitmapIncrement(nestedViews.estimateBitmapMemoryUsage());
+                counter.increment(nestedViews.estimateMemoryUsage());
+            }
+        }
+
+        @Override
+        public void setBitmapCache(BitmapCache bitmapCache) {
+            if (nestedViews != null) {
+                nestedViews.setBitmapCache(bitmapCache);
             }
         }
 
@@ -1027,18 +1177,39 @@
      */
     private class MemoryUsageCounter {
         public void clear() {
-            mBitmapHeapMemoryUsage = 0;
+            mMemoryUsage = 0;
         }
 
-        public void bitmapIncrement(int numBytes) {
-            mBitmapHeapMemoryUsage += numBytes;
+        public void increment(int numBytes) {
+            mMemoryUsage += numBytes;
         }
 
-        public int getBitmapHeapMemoryUsage() {
-            return mBitmapHeapMemoryUsage;
+        public int getMemoryUsage() {
+            return mMemoryUsage;
         }
 
-        int mBitmapHeapMemoryUsage;
+        public void addBitmapMemory(Bitmap b) {
+            final Bitmap.Config c = b.getConfig();
+            // If we don't know, be pessimistic and assume 4
+            int bpp = 4;
+            if (c != null) {
+                switch (c) {
+                case ALPHA_8:
+                    bpp = 1;
+                    break;
+                case RGB_565:
+                case ARGB_4444:
+                    bpp = 2;
+                    break;
+                case ARGB_8888:
+                    bpp = 4;
+                    break;
+                }
+            }
+            increment(b.getWidth() * b.getHeight() * bpp);
+        }
+
+        int mMemoryUsage;
     }
 
     /**
@@ -1051,62 +1222,122 @@
     public RemoteViews(String packageName, int layoutId) {
         mPackage = packageName;
         mLayoutId = layoutId;
+        mBitmapCache = new BitmapCache();
 
         // setup the memory usage statistics
         mMemoryUsageCounter = new MemoryUsageCounter();
         recalculateMemoryUsage();
     }
 
+    private boolean hasLandscapeAndPortraitLayouts() {
+        return (mLandscape != null) && (mPortrait != null);
+    }
+
+     /**
+     * Create a new RemoteViews object that will inflate as the specified
+     * landspace or portrait RemoteViews, depending on the current configuration.
+     *
+     * @param landscape The RemoteViews to inflate in landscape configuration
+     * @param portrait The RemoteViews to inflate in portrait configuration
+     */
+    public RemoteViews(RemoteViews landscape, RemoteViews portrait) {
+        if (landscape == null || portrait == null) {
+            throw new RuntimeException("Both RemoteViews must be non-null");
+        }
+        if (landscape.getPackage().compareTo(portrait.getPackage()) != 0) {
+            throw new RuntimeException("Both RemoteViews must share the same package");
+        }
+        mPackage = portrait.getPackage();
+        mLayoutId = portrait.getLayoutId();
+
+        mLandscape = landscape;
+        mPortrait = portrait;
+
+        // setup the memory usage statistics
+        mMemoryUsageCounter = new MemoryUsageCounter();
+
+        mBitmapCache = new BitmapCache();
+        configureRemoteViewsAsChild(landscape);
+        configureRemoteViewsAsChild(portrait);
+
+        recalculateMemoryUsage();
+    }
+
     /**
      * Reads a RemoteViews object from a parcel.
      * 
      * @param parcel
      */
     public RemoteViews(Parcel parcel) {
-        mPackage = parcel.readString();
-        mLayoutId = parcel.readInt();
-        mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false;
+        this(parcel, null);
+    }
 
-        int count = parcel.readInt();
-        if (count > 0) {
-            mActions = new ArrayList<Action>(count);
-            for (int i=0; i<count; i++) {
-                int tag = parcel.readInt();
-                switch (tag) {
-                case SetOnClickPendingIntent.TAG:
-                    mActions.add(new SetOnClickPendingIntent(parcel));
-                    break;
-                case SetDrawableParameters.TAG:
-                    mActions.add(new SetDrawableParameters(parcel));
-                    break;
-                case ReflectionAction.TAG:
-                    mActions.add(new ReflectionAction(parcel));
-                    break;
-                case ViewGroupAction.TAG:
-                    mActions.add(new ViewGroupAction(parcel));
-                    break;
-                case ReflectionActionWithoutParams.TAG:
-                    mActions.add(new ReflectionActionWithoutParams(parcel));
-                    break;
-                case SetEmptyView.TAG:
-                    mActions.add(new SetEmptyView(parcel));
-                    break;
-                case SetPendingIntentTemplate.TAG:
-                    mActions.add(new SetPendingIntentTemplate(parcel));
-                    break;
-                case SetOnClickFillInIntent.TAG:
-                    mActions.add(new SetOnClickFillInIntent(parcel));
-                    break;
-                case SetRemoteViewsAdapterIntent.TAG:
-                    mActions.add(new SetRemoteViewsAdapterIntent(parcel));
-                    break;
-                case TextViewDrawableAction.TAG:
-                    mActions.add(new TextViewDrawableAction(parcel));
-                    break;
-                default:
-                    throw new ActionException("Tag " + tag + " not found");
+    private RemoteViews(Parcel parcel, BitmapCache bitmapCache) {
+        int mode = parcel.readInt();
+
+        // We only store a bitmap cache in the root of the RemoteViews.
+        if (bitmapCache == null) {
+            mBitmapCache = new BitmapCache(parcel);
+        } else {
+            setBitmapCache(bitmapCache);
+            setNotRoot();
+        }
+
+        if (mode == MODE_NORMAL) {
+            mPackage = parcel.readString();
+            mLayoutId = parcel.readInt();
+            mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false;
+
+            int count = parcel.readInt();
+            if (count > 0) {
+                mActions = new ArrayList<Action>(count);
+                for (int i=0; i<count; i++) {
+                    int tag = parcel.readInt();
+                    switch (tag) {
+                    case SetOnClickPendingIntent.TAG:
+                        mActions.add(new SetOnClickPendingIntent(parcel));
+                        break;
+                    case SetDrawableParameters.TAG:
+                        mActions.add(new SetDrawableParameters(parcel));
+                        break;
+                    case ReflectionAction.TAG:
+                        mActions.add(new ReflectionAction(parcel));
+                        break;
+                    case ViewGroupAction.TAG:
+                        mActions.add(new ViewGroupAction(parcel, mBitmapCache));
+                        break;
+                    case ReflectionActionWithoutParams.TAG:
+                        mActions.add(new ReflectionActionWithoutParams(parcel));
+                        break;
+                    case SetEmptyView.TAG:
+                        mActions.add(new SetEmptyView(parcel));
+                        break;
+                    case SetPendingIntentTemplate.TAG:
+                        mActions.add(new SetPendingIntentTemplate(parcel));
+                        break;
+                    case SetOnClickFillInIntent.TAG:
+                        mActions.add(new SetOnClickFillInIntent(parcel));
+                        break;
+                    case SetRemoteViewsAdapterIntent.TAG:
+                        mActions.add(new SetRemoteViewsAdapterIntent(parcel));
+                        break;
+                    case TextViewDrawableAction.TAG:
+                        mActions.add(new TextViewDrawableAction(parcel));
+                        break;
+                    case BitmapReflectionAction.TAG:
+                        mActions.add(new BitmapReflectionAction(parcel));
+                        break;
+                    default:
+                        throw new ActionException("Tag " + tag + " not found");
+                    }
                 }
             }
+        } else {
+            // MODE_HAS_LANDSCAPE_AND_PORTRAIT
+            mLandscape = new RemoteViews(parcel, mBitmapCache);
+            mPortrait = new RemoteViews(parcel, mBitmapCache);
+            mPackage = mPortrait.getPackage();
+            mLayoutId = mPortrait.getLayoutId();
         }
 
         // setup the memory usage statistics
@@ -1116,11 +1347,18 @@
 
     @Override
     public RemoteViews clone() {
-        final RemoteViews that = new RemoteViews(mPackage, mLayoutId);
-        if (mActions != null) {
-            that.mActions = (ArrayList<Action>)mActions.clone();
-        }
+        RemoteViews that;
+        if (!hasLandscapeAndPortraitLayouts()) {
+            that = new RemoteViews(mPackage, mLayoutId);
 
+            if (mActions != null) {
+                that.mActions = (ArrayList<Action>)mActions.clone();
+            }
+        } else {
+            RemoteViews land = mLandscape.clone();
+            RemoteViews port = mPortrait.clone();
+            that = new RemoteViews(land, port);
+        }
         // update the memory usage stats of the cloned RemoteViews
         that.recalculateMemoryUsage();
         return that;
@@ -1130,6 +1368,13 @@
         return mPackage;
     }
 
+    /**
+     * Reutrns the layout id of the root layout associated with this RemoteViews. In the case
+     * that the RemoteViews has both a landscape and portrait root, this will return the layout
+     * id associated with the portrait layout.
+     *
+     * @return the layout id.
+     */
     public int getLayoutId() {
         return mLayoutId;
     }
@@ -1151,20 +1396,47 @@
     private void recalculateMemoryUsage() {
         mMemoryUsageCounter.clear();
 
-        // Accumulate the memory usage for each action
-        if (mActions != null) {
-            final int count = mActions.size();
-            for (int i= 0; i < count; ++i) {
-                mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter);
+        if (!hasLandscapeAndPortraitLayouts()) {
+            // Accumulate the memory usage for each action
+            if (mActions != null) {
+                final int count = mActions.size();
+                for (int i= 0; i < count; ++i) {
+                    mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter);
+                }
             }
+            if (mIsRoot) {
+                mBitmapCache.addBitmapMemory(mMemoryUsageCounter);
+            }
+        } else {
+            mMemoryUsageCounter.increment(mLandscape.estimateMemoryUsage());
+            mMemoryUsageCounter.increment(mPortrait.estimateMemoryUsage());
+            mBitmapCache.addBitmapMemory(mMemoryUsageCounter);
+        }
+    }
+
+    /**
+     * Recursively sets BitmapCache in the hierarchy and update the bitmap ids.
+     */
+    private void setBitmapCache(BitmapCache bitmapCache) {
+        mBitmapCache = bitmapCache;
+        if (!hasLandscapeAndPortraitLayouts()) {
+            if (mActions != null) {
+                final int count = mActions.size();
+                for (int i= 0; i < count; ++i) {
+                    mActions.get(i).setBitmapCache(bitmapCache);
+                }
+            }
+        } else {
+            mLandscape.setBitmapCache(bitmapCache);
+            mPortrait.setBitmapCache(bitmapCache);
         }
     }
 
     /**
      * Returns an estimate of the bitmap heap memory usage for this RemoteViews.
      */
-    int estimateBitmapMemoryUsage() {
-        return mMemoryUsageCounter.getBitmapHeapMemoryUsage();
+    int estimateMemoryUsage() {
+        return mMemoryUsageCounter.getMemoryUsage();
     }
 
     /**
@@ -1173,6 +1445,11 @@
      * @param a The action to add
      */
     private void addAction(Action a) {
+        if (hasLandscapeAndPortraitLayouts()) {
+            throw new RuntimeException("RemoteViews specifying separate landscape and portrait" +
+                    " layouts cannot be modified. Instead, fully configure the landscape and" +
+                    " portrait layouts individually before constructing the combined layout.");
+        }
         if (mActions == null) {
             mActions = new ArrayList<Action>();
         }
@@ -1644,7 +1921,7 @@
      * @param value The value to pass to the method.
      */
     public void setBitmap(int viewId, String methodName, Bitmap value) {
-        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, value));
+        addAction(new BitmapReflectionAction(viewId, methodName, value));
     }
 
     /**
@@ -1679,6 +1956,18 @@
         setCharSequence(viewId, "setContentDescription", contentDescription);
     }
 
+    private RemoteViews getRemoteViewsToApply(Context context) {
+        if (hasLandscapeAndPortraitLayouts()) {
+            int orientation = context.getResources().getConfiguration().orientation;
+            if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+                return mLandscape;
+            } else {
+                return mPortrait;
+            }
+        }
+        return this;
+    }
+
     /**
      * Inflates the view hierarchy represented by this object and applies
      * all of the actions.
@@ -1691,6 +1980,8 @@
      * @return The inflated view hierarchy
      */
     public View apply(Context context, ViewGroup parent) {
+        RemoteViews rvToApply = getRemoteViewsToApply(context);
+
         View result;
 
         Context c = prepareContext(context);
@@ -1701,13 +1992,13 @@
         inflater = inflater.cloneInContext(c);
         inflater.setFilter(this);
 
-        result = inflater.inflate(mLayoutId, parent, false);
+        result = inflater.inflate(rvToApply.getLayoutId(), parent, false);
 
-        performApply(result, parent);
+        rvToApply.performApply(result, parent);
 
         return result;
     }
-    
+
     /**
      * Applies all of the actions to the provided view.
      *
@@ -1717,8 +2008,20 @@
      * the {@link #apply(Context,ViewGroup)} call.
      */
     public void reapply(Context context, View v) {
+        RemoteViews rvToApply = getRemoteViewsToApply(context);
+
+        // In the case that a view has this RemoteViews applied in one orientation, is persisted
+        // across orientation change, and has the RemoteViews re-applied in the new orientation,
+        // we throw an exception, since the layouts may be completely unrelated.
+        if (hasLandscapeAndPortraitLayouts()) {
+            if (v.getId() != rvToApply.getLayoutId()) {
+                throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
+                        " that does not share the same root layout id.");
+            }
+        }
+
         prepareContext(context);
-        performApply(v, (ViewGroup) v.getParent());
+        rvToApply.performApply(v, (ViewGroup) v.getParent());
     }
 
     private void performApply(View v, ViewGroup parent) {
@@ -1757,25 +2060,42 @@
     public boolean onLoadClass(Class clazz) {
         return clazz.isAnnotationPresent(RemoteView.class);
     }
-    
+
     public int describeContents() {
         return 0;
     }
 
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mPackage);
-        dest.writeInt(mLayoutId);
-        dest.writeInt(mIsWidgetCollectionChild ? 1 : 0);
-        int count;
-        if (mActions != null) {
-            count = mActions.size();
+        if (!hasLandscapeAndPortraitLayouts()) {
+            dest.writeInt(MODE_NORMAL);
+            // We only write the bitmap cache if we are the root RemoteViews, as this cache
+            // is shared by all children.
+            if (mIsRoot) {
+                mBitmapCache.writeBitmapsToParcel(dest, flags);
+            }
+            dest.writeString(mPackage);
+            dest.writeInt(mLayoutId);
+            dest.writeInt(mIsWidgetCollectionChild ? 1 : 0);
+            int count;
+            if (mActions != null) {
+                count = mActions.size();
+            } else {
+                count = 0;
+            }
+            dest.writeInt(count);
+            for (int i=0; i<count; i++) {
+                Action a = mActions.get(i);
+                a.writeToParcel(dest, 0);
+            }
         } else {
-            count = 0;
-        }
-        dest.writeInt(count);
-        for (int i=0; i<count; i++) {
-            Action a = mActions.get(i);
-            a.writeToParcel(dest, 0);
+            dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT);
+            // We only write the bitmap cache if we are the root RemoteViews, as this cache
+            // is shared by all children.
+            if (mIsRoot) {
+                mBitmapCache.writeBitmapsToParcel(dest, flags);
+            }
+            mLandscape.writeToParcel(dest, flags);
+            mPortrait.writeToParcel(dest, flags);
         }
     }
 
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 8067435..f266d50 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -595,7 +595,7 @@
             for (Integer i : mIndexRemoteViews.keySet()) {
                 final RemoteViews v = mIndexRemoteViews.get(i);
                 if (v != null) {
-                    mem += v.estimateBitmapMemoryUsage();
+                    mem += v.estimateMemoryUsage();
                 }
             }
             return mem;
@@ -942,10 +942,6 @@
      * which  wouldn't otherwise be possible.
      */
     public void setVisibleRangeHint(int lowerBound, int upperBound) {
-        if (lowerBound < 0 || upperBound < 0) {
-            throw new RuntimeException("Attempted to set invalid range: lowerBound="+lowerBound +
-                    "," + "upperBound="+upperBound);
-        }
         mVisibleWindowLowerBound = lowerBound;
         mVisibleWindowUpperBound = upperBound;
     }
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 99cd0b8..561326e 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -381,6 +381,17 @@
     }
 
     /**
+     * Returns the IME options set on the query text field.
+     * @return the ime options
+     * @see TextView#setImeOptions(int)
+     *
+     * @attr ref android.R.styleable#SearchView_imeOptions
+     */
+    public int getImeOptions() {
+        return mQueryTextView.getImeOptions();
+    }
+
+    /**
      * Sets the input type on the query text field.
      *
      * @see TextView#setInputType(int)
@@ -392,6 +403,16 @@
         mQueryTextView.setInputType(inputType);
     }
 
+    /**
+     * Returns the input type set on the query text field.
+     * @return the input type
+     *
+     * @attr ref android.R.styleable#SearchView_inputType
+     */
+    public int getInputType() {
+        return mQueryTextView.getInputType();
+    }
+
     /** @hide */
     @Override
     public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
@@ -514,6 +535,26 @@
     }
 
     /**
+     * Gets the hint text to display in the query text field.
+     * @return the query hint text, if specified, null otherwise.
+     *
+     * @attr ref android.R.styleable#SearchView_queryHint
+     */
+    public CharSequence getQueryHint() {
+        if (mQueryHint != null) {
+            return mQueryHint;
+        } else if (mSearchable != null) {
+            CharSequence hint = null;
+            int hintId = mSearchable.getHintId();
+            if (hintId != 0) {
+                hint = getContext().getString(hintId);
+            }
+            return hint;
+        }
+        return null;
+    }
+
+    /**
      * Sets the default or resting state of the search field. If true, a single search icon is
      * shown by default and expands to show the text field and other buttons when pressed. Also,
      * if the default state is iconified, then it collapses to that state when the close button
@@ -651,6 +692,15 @@
         requestLayout();
     }
 
+    /**
+     * Gets the specified maximum width in pixels, if set. Returns zero if
+     * no maximum width was specified.
+     * @return the maximum width of the view
+     */
+    public int getMaxWidth() {
+        return mMaxWidth;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // Let the standard measurements take effect in iconified state.
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
index bbd6bea..2f864d7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
@@ -47,6 +47,7 @@
     private boolean jpegPictureCallbackResult = false;
     
     private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000;  // Milliseconds.
+    private static final int CAMERA_ID = 0;
     
     private RawPreviewCallback mRawPreviewCallback = new RawPreviewCallback();
     private TestShutterCallback mShutterCallback = new TestShutterCallback();
@@ -85,7 +86,7 @@
                 // Save the looper so that we can terminate this thread 
                 // after we are done with it.
                 mLooper = Looper.myLooper();
-                mCamera = Camera.open();
+                mCamera = Camera.open(CAMERA_ID);
                 startDone.open();
                 Looper.loop();  // Blocks forever until Looper.quit() is called.
                 Log.v(TAG, "initializeMessageLooper: quit.");
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
index 0684946..8e6d5cb 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
@@ -54,6 +54,8 @@
 
     private int MIN_VIDEO_FPS = 5;
 
+    private static final int CAMERA_ID = 0;
+
     Context mContext;
     Camera mCamera;
   
@@ -247,7 +249,7 @@
     public void testPortraitH263() throws Exception {
         boolean videoRecordedResult = false;
         try {
-            mCamera = Camera.open();
+            mCamera = Camera.open(CAMERA_ID);
             Camera.Parameters parameters = mCamera.getParameters();
             parameters.setPreviewSize(352, 288);
             parameters.set("orientation", "portrait");
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 db64b94..ccb0638 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -72,6 +72,7 @@
         "/sdcard/mediaMemOutput.txt";
     private static final String MEDIA_PROCMEM_OUTPUT =
         "/sdcard/mediaProcmemOutput.txt";
+    private static final int CAMERA_ID = 0;
 
     private static int mStartMemory = 0;
     private static int mEndMemory = 0;
@@ -132,7 +133,7 @@
                 Looper.prepare();
                 Log.v(TAG, "start loopRun");
                 mLooper = Looper.myLooper();
-                mCamera = Camera.open();
+                mCamera = Camera.open(CAMERA_ID);
                 startDone.open();
                 Looper.loop();
                 Log.v(TAG, "initializeMessageLooper: quit.");
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java
index a9c6119..ab9e36c3 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java
@@ -60,6 +60,7 @@
     private static final long WAIT_ZOOM_ANIMATION = 5 * 1000; // 5 seconds
     private static final String CAMERA_STRESS_OUTPUT =
             "/sdcard/cameraStressOutput.txt";
+    private static final int CAMERA_ID = 0;
     private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback();
 
     private Thread mLooperThread;
@@ -213,7 +214,7 @@
             Log.v(TAG, "Start preview");
             output.write("No of loop: ");
 
-            mCamera = Camera.open();
+            mCamera = Camera.open(CAMERA_ID);
             Camera.Parameters params = mCamera.getParameters();
             mCamera.release();
 
@@ -230,7 +231,7 @@
                     runOnLooper(new Runnable() {
                         @Override
                         public void run() {
-                            mCamera = Camera.open();
+                            mCamera = Camera.open(CAMERA_ID);
                         }
                     });
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
index e9bc6f0..62462bd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -60,6 +60,8 @@
     private static final String OUTPUT_FILE_EXT = ".3gp";
     private static final String MEDIA_STRESS_OUTPUT =
         "/sdcard/mediaStressOutput.txt";
+    private static final int CAMERA_ID = 0;
+
     private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback();
     private final RecorderErrorCallback mRecorderErrorCallback = new RecorderErrorCallback();
 
@@ -162,7 +164,7 @@
                 runOnLooper(new Runnable() {
                     @Override
                     public void run() {
-                        mCamera = Camera.open();
+                        mCamera = Camera.open(CAMERA_ID);
                     }
                 });
                 mCamera.setErrorCallback(mCameraErrorCallback);
@@ -250,7 +252,7 @@
                 runOnLooper(new Runnable() {
                     @Override
                     public void run() {
-                        mCamera = Camera.open();
+                        mCamera = Camera.open(CAMERA_ID);
                     }
                 });
                 mCamera.setErrorCallback(mCameraErrorCallback);