Merge "Move softap config handling to WifiConfigStore" into honeycomb-mr2
diff --git a/api/current.xml b/api/current.xml
index e669a99..393e542 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -31483,6 +31483,25 @@
 <parameter name="exit" type="int">
 </parameter>
 </method>
+<method name="setCustomAnimations"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enter" type="int">
+</parameter>
+<parameter name="exit" type="int">
+</parameter>
+<parameter name="popEnter" type="int">
+</parameter>
+<parameter name="popExit" type="int">
+</parameter>
+</method>
 <method name="setTransition"
  return="android.app.FragmentTransaction"
  abstract="true"
@@ -95449,6 +95468,17 @@
  visibility="public"
 >
 </method>
+<method name="getRawDescriptors"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getSerial"
  return="java.lang.String"
  abstract="false"
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 09e3d76..e5a7980 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -43,7 +43,7 @@
             if (op.removed != null) numRemoved += op.removed.size();
             op = op.next;
         }
-        mOps = new int[bse.mNumOp*5 + numRemoved];
+        mOps = new int[bse.mNumOp*7 + numRemoved];
 
         if (!bse.mAddToBackStack) {
             throw new IllegalStateException("Not on back stack");
@@ -56,6 +56,8 @@
             mOps[pos++] = op.fragment.mIndex;
             mOps[pos++] = op.enterAnim;
             mOps[pos++] = op.exitAnim;
+            mOps[pos++] = op.popEnterAnim;
+            mOps[pos++] = op.popExitAnim;
             if (op.removed != null) {
                 final int N = op.removed.size();
                 mOps[pos++] = N;
@@ -101,6 +103,8 @@
             op.fragment = f;
             op.enterAnim = mOps[pos++];
             op.exitAnim = mOps[pos++];
+            op.popEnterAnim = mOps[pos++];
+            op.popExitAnim = mOps[pos++];
             final int N = mOps[pos++];
             if (N > 0) {
                 op.removed = new ArrayList<Fragment>(N);
@@ -179,6 +183,8 @@
         Fragment fragment;
         int enterAnim;
         int exitAnim;
+        int popEnterAnim;
+        int popExitAnim;
         ArrayList<Fragment> removed;
     }
 
@@ -187,6 +193,8 @@
     int mNumOp;
     int mEnterAnim;
     int mExitAnim;
+    int mPopEnterAnim;
+    int mPopExitAnim;
     int mTransition;
     int mTransitionStyle;
     boolean mAddToBackStack;
@@ -243,6 +251,11 @@
                     writer.print(prefix); writer.print("enterAnim="); writer.print(op.enterAnim);
                             writer.print(" exitAnim="); writer.println(op.exitAnim);
                 }
+                if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
+                    writer.print(prefix);
+                            writer.print("popEnterAnim="); writer.print(op.popEnterAnim);
+                            writer.print(" popExitAnim="); writer.println(op.popExitAnim);
+                }
                 if (op.removed != null && op.removed.size() > 0) {
                     for (int i=0; i<op.removed.size(); i++) {
                         writer.print(innerPrefix);
@@ -301,6 +314,8 @@
         }
         op.enterAnim = mEnterAnim;
         op.exitAnim = mExitAnim;
+        op.popEnterAnim = mPopEnterAnim;
+        op.popExitAnim = mPopExitAnim;
         mNumOp++;
     }
 
@@ -430,8 +445,15 @@
     }
 
     public FragmentTransaction setCustomAnimations(int enter, int exit) {
+        return setCustomAnimations(enter, exit, 0, 0);
+    }
+
+    public FragmentTransaction setCustomAnimations(int enter, int exit,
+            int popEnter, int popExit) {
         mEnterAnim = enter;
         mExitAnim = exit;
+        mPopEnterAnim = popEnter;
+        mPopExitAnim = popExit;
         return this;
     }
 
@@ -631,6 +653,7 @@
             switch (op.cmd) {
                 case OP_ADD: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popExitAnim;
                     f.mImmediateActivity = null;
                     mManager.removeFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition),
@@ -638,6 +661,7 @@
                 } break;
                 case OP_REPLACE: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popExitAnim;
                     f.mImmediateActivity = null;
                     mManager.removeFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition),
@@ -645,6 +669,7 @@
                     if (op.removed != null) {
                         for (int i=0; i<op.removed.size(); i++) {
                             Fragment old = op.removed.get(i);
+                            old.mNextAnim = op.popEnterAnim;
                             f.mImmediateActivity = mManager.mActivity;
                             mManager.addFragment(old, false);
                         }
@@ -652,16 +677,19 @@
                 } break;
                 case OP_REMOVE: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popEnterAnim;
                     f.mImmediateActivity = mManager.mActivity;
                     mManager.addFragment(f, false);
                 } break;
                 case OP_HIDE: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popEnterAnim;
                     mManager.showFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
                 } break;
                 case OP_SHOW: {
                     Fragment f = op.fragment;
+                    f.mNextAnim = op.popExitAnim;
                     mManager.hideFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
                 } break;
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 15b873b..c1f3cd6 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -141,10 +141,20 @@
 
     /**
      * Set specific animation resources to run for the fragments that are
-     * entering and exiting in this transaction.
+     * entering and exiting in this transaction. These animations will not be
+     * played when popping the back stack.
      */
     public abstract FragmentTransaction setCustomAnimations(int enter, int exit);
-    
+
+    /**
+     * Set specific animation resources to run for the fragments that are
+     * entering and exiting in this transaction. The <code>popEnter</code>
+     * and <code>popExit</code> animations will be played for enter/exit
+     * operations specifically when popping the back stack.
+     */
+    public abstract FragmentTransaction setCustomAnimations(int enter, int exit,
+            int popEnter, int popExit);
+
     /**
      * Select a standard transition animation for this transaction.  May be
      * one of {@link #TRANSIT_NONE}, {@link #TRANSIT_FRAGMENT_OPEN},
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index a153c0b..b536490 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -69,6 +69,17 @@
     }
 
     /**
+     * Returns the raw USB descriptors for the device.
+     * This can be used to access descriptors not supported directly
+     * via the higher level APIs.
+     *
+     * @return raw USB descriptors
+     */
+    public byte[] getRawDescriptors() {
+        return native_get_desc();
+    }
+
+    /**
      * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
      * This must be done before sending or receiving data on any
      * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface.
@@ -160,6 +171,7 @@
     private native boolean native_open(String deviceName, FileDescriptor pfd);
     private native void native_close();
     private native int native_get_fd();
+    private native byte[] native_get_desc();
     private native boolean native_claim_interface(int interfaceID, boolean force);
     private native boolean native_release_interface(int interfaceID);
     private native int native_control_request(int requestType, int request, int value,
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index d79f6c8..d68e6fb 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -34,10 +34,10 @@
     private final boolean mRemovable;
     private final boolean mEmulated;
     private final int mMtpReserveSpace;
+    private int mStorageId;
 
     public StorageVolume(String path, String description,
-            boolean removable, boolean emulated,
-            int mtpReserveSpace) {
+            boolean removable, boolean emulated, int mtpReserveSpace) {
         mPath = path;
         mDescription = description;
         mRemovable = removable;
@@ -45,6 +45,17 @@
         mMtpReserveSpace = mtpReserveSpace;
     }
 
+    // for parcelling only
+    private StorageVolume(String path, String description,
+            boolean removable, boolean emulated, int mtpReserveSpace, int storageId) {
+        mPath = path;
+        mDescription = description;
+        mRemovable = removable;
+        mEmulated = emulated;
+        mMtpReserveSpace = mtpReserveSpace;
+        mStorageId = storageId;
+    }
+
     /**
      * Returns the mount path for the volume.
      *
@@ -82,6 +93,25 @@
     }
 
     /**
+     * Returns the MTP storage ID for the volume.
+     * this is also used for the storage_id column in the media provider.
+     *
+     * @return MTP storage ID
+     */
+    public int getStorageId() {
+        return mStorageId;
+    }
+
+    /**
+     * Do not call this unless you are MountService
+     */
+    public void setStorageId(int index) {
+        // storage ID is 0x00010001 for primary storage,
+        // then 0x00020001, 0x00030001, etc. for secondary storages
+        mStorageId = ((index + 1) << 16) + 1;
+    }
+
+    /**
      * Number of megabytes of space to leave unallocated by MTP.
      * MTP will subtract this value from the free space it reports back
      * to the host via GetStorageInfo, and will not allow new files to
@@ -123,9 +153,11 @@
             String description = in.readString();
             int removable = in.readInt();
             int emulated = in.readInt();
+            int storageId = in.readInt();
             int mtpReserveSpace = in.readInt();
             return new StorageVolume(path, description,
-                    removable == 1, emulated == 1, mtpReserveSpace);
+                    removable == 1, emulated == 1,
+                    mtpReserveSpace, storageId);
         }
 
         public StorageVolume[] newArray(int size) {
@@ -142,6 +174,7 @@
         parcel.writeString(mDescription);
         parcel.writeInt(mRemovable ? 1 : 0);
         parcel.writeInt(mEmulated ? 1 : 0);
+        parcel.writeInt(mStorageId);
         parcel.writeInt(mMtpReserveSpace);
     }
 }
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index b49fdc5..5da5e44 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -104,9 +104,7 @@
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        final int screen = newConfig.screenLayout;
-        mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
-                Configuration.SCREENLAYOUT_SIZE_XLARGE;
+        mReserveOverflow = newConfig.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
         mMaxItems = getMaxActionButtons();
         mWidthLimit = getResources().getDisplayMetrics().widthPixels / 2;
         if (mMenu != null) {
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index ec36a38..b5d6b91 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -83,6 +83,27 @@
     return usb_device_get_fd(device);
 }
 
+static jbyteArray
+android_hardware_UsbDeviceConnection_get_desc(JNIEnv *env, jobject thiz)
+{
+    char buffer[16384];
+    int fd = android_hardware_UsbDeviceConnection_get_fd(env, thiz);
+    if (fd < 0) return NULL;
+    lseek(fd, 0, SEEK_SET);
+    int length = read(fd, buffer, sizeof(buffer));
+    if (length < 0) return NULL;
+
+    jbyteArray ret = env->NewByteArray(length);
+    if (ret) {
+        jbyte* bytes = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
+        if (bytes) {
+            memcpy(bytes, buffer, length);
+            env->ReleasePrimitiveArrayCritical(ret, bytes, 0);
+        }
+    }
+    return ret;
+}
+
 static jboolean
 android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz,
         int interfaceID, jboolean force)
@@ -211,6 +232,7 @@
                                         (void *)android_hardware_UsbDeviceConnection_open},
     {"native_close",            "()V",  (void *)android_hardware_UsbDeviceConnection_close},
     {"native_get_fd",           "()I",  (void *)android_hardware_UsbDeviceConnection_get_fd},
+    {"native_get_desc",         "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc},
     {"native_claim_interface",  "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},
     {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},
     {"native_control_request",  "(IIII[BII)I",
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
index 6c6252e..32c2c97 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
index 175c750..f1cba06 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
index 6e9abe65..08b163a 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
index f96d09e..77ec017 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
index 1f11f44..029f186 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
index 2e376cd..abaea2d 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
index 73d56b7..acbd7cf 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
index 869decf..8982396 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png
index 736683e..08b163a 100644
--- a/core/res/res/drawable-hdpi/toast_frame.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
index 9471615..cc66804 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
index 0502b93..bc734c8 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
index f364b2e..8603e93 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
index 91c2076..65a318c 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
index 92788c9..e39a472 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
index 74b66f8..68f9e57 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
index f25cfb6..32c49f2 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
index ff3ff06..60aa8cb 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png
index 1b06b7c8..8603e93 100755
--- a/core/res/res/drawable-mdpi/toast_frame.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
new file mode 100644
index 0000000..b33e117
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
new file mode 100644
index 0000000..d84d427
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
new file mode 100644
index 0000000..9c0ff47
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
new file mode 100644
index 0000000..331a4f2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
new file mode 100644
index 0000000..cdc887d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
new file mode 100644
index 0000000..55c60b8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
new file mode 100644
index 0000000..600efb3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
new file mode 100644
index 0000000..d33d033
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png
new file mode 100644
index 0000000..9c0ff47
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/layout-w720dp/action_bar_home.xml b/core/res/res/layout-w720dp/action_bar_home.xml
new file mode 100644
index 0000000..ece1a34
--- /dev/null
+++ b/core/res/res/layout-w720dp/action_bar_home.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+      class="com.android.internal.widget.ActionBarView$HomeView"
+      android:layout_width="wrap_content"
+      android:layout_height="match_parent"
+      android:background="?android:attr/selectableItemBackground" >
+    <ImageView android:id="@android:id/up"
+               android:src="?android:attr/homeAsUpIndicator"
+               android:layout_gravity="center_vertical|left"
+               android:visibility="gone"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_marginRight="-12dip" />
+    <ImageView android:id="@android:id/home"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:paddingLeft="16dip"
+               android:paddingRight="16dip"
+               android:layout_gravity="center"
+               android:scaleType="center" />
+</view>
diff --git a/core/res/res/layout/action_bar_home.xml b/core/res/res/layout/action_bar_home.xml
index c82f91d..a45432a 100644
--- a/core/res/res/layout/action_bar_home.xml
+++ b/core/res/res/layout/action_bar_home.xml
@@ -25,12 +25,12 @@
                android:visibility="gone"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
-               android:layout_marginRight="-12dip" />
+               android:layout_marginRight="-4dip" />
     <ImageView android:id="@android:id/home"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
-               android:paddingLeft="16dip"
-               android:paddingRight="16dip"
+               android:paddingLeft="8dip"
+               android:paddingRight="8dip"
                android:layout_gravity="center"
                android:scaleType="center" />
 </view>
diff --git a/core/res/res/layout/alert_dialog_holo.xml b/core/res/res/layout/alert_dialog_holo.xml
index 57eb9c7..8ee91ca 100644
--- a/core/res/res/layout/alert_dialog_holo.xml
+++ b/core/res/res/layout/alert_dialog_holo.xml
@@ -22,6 +22,8 @@
     android:id="@+id/parentPanel"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:layout_marginLeft="8dip"
+    android:layout_marginRight="8dip"
     android:orientation="vertical">
 
     <LinearLayout android:id="@+id/topPanel"
@@ -42,7 +44,7 @@
             android:layout_height="wrap_content"
             android:orientation="horizontal"
             android:gravity="center_vertical|left"
-            android:minHeight="60dip"
+            android:minHeight="@dimen/alert_dialog_title_height"
             android:layout_marginLeft="32dip"
             android:layout_marginRight="32dip">
             <ImageView android:id="@+id/icon"
@@ -107,7 +109,7 @@
     <LinearLayout android:id="@+id/buttonPanel"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:minHeight="54dip"
+        android:minHeight="@dimen/alert_dialog_button_bar_height"
         android:orientation="vertical"
         android:divider="?android:attr/dividerHorizontal"
         android:showDividers="beginning"
@@ -132,6 +134,7 @@
                 android:layout_weight="1"
                 android:maxLines="2"
                 style="?android:attr/buttonBarButtonStyle"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
                 android:layout_height="wrap_content" />
             <Button android:id="@+id/button3"
                 android:layout_width="0dip"
@@ -139,12 +142,14 @@
                 android:layout_weight="1"
                 android:maxLines="2"
                 style="?android:attr/buttonBarButtonStyle"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
                 android:layout_height="wrap_content" />
             <Button android:id="@+id/button2"
                 android:layout_width="0dip"
                 android:layout_gravity="right"
                 android:layout_weight="1"
                 android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
                 style="?android:attr/buttonBarButtonStyle"
                 android:layout_height="wrap_content" />
             <LinearLayout android:id="@+id/rightSpacer"
diff --git a/core/res/res/values-h720dp/dimens.xml b/core/res/res/values-h720dp/dimens.xml
new file mode 100644
index 0000000..7f43946
--- /dev/null
+++ b/core/res/res/values-h720dp/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Dialog title height -->
+    <dimen name="alert_dialog_title_height">54dip</dimen>
+    <!-- Dialog button bar height -->
+    <dimen name="alert_dialog_button_bar_height">54dip</dimen>
+</resources>
diff --git a/core/res/res/values-large/strings.xml b/core/res/res/values-large/strings.xml
new file mode 100644
index 0000000..e998b9a
--- /dev/null
+++ b/core/res/res/values-large/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Do not translate.  WebView User Agent targeted content -->
+    <string name="web_user_agent_target_content" translatable="false"></string>
+
+</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8a590cd..05840a4 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -76,4 +76,9 @@
 
     <!-- Minimum width of the search view text entry area. -->
     <dimen name="search_view_text_min_width">160dip</dimen>
+
+    <!-- Dialog title height -->
+    <dimen name="alert_dialog_title_height">48dip</dimen>
+    <!-- Dialog button bar height -->
+    <dimen name="alert_dialog_button_bar_height">48dip</dimen>
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 5d054bd..08a3024 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1434,6 +1434,10 @@
     </style>
 
     <style name="Holo.ButtonBar" parent="ButtonBar">
+        <item name="android:paddingTop">0dip</item>
+        <item name="android:paddingLeft">0dip</item>
+        <item name="android:paddingRight">0dip</item>
+        <item name="android:paddingBottom">0dip</item>
         <item name="divider">?android:attr/dividerVertical</item>
         <item name="showDividers">middle</item>
         <item name="dividerPadding">8dip</item>
diff --git a/docs/html/guide/appendix/install-location.jd b/docs/html/guide/appendix/install-location.jd
index 7f96809..617f4fc 100644
--- a/docs/html/guide/appendix/install-location.jd
+++ b/docs/html/guide/appendix/install-location.jd
@@ -171,6 +171,11 @@
     <dd>The system delivers the {@link android.content.Intent#ACTION_BOOT_COMPLETED} broadcast
 before the external storage is mounted to the device. If your application is installed on the
 external storage, it can never receive this broadcast.</dd>
+  <dt>Copy Protection</dt>
+    <dd>Your application cannot be installed to a device's SD card if it uses Android Market's 
+      Copy Protection feature. However, if you use Android Market's 
+      <a href="{@docRoot}guide/publishing/licensing.html">Application Licensing</a> instead, your 
+      application <em>can</em> be installed to internal or external storage, including SD cards.</dd>
 </dl>
 
 <p>If your application uses any of the features listed above, you <strong>should not</strong> allow
diff --git a/docs/html/guide/publishing/licensing.jd b/docs/html/guide/publishing/licensing.jd
index a9b182e..d89a8ca 100644
--- a/docs/html/guide/publishing/licensing.jd
+++ b/docs/html/guide/publishing/licensing.jd
@@ -263,15 +263,15 @@
 you won't be able to upload a new version that uses licensing.</li>
 </ul>
 
-<h4>Replacement for copy protection</h4>
+<h4>Replacement for Copy Protection</h4>
 
 <p>Android Market Licensing is a flexible, secure mechanism for controlling
-access to your applications. It effectively replaces the copy-protection
+access to your applications. It effectively replaces the Copy Protection
 mechanism offered on Android Market and gives you wider distribution
 potential for your applications. </p>
 
 <ul>
-<li>A limitation of the legacy copy-protection mechanism on Android Market is
+<li>A limitation of the legacy Copy Protection mechanism on Android Market is
 that applications using it can be installed only on compatible devices that
 provide a secure internal storage environment. For example, a copy-protected
 application cannot be downloaded from Market to a device that provides root
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index 89306a2..e589292 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -7,7 +7,8 @@
     <ul>
       <li>App Widgets provide users access to some of your application features
 directly from the Home screen (without the need to launch an activity)</li>
-      <li>App Widgets are backed by a special kind of broadcast receiver that handles the App
+      <li>App Widgets are backed by a special kind of broadcast receiver that
+handles the App
 Widget lifecycle</li>
     </ul>
     
@@ -19,15 +20,28 @@
       <li><a href="#CreatingLayout">Creating the App Widget Layout</a></li>
       <li><a href="#AppWidgetProvider">Using the AppWidgetProvider Class</a>
         <ol>
-          <li><a href="#ProviderBroadcasts">Receiving App Widget broadcast Intents</a></li>
+          <li><a href="#ProviderBroadcasts">Receiving App Widget broadcast
+Intents</a></li>
         </ol>
       </li>
-      <li><a href="#Configuring">Creating an App Widget Configuration Activity</a>
+      <li><a href="#Configuring">Creating an App Widget Configuration
+Activity</a>
         <ol>
-          <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget from 
+          <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget
+from 
             the configuration Activity</a></li>
         </ol>
       </li>
+      <li><a href="#preview">Setting a Preview Image</a></li>
+      <li><a href="#collections">Using App Widgets with Collections</a>
+        <ol>
+          <li><a href="#collection_sample">Sample application</a></li>
+          <li><a href="#implementing_collections">Implementing app widgets with
+collections
+</a></li>
+          <li><a href="#fresh">Keeping Collection Data Fresh</a></li>
+        </ol>   
+      </li>
     </ol>
 
     <h2>Key classes</h2>
@@ -39,25 +53,34 @@
     
     <h2>See also</h2>
     <ol>
-      <li><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design 
+      <li><a
+href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
+Design 
         Guidelines</a></li>
-      <li><a href="http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html">Introducing
+      <li><a
+href="http://android-developers.blogspot.com/2009/04/introducing-home-screen-
+widgets-and.html">Introducing
         home screen widgets and the AppWidget framework &raquo;</a></li>
     </ol>
   </div>
 </div>
 
 
-<p>App Widgets are miniature application views that can be embedded in other applications
-(such as the Home screen) and receive periodic updates. These views are referred 
+<p>App Widgets are miniature application views that can be embedded in other
+applications
+(such as the Home screen) and receive periodic updates. These views are
+referred 
 to as Widgets in the user interface,
-and you can publish one with an App Widget provider. An application component that is 
-able to hold other App Widgets is called an App Widget host. The screenshot below shows
+and you can publish one with an App Widget provider. An application component
+that is 
+able to hold other App Widgets is called an App Widget host. The screenshot
+below shows
 the Music App Widget.</p>
 
 <img src="{@docRoot}images/appwidget.png" alt="" />
 
-<p>This document describes how to publish an App Widget using an App Widget provider.</p>
+<p>This document describes how to publish an App Widget using an App Widget
+provider.</p>
 
 
 <h2 id="Basics">The Basics</h2>
@@ -66,18 +89,23 @@
 
 <dl>
   <dt>{@link android.appwidget.AppWidgetProviderInfo} object</dt>
-  <dd>Describes the metadata for an App Widget, such as the App Widget's layout, update frequency,
+  <dd>Describes the metadata for an App Widget, such as the App Widget's layout,
+update frequency,
     and the AppWidgetProvider class. This should be defined in XML.</dd>
   <dt>{@link android.appwidget.AppWidgetProvider} class implementation</dt>
-  <dd>Defines the basic methods that allow you to programmatically interface with the App Widget,
-    based on broadcast events. Through it, you will receive broadcasts when the App Widget is updated, 
+  <dd>Defines the basic methods that allow you to programmatically interface
+with the App Widget,
+    based on broadcast events. Through it, you will receive broadcasts when the
+App Widget is updated, 
     enabled, disabled and deleted.</dd>
   <dt>View layout</dt>
   <dd>Defines the initial layout for the App Widget, defined in XML.</dd>
 </dl>
 
-<p>Additionally, you can implement an App Widget configuration Activity. This is an optional 
-{@link android.app.Activity} that launches when the user adds your App Widget and allows him or her
+<p>Additionally, you can implement an App Widget configuration Activity. This is
+an optional 
+{@link android.app.Activity} that launches when the user adds your App Widget
+and allows him or her
 to modify App Widget settings at create-time.</p>
 
 <p>The following sections describe how to setup each of these components.</p>
@@ -85,7 +113,8 @@
 
 <h2 id="Manifest">Declaring an App Widget in the Manifest</h2>
 
-<p>First, declare the {@link android.appwidget.AppWidgetProvider} class in your application's
+<p>First, declare the {@link android.appwidget.AppWidgetProvider} class in your
+application's
 <code>AndroidManifest.xml</code> file. For example:</p>
 
 <pre>
@@ -98,24 +127,32 @@
 &lt;/receiver>
 </pre>
 
-<p>The <code>&lt;receiver&gt;</code> element requires the <code>android:name</code> 
+<p>The <code>&lt;receiver&gt;</code> element requires the
+<code>android:name</code> 
 attribute, which specifies the {@link android.appwidget.AppWidgetProvider} used
 by the App Widget.</p>
 
-<p>The <code>&lt;intent-filter&gt;</code> element must include an <code>&lt;action></code>
+<p>The <code>&lt;intent-filter&gt;</code> element must include an
+<code>&lt;action></code>
 element with the <code>android:name</code> attribute. This attribute specifies
 that the {@link android.appwidget.AppWidgetProvider} accepts the {@link
-android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE ACTION_APPWIDGET_UPDATE} broadcast.
-This is the only broadcast that you must explicitly declare. The {@link android.appwidget.AppWidgetManager}
-automatically sends all other App Widget broadcasts to the AppWidgetProvider as necessary.</p>
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE
+ACTION_APPWIDGET_UPDATE} broadcast.
+This is the only broadcast that you must explicitly declare. The {@link
+android.appwidget.AppWidgetManager}
+automatically sends all other App Widget broadcasts to the AppWidgetProvider as
+necessary.</p>
 
 <p>The <code>&lt;meta-data&gt;</code> element specifies the
 {@link android.appwidget.AppWidgetProviderInfo} resource and requires the 
 following attributes:</p>
 <ul>
-  <li><code>android:name</code> - Specifies the metadata name. Use <code>android.appwidget.provider</code>
-    to identify the data as the {@link android.appwidget.AppWidgetProviderInfo} descriptor.</li>
-  <li><code>android:resource</code> - Specifies the {@link android.appwidget.AppWidgetProviderInfo} 
+  <li><code>android:name</code> - Specifies the metadata name. Use
+<code>android.appwidget.provider</code>
+    to identify the data as the {@link android.appwidget.AppWidgetProviderInfo}
+descriptor.</li>
+  <li><code>android:resource</code> - Specifies the {@link
+android.appwidget.AppWidgetProviderInfo} 
     resource location.</li>
 </ul>
 
@@ -123,10 +160,13 @@
 <h2 id="MetaData">Adding the AppWidgetProviderInfo Metadata</h2>
 
 <p>The {@link android.appwidget.AppWidgetProviderInfo} defines the essential 
-qualities of an App Widget, such as its minimum layout dimensions, its initial layout resource,
-how often to update the App Widget, and (optionally) a configuration Activity to launch at create-time.
+qualities of an App Widget, such as its minimum layout dimensions, its initial
+layout resource,
+how often to update the App Widget, and (optionally) a configuration Activity to
+launch at create-time.
 Define the AppWidgetProviderInfo object in an XML resource using a single
-<code>&lt;appwidget-provider></code> element and save it in the project's <code>res/xml/</code> 
+<code>&lt;appwidget-provider></code> element and save it in the project's
+<code>res/xml/</code> 
 folder.</p>
 
 <p>For example:</p>
@@ -136,71 +176,131 @@
     android:minWidth="294dp"
     android:minHeight="72dp"
     android:updatePeriodMillis="86400000"
+    android:previewImage="@drawable/preview"
     android:initialLayout="@layout/example_appwidget"
-    android:configure="com.example.android.ExampleAppWidgetConfigure" >
+    android:configure="com.example.android.ExampleAppWidgetConfigure" 
+    android:resizeMode="horizontal|vertical">
 &lt;/appwidget-provider>
 </pre>
 
 <p>Here's a summary of the <code>&lt;appwidget-provider></code> attributes:</p>
 <ul>
-  <li>The values for the <code>minWidth</code> and <code>minHeight</code> attributes specify the minimum
-    area required by the App Widget's layout.
-    <p>The default Home screen positions App Widgets in its window based on a grid of
-    cells that have a defined height and width. If the values for an App Widget's minimum width 
+  <li>The values for the <code>minWidth</code> and <code>minHeight</code>
+attributes specify the minimum
+    area required by the App Widget's layout. 
+    <p>The default Home screen positions App Widgets in its window based on a
+grid of
+    cells that have a defined height and width. If the values for an App
+Widget's minimum width 
     or height don't match the dimensions of the cells,
     then the App Widget dimensions round <em>up</em> to the nearest cell size.
-    (See the <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design 
+    (See the <a
+href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
+Design 
     Guidelines</a> for more information on the Home screen cell sizes.)</p>
-    <p>Because the Home screen's layout orientation (and thus, the cell sizes) can change,
-    as a rule of thumb, you should assume the worst-case cell size of 74 pixels for the height
-    <em>and</em> width of a cell. However, you must subtract 2 from the final dimension to account
-    for any integer rounding errors that occur in the pixel count. To find your minimum width
+    <p>Because the Home screen's layout orientation (and thus, the cell sizes)
+can change,
+    as a rule of thumb, you should assume the worst-case cell size of 74 pixels
+for the height
+    <em>and</em> width of a cell. However, you must subtract 2 from the final
+dimension to account
+    for any integer rounding errors that occur in the pixel count. To find your
+minimum width
     and height in density-independent pixels (dp), use this formula:<br/>
       <code>(number of cells * 74) - 2</code><br/>
-    Following this formula, you should use 72 dp for a height of one cell, 294 dp and for a width of four cells.</p>
+    Following this formula, you should use 72 dp for a height of one cell, 294
+dp and for a width of four cells.</p>
+<p class="note"><strong>Note:</strong> To make your app widget portable across
+devices, your app widget's minimum size should never be larger than 4 x 4 cells.
+See the <a
+href="{@docRoot}guide/practices/ui_guidelines/widget_design.htmll#sizes">App
+Widget Design Guidelines</a> for more discussion of Home screen cell sizes.</p>
   </li>
-  <li>The <code>updatePeriodMillis</code> attribute defines how often the App Widget framework should
-    request an update from the {@link android.appwidget.AppWidgetProvider} by calling the
-    {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-    onUpdate()} method. The actual update is not guaranteed to occur exactly on time with this value
-    and we suggest updating as infrequently as possible&mdash;perhaps no more than once an hour to 
-    conserve the battery. You might also allow the user to adjust the frequency in a 
-    configuration&mdash;some people might want a stock ticker to update every 15 minutes, or maybe 
-    only four times a day. 
-    	<p class="note"><strong>Note:</strong> If the device is asleep when it is time for an update 
-    	(as defined by <code>updatePeriodMillis</code>), then the device will wake up in order 
-    	to perform the update. If you don't update more than once per hour, this probably won't 
-    	cause significant problems for the battery life. If, however, you need to update more 
-    	frequently and/or you do not need to update while the device is asleep, then you can instead 
-    	perform updates based on an alarm that will not wake the device. To do so, set an alarm with 
-    	an Intent that your AppWidgetProvider receives, using the	{@link android.app.AlarmManager}. 
-    	Set the alarm type to either {@link android.app.AlarmManager#ELAPSED_REALTIME} or 
+  <li>The <code>updatePeriodMillis</code> attribute defines how often the App
+Widget framework should request an update from the {@link
+android.appwidget.AppWidgetProvider} by calling the 
+{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()} 
+callback method. The actual update
+is not guaranteed to occur exactly on time with this value and we suggest
+updating as infrequently as possible&mdash;perhaps no more than once an hour to
+conserve the battery. You might also allow the user to adjust the frequency in a
+configuration&mdash;some people might want a stock ticker to update every 15
+minutes, or maybe only four times a day. 
+    	<p class="note"><strong>Note:</strong> If the device is asleep when it
+is time for an update 
+    	(as defined by <code>updatePeriodMillis</code>), then the device will
+wake up in order 
+    	to perform the update. If you don't update more than once per hour, this
+probably won't 
+    	cause significant problems for the battery life. If, however, you need
+to update more 
+    	frequently and/or you do not need to update while the device is asleep,
+then you can instead 
+    	perform updates based on an alarm that will not wake the device. To do
+so, set an alarm with 
+    	an Intent that your AppWidgetProvider receives, using the	{@link
+android.app.AlarmManager}. 
+    	Set the alarm type to either {@link
+android.app.AlarmManager#ELAPSED_REALTIME} or 
     	{@link android.app.AlarmManager#RTC}, which will only
-    	deliver the alarm when the device is awake. Then set <code>updatePeriodMillis</code> to 
+    	deliver the alarm when the device is awake. Then set
+<code>updatePeriodMillis</code> to 
     	zero (<code>"0"</code>).</p>
   </li>
-  <li>The <code>initialLayout</code> attribute points to the layout resource that defines the
+  <li>The <code>initialLayout</code> attribute points to the layout resource
+that defines the
     App Widget layout.</li>
-  <li>The <code>configure</code> attribute defines the {@link android.app.Activity} to launch when
-    the user adds the App Widget, in order for him or her to configure App Widget properties. This is optional
-    (read <a href="#Configuring">Creating an App Widget Configuration Activity</a> below).</li>
-</ul>
+  <li>The <code>configure</code> attribute defines the {@link
+android.app.Activity} to launch when
+    the user adds the App Widget, in order for him or her to configure App
+Widget properties. This is optional
+    (read <a href="#Configuring">Creating an App Widget Configuration
+Activity</a> below).</li>
+    
+   <li>The <code>previewImage</code> attribute specifies a preview of what the
+app widget will look like after it's configured, which the user sees when
+selecting the app widget. If not supplied, the user instead sees your
+application's launcher icon. This field corresponds to the
+<code>android:previewImage</code> attribute in the <code>&lt;receiver&gt;</code>
+element in the <code>AndroidManifest.xml</code> file. For more discussion of
+using <code>previewImage</code>, see <a href="#preview">Setting a Preview
+Image</a>. Introduced in Android 3.0.</li>
 
-<p>See the {@link android.appwidget.AppWidgetProviderInfo} class for more information on the
+   <li>The <code>autoAdvanceViewId</code> attribute specifies the view ID of the
+app widget subview that should be auto-advanced by the widget's host. Introduced in Android 3.0.</li> 
+
+<li>The <code>resizeMode</code> attribute specifies the rules by which a widget
+can be resized. You use this attribute to make homescreen widgets
+resizeable&mdash;horizontally, vertically, or on both axes. Users touch-hold a
+widget to show its resize handles, then drag the horizontal and/or vertical
+handles to change the size on the layout grid. Values for the
+<code>resizeMode</code> attribute include "horizontal", "vertical", and "none".
+To declare a widget as resizeable horizontally and vertically, supply the value
+"horizontal|vertical". Introduced in Android 3.1.</li> </ul>
+
+<p>See the {@link android.appwidget.AppWidgetProviderInfo} class for more
+information on the
 attributes accepted by the <code>&lt;appwidget-provider></code> element.</p>
 
 
 <h2 id="CreatingLayout">Creating the App Widget Layout</h2>
 
-<p>You must define an initial layout for your App Widget in XML and save it in the project's
-<code>res/layout/</code> directory. You can design your App Widget using the View objects listed
-below, but before you begin designing your App Widget, please read and understand the
-<a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design 
+<p>You must define an initial layout for your App Widget in XML and save it in
+the project's
+<code>res/layout/</code> directory. You can design your App Widget using the
+View objects listed
+below, but before you begin designing your App Widget, please read and
+understand the
+<a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
+Design 
 Guidelines</a>.</p>
 
 <p>Creating the App Widget layout is simple if you're
-familiar with <a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout in XML</a>.
-However, you must be aware that App Widget layouts are based on {@link android.widget.RemoteViews},
+familiar with <a
+href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout in
+XML</a>.
+However, you must be aware that App Widget layouts are based on {@link
+android.widget.RemoteViews},
 which do not support every kind of layout or view widget.</p>
 
 <p>A RemoteViews object (and, consequently, an App Widget) can support the 
@@ -221,6 +321,7 @@
   <li>{@link android.widget.ImageView}</li>
   <li>{@link android.widget.ProgressBar}</li>
   <li>{@link android.widget.TextView}</li>
+  <li>{@link android.widget.ViewFlipper}</li>
 </ul>
 
 <p>Descendants of these classes are not supported.</p>
@@ -230,66 +331,90 @@
 
 <div class="sidebox-wrapper">
 <div class="sidebox">
-    <p>You must declare your AppWidgetProvider class implementation as a broadcast receiver 
+    <p>You must declare your AppWidgetProvider class implementation as a
+broadcast receiver 
     using the <code>&lt;receiver></code> element in the AndroidManifest (see
     <a href="#Manifest">Declaring an App Widget in the Manifest</a> above).</p>
   </div>
 </div>
 
-<p>The {@link android.appwidget.AppWidgetProvider} class extends BroadcastReceiver as a convenience
-class to handle the App Widget broadcasts. The AppWidgetProvider receives only the event broadcasts that
-are relevant to the App Widget, such as when the App Widget is updated, deleted, enabled, and disabled.
-When these broadcast events occur, the AppWidgetProvider receives the following method calls:</p>
+<p>The {@link android.appwidget.AppWidgetProvider} class extends
+BroadcastReceiver as a convenience
+class to handle the App Widget broadcasts. The AppWidgetProvider receives only
+the event broadcasts that
+are relevant to the App Widget, such as when the App Widget is updated, deleted,
+enabled, and disabled.
+When these broadcast events occur, the AppWidgetProvider receives the following
+method calls:</p>
 
 <dl>
-  <dt>{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])}</dt>
-    <dd>This is called to update the App Widget at intervals defined by the <code>updatePeriodMillis</code>
+  <dt>
+  {@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()} 
+</dt>
+    <dd>This is called to update the App Widget at intervals defined by the
+<code>updatePeriodMillis</code>
     attribute in the AppWidgetProviderInfo (see <a href="#MetaData">Adding the 
     AppWidgetProviderInfo Metadata</a> above). This method is also called
     when the user adds the App Widget, so it should perform the essential setup,
     such as define event handlers for Views and start a temporary
-    {@link android.app.Service}, if necessary. However, if you have declared a configuration
-    Activity, <strong>this method is not called</strong> when the user adds the App Widget,
+    {@link android.app.Service}, if necessary. However, if you have declared a
+configuration
+    Activity, <strong>this method is not called</strong> when the user adds the
+App Widget,
     but is called for the subsequent updates. It is the responsibility of the 
-    configuration Activity to perform the first update when configuration is done.
-    (See <a href="#Configuring">Creating an App Widget Configuration Activity</a> below.)</dd> 
+    configuration Activity to perform the first update when configuration is
+done.
+    (See <a href="#Configuring">Creating an App Widget Configuration
+Activity</a> below.)</dd> 
   <dt>{@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}</dt>
-    <dd>This is called every time an App Widget is deleted from the App Widget host.</dd>
+    <dd>This is called every time an App Widget is deleted from the App Widget
+host.</dd>
   <dt>{@link android.appwidget.AppWidgetProvider#onEnabled(Context)}</dt>
-    <dd>This is called when an instance the App Widget is created for the first time. For example, if the user 
+    <dd>This is called when an instance the App Widget is created for the first
+time. For example, if the user 
     adds two instances of your App Widget, this is only called the first time.
-    If you need to open a new database or perform other setup that only needs to occur once 
+    If you need to open a new database or perform other setup that only needs to
+occur once 
     for all App Widget instances, then this is a good place to do it.</dd> 
   <dt>{@link android.appwidget.AppWidgetProvider#onDisabled(Context)}</dt>
-    <dd>This is called when the last instance of your App Widget is deleted from the App Widget host. 
+    <dd>This is called when the last instance of your App Widget is deleted from
+the App Widget host. 
     This is where you should clean up any work done in 
     {@link android.appwidget.AppWidgetProvider#onEnabled(Context)}, 
     such as delete a temporary database.</dd> 
   <dt>{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)}</dt>
-    <dd>This is called for every broadcast and before each of the above callback methods.
-    You normally don't need to implement this method because the default AppWidgetProvider 
+    <dd>This is called for every broadcast and before each of the above callback
+methods.
+    You normally don't need to implement this method because the default
+AppWidgetProvider 
     implementation filters all App Widget broadcasts and calls the above 
     methods as appropriate.</dd> 
 </dl>
 
-<p class="warning"><strong>Note:</strong> In Android 1.5, there is a known issue in which the
-<code>onDeleted()</code> method will not be called when it should be. To work around this issue, 
-you can implement {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)
+<p class="warning"><strong>Note:</strong> In Android 1.5, there is a known issue
+in which the
+<code>onDeleted()</code> method will not be called when it should be. To work
+around this issue, 
+you can implement {@link
+android.appwidget.AppWidgetProvider#onReceive(Context,Intent)
 onReceive()} as described in this 
-<a href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2">Group post</a>
+<a
+href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2">
+Group post</a>
 to receive the <code>onDeleted()</code> callback.
 </p>
 
 <p>The most important AppWidgetProvider callback is 
-{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-onUpdated()} because it is called when each App Widget is added to a host (unless you use
-a configuration Activity). If your App Widget accepts any
-user interaction events, then you need to register the event handlers in this callback.
-If your App Widget doesn't create temporary
-files or databases, or perform other work that requires clean-up, then
-{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-onUpdated()} may be the only callback method you need to define. For example, if you want an App Widget
-with a button that launches an Activity when clicked, you could use the following
+{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 
+because it is called when
+each App Widget is added to a host (unless you use a configuration Activity). If
+your App Widget accepts any user interaction events, then you need to register
+the event handlers in this callback. If your App Widget doesn't create temporary
+files or databases, or perform other work that requires clean-up, then 
+{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 
+may be the only callback
+method you need to define. For example, if you want an App Widget with a button
+that launches an Activity when clicked, you could use the following
 implementation of AppWidgetProvider:</p>
 
 <pre>
@@ -306,11 +431,12 @@
             Intent intent = new Intent(context, ExampleActivity.class);
             PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
 
-            // Get the layout for the App Widget and attach an on-click listener to the button
+            // Get the layout for the App Widget and attach an on-click listener
+            // to the button
             RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
             views.setOnClickPendingIntent(R.id.button, pendingIntent);
 
-            // Tell the AppWidgetManager to perform an update on the current App Widget
+            // Tell the AppWidgetManager to perform an update on the current app widget
             appWidgetManager.updateAppWidget(appWidgetId, views);
         }
     }
@@ -318,43 +444,51 @@
 </pre>
 
 <p>This AppWidgetProvider defines only the 
-{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-onUpdated()} method for the purpose
-of defining a {@link android.app.PendingIntent} that launches an {@link android.app.Activity}
-and attaching it to the App Widget's button
-with {@link android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}.
-Notice that it includes a loop that iterates through each entry in <code>appWidgetIds</code>, which
-is an array of IDs that identify each App Widget created by this provider.
-In this way, if the user creates more than one instance of the App Widget, then they are
-all updated simultaneously. However, only one <code>updatePeriodMillis</code> schedule will be 
-managed for all instances of the App Widget. For example, if the update schedule is defined 
-to be every two hours, and a second instance 
-of the App Widget is added one hour after the first one, then they will both be updated 
-on the period defined by the first one and the second update period will be ignored 
-(they'll both be updated every two hours, not every hour).</p>
+{@link
+android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 
+method for the purpose of
+defining a {@link android.app.PendingIntent} that launches an {@link
+android.app.Activity} and attaching it to the App Widget's button with {@link
+android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}. Notice
+that it includes a loop that iterates through each entry in
+<code>appWidgetIds</code>, which is an array of IDs that identify each App
+Widget created by this provider. In this way, if the user creates more than one
+instance of the App Widget, then they are all updated simultaneously. However,
+only one <code>updatePeriodMillis</code> schedule will be managed for all
+instances of the App Widget. For example, if the update schedule is defined to
+be every two hours, and a second instance of the App Widget is added one hour
+after the first one, then they will both be updated on the period defined by the
+first one and the second update period will be ignored (they'll both be updated
+every two hours, not every hour).</p>
 
-<p class="note"><strong>Note:</strong> Because {@link android.appwidget.AppWidgetProvider} is an
-extension of {@link android.content.BroadcastReceiver}, your process is not guaranteed to keep
-running after the callback methods return (see {@link android.content.BroadcastReceiver} for
-information about the broadcast lifecycle). If your App Widget setup process can take several
-seconds (perhaps while performing web requests) and you require that your process continues, 
-consider starting a {@link android.app.Service} 
-in the {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-onUpdated()} method. From within the Service, you can perform your own updates to the App Widget
-without worrying about the AppWidgetProvider closing down due to an 
-<a href="{@docRoot}guide/practices/design/responsiveness.html">Application Not Responding</a> 
-(ANR) error. See the
-<a href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary/src/com/example/android/wiktionary/WordWidget.java">Wiktionary
-sample's AppWidgetProvider</a> for an example of an App Widget running a {@link android.app.Service}.</p>
+<p class="note"><strong>Note:</strong> Because {@link
+android.appwidget.AppWidgetProvider} is an extension of {@link
+android.content.BroadcastReceiver}, your process is not guaranteed to keep
+running after the callback methods return (see {@link
+android.content.BroadcastReceiver} for information about the broadcast
+lifecycle). If your App Widget setup process can take several seconds (perhaps
+while performing web requests) and you require that your process continues,
+consider starting a {@link android.app.Service} in the 
+{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 
+method. From within the Service, you can perform your own updates
+to the App Widget without worrying about the AppWidgetProvider closing down due
+to an <a href="{@docRoot}guide/practices/design/responsiveness.html">Application
+Not Responding</a> (ANR) error. See the <a
+href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary
+/src/com/example/android/wiktionary/WordWidget.java">Wiktionary sample's
+AppWidgetProvider</a> for an example of an App Widget running a {@link
+android.app.Service}.</p>
 
 <p>Also see the <a 
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.html">
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/
+appwidget/ExampleAppWidgetProvider.html">
 ExampleAppWidgetProvider.java</a> sample class.</p>
 
 
 <h3 id="ProviderBroadcasts">Receiving App Widget broadcast Intents</h3>
 
-<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class.  If you would like
+<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class.  If
+you would like
 to receive the App Widget broadcasts directly, you can implement your own 
 {@link android.content.BroadcastReceiver} or override the 
 {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback. 
@@ -370,28 +504,36 @@
 
 <h2 id="Configuring">Creating an App Widget Configuration Activity</h2>
 
-<p>If you would like the user to configure settings when he or she adds a new App Widget,
-you can create an App Widget configuration Activity. This {@link android.app.Activity} 
-will be automatically launched by the App Widget host and allows the user to configure
-available settings for the App Widget at create-time, such as the App Widget color, size, 
+<p>If you would like the user to configure settings when he or she adds a new
+App Widget,
+you can create an App Widget configuration Activity. This {@link
+android.app.Activity} 
+will be automatically launched by the App Widget host and allows the user to
+configure
+available settings for the App Widget at create-time, such as the App Widget
+color, size, 
 update period or other functionality settings.</p>
 
-<p>The configuration Activity should be declared as a normal Activity in the Android manifest file.
+<p>The configuration Activity should be declared as a normal Activity in the
+Android manifest file.
 However, it will be launched by the App Widget host with the {@link
-android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE ACTION_APPWIDGET_CONFIGURE} action,
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE
+ACTION_APPWIDGET_CONFIGURE} action,
 so the Activity needs to accept this Intent. For example:</p>
 
 <pre>
 &lt;activity android:name=".ExampleAppWidgetConfigure">
     &lt;intent-filter>
-        &lt;action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
+        &lt;action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
     &lt;/intent-filter>
 &lt;/activity>
 </pre>
 
-<p>Also, the Activity must be declared in the AppWidgetProviderInfo XML file, with the 
+<p>Also, the Activity must be declared in the AppWidgetProviderInfo XML file,
+with the 
 <code>android:configure</code> attribute (see <a href="#MetaData">Adding 
-the AppWidgetProviderInfo Metadata</a> above). For example, the configuration Activity
+the AppWidgetProviderInfo Metadata</a> above). For example, the configuration
+Activity
 can be declared like this:</p>
 
 <pre>
@@ -402,32 +544,45 @@
 &lt;/appwidget-provider>
 </pre>
 
-<p>Notice that the Activity is declared with a fully-qualified namespace, because 
+<p>Notice that the Activity is declared with a fully-qualified namespace,
+because 
 it will be referenced from outside your package scope.</p>
 
-<p>That's all you need to get started with a configuration Activity. Now all you need is the actual
-Activity. There are, however, two important things to remember when you implement the Activity:</p>
+<p>That's all you need to get started with a configuration Activity. Now all you
+need is the actual
+Activity. There are, however, two important things to remember when you
+implement the Activity:</p>
 <ul>
-  <li>The App Widget host calls the configuration Activity and the configuration Activity should always 
+  <li>The App Widget host calls the configuration Activity and the configuration
+Activity should always 
     return a result. The result should include the App Widget ID
-    passed by the Intent that launched the Activity (saved in the Intent extras as
+    passed by the Intent that launched the Activity (saved in the Intent extras
+as
     {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}).</li>
-  <li>The {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-    onUpdate()} method <strong>will not be called</strong> when the App Widget is created
-    (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a configuration Activity
-    is launched). It is the responsibility of the configuration Activity to request an update from the 
+  <li>The 
+  {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 
+    method <strong>will not be called</strong> when the App Widget
+is created
+    (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a
+configuration Activity
+    is launched). It is the responsibility of the configuration Activity to
+request an update from the 
     AppWidgetManager when the App Widget is first created. However, 
-    {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-    onUpdate()} will be called for subsequent updates&mdash;it is only skipped the first time.</li>
+{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 
+    will be called for subsequent updates&mdash;it is only skipped
+the first time.</li>
 </ul>
 
-<p>See the code snippets in the following section for an example of how to return a result
+<p>See the code snippets in the following section for an example of how to
+return a result
 from the configuration and update the App Widget.</p>
 
 
-<h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the configuration Activity</h3>
+<h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the
+configuration Activity</h3>
 
-<p>When an App Widget uses a configuration Activity, it is the responsibility of the Activity
+<p>When an App Widget uses a configuration Activity, it is the responsibility of
+the Activity
 to update the App Widget when configuration is complete. 
 You can do so by requesting an update directly from the 
 {@link android.appwidget.AppWidgetManager}.</p>
@@ -448,20 +603,24 @@
 </pre>
   </li>
   <li>Perform your App Widget configuration.</li>
-  <li>When the configuration is complete, get an instance of the AppWidgetManager by calling
+  <li>When the configuration is complete, get an instance of the
+AppWidgetManager by calling
     {@link android.appwidget.AppWidgetManager#getInstance(Context)}:
 <pre>
 AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
 </pre>
   </li>
-  <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by calling
+  <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by
+calling
     {@link android.appwidget.AppWidgetManager#updateAppWidget(int,RemoteViews)}:
 <pre>
-RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
+RemoteViews views = new RemoteViews(context.getPackageName(),
+R.layout.example_appwidget);
 appWidgetManager.updateAppWidget(mAppWidgetId, views);
 </pre>
   </li>
-  <li>Finally, create the return Intent, set it with the Activity result, and finish the Activity:</li>
+  <li>Finally, create the return Intent, set it with the Activity result, and
+finish the Activity:</li>
 <pre>
 Intent resultValue = new Intent();
 resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
@@ -471,14 +630,657 @@
   </li>
 </ol>
 
-<p class="note"><strong>Tip:</strong> When your configuration Activity first opens, set
-the Activity result to RESULT_CANCELED. This way, if the user backs-out of the Activity before
-reaching the end, the App Widget host is notified that the configuration was cancelled and the
+<p class="note"><strong>Tip:</strong> When your configuration Activity first
+opens, set
+the Activity result to RESULT_CANCELED. This way, if the user backs-out of the
+Activity before
+reaching the end, the App Widget host is notified that the configuration was
+cancelled and the
 App Widget will not be added.</p>
 
 <p>See the <a 
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.html">
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/
+appwidget/ExampleAppWidgetConfigure.html">
 ExampleAppWidgetConfigure.java</a> sample class in ApiDemos for an example.</p>
 
+<h2 id="preview">Setting a Preview Image</h2>
+
+<p>Android 3.0 introduces the {@link
+
+
+android.appwidget.AppWidgetProviderInfo#previewImage} field, which specifies a
+preview of what the app widget looks like. This preview is shown to the user from the
+widget picker. If this field is not supplied, the app widget's icon is used for
+the preview.</p> 
+
+<p>This is how you specify this setting in XML:</p>
+
+<pre>&lt;appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+  ...
+  android:previewImage="@drawable/preview">
+&lt;/appwidget-provider></pre>
+
+<p>To help create a preview image for your app widget (to specify in the {@link
+android.appwidget.AppWidgetProviderInfo#previewImage} field), the Android
+emulator includes an application called &quot;Widget Preview.&quot; To create a
+preview image, launch this application, select the app widget for your
+application and set it up how you'd like your preview image to appear, then save
+it and place it in your application's drawable resources.</p>
+
+<h2 id="collections">Using App Widgets with Collections</h2>
+
+<p>Android 3.0 introduces App Widgets with collections. These kinds of App
+Widgets use the {@link android.widget.RemoteViewsService} to display collections
+that are backed by remote data, such as from a <a
+href="{@docRoot}guide/topics/providers/content-providers.html">content
+provider</a>. The data provided by the {@link android.widget.RemoteViewsService}
+is presented in the App Widget using one of the following view types, which
+we’ll refer to as “collection views:”</p>
+
+<dl>
+  <dt>{@link android.widget.ListView}</dt>
+  <dd>A view that shows items in a
+vertically scrolling
+list. For an example, see the Gmail app widget. </dd>
+<dt>{@link android.widget.GridView}</dt>
+<dd>A view that shows items in
+two-dimensional scrolling grid. For an example, see the Bookmarks app
+widget.</dd> 
+<dt>{@link android.widget.StackView}</dt>
+<dd>A
+stacked card view (kind of like a rolodex), where the user can flick the  front
+card up/down to see the previous/next card, respectively.  Examples include
+the YouTube and Books app widgets. </dd> 
+<dt>{@link android.widget.AdapterViewFlipper}</dt>
+<dd>An adapter-backed simple
+{@link
+android.widget.ViewAnimator} that  animates between two or more views. Only one
+child is shown at a time.  </dd>
+</dl>
+
+<p>As stated above, these collection views display collections backed by remote
+data. This means that they use an {@link android.widget.Adapter} to bind their
+user interface to their data. An {@link android.widget.Adapter} binds individual
+items from a set of data into individual {@link android.view.View} objects.
+Because these collection views are backed by adapters, the Android framework
+must include extra architecture to support their use in app widgets. In the
+context of an app widget, the {@link android.widget.Adapter} is replaced by a
+{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory},
+which is simply a thin wrapper around  the {@link android.widget.Adapter}
+interface. 
+ When
+requested for a specific item in the collection, the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} creates
+and returns the item for the collection as a {@link android.widget.RemoteViews}
+object.
+In order to include a collection view in your app widget, you
+must implement {@link android.widget.RemoteViewsService} and {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}.</p>
+
+<p> {@link android.widget.RemoteViewsService} is a service that allows a remote
+adapter to request {@link
+android.widget.RemoteViews} objects. {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} is an
+interface for an adapter between a collection view (such as {@link
+android.widget.ListView}, {@link android.widget.GridView}, and so on) and the
+underlying data for that view. From the  <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a>, here is an example of the boilerplate code you use to implement 
+this service and interface:
+</p>
+
+<pre>
+public class StackWidgetService extends RemoteViewsService {
+    &#64;Override
+    public RemoteViewsFactory onGetViewFactory(Intent intent) {
+        return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
+    }
+}
+
+class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
+
+//... include adapter-like methods here. See the StackView Widget sample.
+
+}
+</pre>
+
+<h3 id="collection_sample">Sample application</h3>
+
+<p>The code excerpts in this section are drawn from the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a>:</p>
+
+<p>
+<img src="{@docRoot}resources/samples/images/StackWidget.png" alt="StackView
+Widget" />
+</p>
+
+<p>This sample consists of a stack of 10 views, which  display the values
+<code>&quot;0!&quot;</code> through <code>&quot;9!&quot;</code> The sample
+app widget has these primary behaviors:</p> 
+
+<ul>
+
+  <li>The user can vertically fling the top view in the
+app widget to display the next or previous view. This is a built-in StackView
+behavior.</li> 
+
+  <li>Without any user interaction, the app widget automatically advances
+through
+its views in sequence, like a slide show. This is due to the setting
+<code>android:autoAdvanceViewId=&quot;@id/stack_view&quot;</code> in the
+<code>res/xml/stackwidgetinfo.xml</code> file. This setting applies to the view
+ID,
+which in this case is the view ID of the stack view.</li>
+  
+  <li>If the user touches the top view, the app widget displays the {@link
+android.widget.Toast} message &quot;Touched view <em>n</em>,&quot; where
+<em>n</em> is the index (position) of the touched view. For more discussion of
+how this is implemented, see  
+<a href="#behavior">Adding behavior to individual items</a>.</li>
+
+</ul>
+<h3 id="implementing_collections">Implementing app widgets with collections</h3>
+
+<p>To implement an App Widget with collections, you follow the same basic steps 
+you would use to implement any app widget. The following sections  describe the
+additional steps you need to perform to implement an App Widget with
+collections.</p>
+
+<h4>Manifest for app widgets with collections</h4>
+
+<p> In addition to the requirements listed in <a href="#Manifest">Declaring an
+App Widget in the Manifest</a>, to make it possible for App Widgets with
+collections to bind to your {@link android.widget.RemoteViewsService}, you must
+declare the service in your manifest file with the permission {@link
+android.Manifest.permission#BIND_REMOTEVIEWS}. This prevents other applications
+from freely accessing your app widget's data. For example, when creating an App
+Widget that uses {@link android.widget.RemoteViewsService} to populate a
+collection view, the manifest entry may look like this:</p>
+
+<pre>&lt;service android:name=&quot;MyWidgetService&quot;
+...
+android:permission=&quot;android.permission.BIND_REMOTEVIEWS&quot; /&gt;</pre>
+
+<p>The line <code>android:name=&quot;MyWidgetService&quot;</code>
+refers to your subclass of {@link android.widget.RemoteViewsService}. </p>
+
+<h4>Layout for app widgets with collections</h4>
+
+<p>The main requirement for your app widget layout XML file is that it
+include one of the collection views: {@link android.widget.ListView},
+{@link android.widget.GridView}, {@link android.widget.StackView}, or
+{@link android.widget.AdapterViewFlipper}. Here is the
+<code>widget_layout.xml</code> for
+the <a href="{@docRoot}resources/samples/StackWidget/index.html">StackView
+Widget sample</a>:</p>
+
+<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+
+&lt;FrameLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+    android:layout_width=&quot;match_parent&quot;
+    android:layout_height=&quot;match_parent&quot;&gt;
+    &lt;StackView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+        android:id=&quot;&#64;+id/stack_view&quot;
+        android:layout_width=&quot;match_parent&quot;
+        android:layout_height=&quot;match_parent&quot;
+        android:gravity=&quot;center&quot;
+        android:loopViews=&quot;true&quot; /&gt;
+    &lt;TextView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+        android:id=&quot;&#64;+id/empty_view&quot;
+        android:layout_width=&quot;match_parent&quot;
+        android:layout_height=&quot;match_parent&quot;
+        android:gravity=&quot;center&quot;
+        android:background=&quot;&#64;drawable/widget_item_background&quot;
+        android:textColor=&quot;#ffffff&quot;
+        android:textStyle=&quot;bold&quot;
+        android:text=&quot;&#64;string/empty_view_text&quot;
+        android:textSize=&quot;20sp&quot; /&gt;
+&lt;/FrameLayout&gt;</pre>
+
+<p> Note that empty views must be siblings of the collection view for which the
+empty view represents empty state. </p>
+
+<p>In addition to the layout file for your entire app widget, you must create
+another layout file that defines the layout for each item in the collection (for
+example, a layout for each book in a collection of books). For example, the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a> only has one layout file, <code>widget_item.xml</code>, since all
+items use the same layout. But the <a
+href="{@docRoot}resources/samples/WeatherListWidget/index.html">
+WeatherListWidget sample</a> has two layout files:
+<code>dark_widget_item.xml</code> and <code>light_widget_item.xml</code>.</p>
+
+
+
+<h4 id="AppWidgetProvider-collections">AppWidgetProvider class for app widgets with collections</h4>
+
+<p>As with a regular app widget, the bulk of your code in your {@link
+android.appwidget.AppWidgetProvider} subclass typically goes in {@link
+android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,
+android.appwidget.AppWidgetManager, int[]) onUpdate()}. The major difference in
+your implementation for {@link
+android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,
+android.appwidget.AppWidgetManager, int[]) onUpdate()} when creating an app
+widget with collections is that you must call {@link
+android.widget.RemoteViews#setRemoteAdapter setRemoteAdapter()}. This tells the
+collection view where to get its data. The {@link
+android.widget.RemoteViewsService} can then return your implementation of {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, and
+the widget can serve up the appropriate data. When you call this method, you
+must pass an intent that  points to your implementation of {@link
+android.widget.RemoteViewsService} and the App Widget ID that specifies the app
+widget to update.</p>
+
+
+<p>For example, here's how the StackView Widget sample implements the {@link
+android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,
+android.appwidget.AppWidgetManager, int[]) onUpdate()} callback method to set
+the {@link
+android.widget.RemoteViewsService} as the remote adapter for the app widget
+collection:</p>
+
+<pre>public void onUpdate(Context context, AppWidgetManager appWidgetManager,
+int[] appWidgetIds) {
+    // update each of the app widgets with the remote adapter
+    for (int i = 0; i &lt; appWidgetIds.length; ++i) {
+        
+        // Set up the intent that starts the StackViewService, which will
+        // provide the views for this collection.
+        Intent intent = new Intent(context, StackWidgetService.class);
+        // Add the app widget ID to the intent extras.
+        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
+        intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
+        // Instantiate the RemoteViews object for the App Widget layout.
+        RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
+        // Set up the RemoteViews object to use a RemoteViews adapter. 
+        // This adapter connects
+        // to a RemoteViewsService  through the specified intent.
+        // This is how you populate the data.
+        rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
+        
+        // The empty view is displayed when the collection has no items. 
+        // It should be in the same layout used to instantiate the RemoteViews
+        // object above.
+        rv.setEmptyView(R.id.stack_view, R.id.empty_view);
+
+        //
+        // Do additional processing specific to this app widget...
+        //
+        
+        appWidgetManager.updateAppWidget(appWidgetIds[i], rv);   
+    }
+    super.onUpdate(context, appWidgetManager, appWidgetIds);
+}</pre>
+            
+<h4>RemoteViewsService class</h4>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h3>Persisting data</h3>
+   <p>You can’t rely on a single instance of your service, or any data it
+contains, to persist. You should therefore not store any data in your {@link
+android.widget.RemoteViewsService} (unless it is static). If you want your
+app widget’s data to persist, the best approach is to use a {@link
+android.content.ContentProvider} whose data persists beyond the process
+lifecycle.</p> </div>
+</div>
+
+<p>As described above, your {@link android.widget.RemoteViewsService} subclass
+provides the {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} used to  populate the remote collection view.</p> 
+
+<p>Specifically, you need to
+perform these steps:</p>
+
+<ol>
+  <li>Subclass {@link android.widget.RemoteViewsService}. {@link
+android.widget.RemoteViewsService} is the service through which
+a remote adapter can request {@link android.widget.RemoteViews}.  </li>
+  
+  <li>In your {@link android.widget.RemoteViewsService} subclass, include a
+class that implements the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+interface. {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} is an interface for an adapter between a remote collection
+view (such as {@link android.widget.ListView}, {@link android.widget.GridView},
+and so on) and  the underlying data for that view.  Your implementation is
+responsible for making a {@link android.widget.RemoteViews} object  for each
+item in the data set. This interface is a thin wrapper around {@link
+android.widget.Adapter}.</li>
+</ol>
+
+<p>The primary contents of the {@link android.widget.RemoteViewsService}
+implementation is its {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory},
+described below.</p>
+
+<h4>RemoteViewsFactory interface</h4>
+
+<p>Your custom class that implements the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+interface provides the app widget with the data for the items in its collection.
+To
+do this, it combines your app widget item XML layout file with a source of data.
+This source of data could be anything from a database to a simple array. In the
+<a href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a>, the data source is an array of <code>WidgetItems</code>. The {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+functions as an adapter to glue the data to the remote collection view.</p>
+
+<p>The two most important methods you need to implement for your
+
+{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+subclass are 
+{@link android.widget.RemoteViewsService.RemoteViewsFactory#onCreate()
+onCreate()} and
+{@link android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int)
+getViewAt()}
+.</p> 
+
+<p>The system calls {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} when
+creating your factory for the first time. This is where you set up any
+connections and/or cursors to your data source. For example, the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a> uses {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} to
+initialize an array of <code>WidgetItem</code> objects. When your app widget is
+active, the system accesses these objects using their index position in the
+array and the text they contain is displayed  </p>
+
+<p>Here is an excerpt from the the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget</a>
+sample's 
+{@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} implementation that shows portions of the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()}
+method:</p>
+
+<pre>class StackRemoteViewsFactory implements
+RemoteViewsService.RemoteViewsFactory {
+    private static final int mCount = 10;
+    private List&lt;WidgetItem&gt; mWidgetItems = new ArrayList&lt;WidgetItem&gt;();
+    private Context mContext;
+    private int mAppWidgetId;
+
+    public StackRemoteViewsFactory(Context context, Intent intent) {
+        mContext = context;
+        mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+                AppWidgetManager.INVALID_APPWIDGET_ID);
+    }
+
+    public void onCreate() {
+        // In onCreate() you setup any connections / cursors to your data source. Heavy lifting,
+        // for example downloading or creating content etc, should be deferred to onDataSetChanged()
+        // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.
+        for (int i = 0; i &lt; mCount; i++) {
+            mWidgetItems.add(new WidgetItem(i + &quot;!&quot;));
+        }
+        ...
+    }
+...</pre>
+
+<p>The {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} method {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()}
+returns a {@link android.widget.RemoteViews} object corresponding to the data at
+the specified <code>position</code> in the data set. Here is an excerpt from 
+the <a
+href="http://developer.android.com/resources/samples/StackWidget/index.html">
+StackView Widget</a> sample's {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+implementation:</p>
+
+<pre>public RemoteViews getViewAt(int position) {
+   
+    // Construct a remote views item based on the app widget item XML file, 
+    // and set the text based on the position.
+    RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
+    rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);
+
+    ...
+    // Return the remote views object.
+    return rv;
+}</pre>
+
+<h4 id="behavior">Adding behavior to individual items</h4>
+
+<p>The above sections show you how to bind your data to your app widget
+collection. But what if you want to add dynamic behavior to the individual items
+in your collection view?</p> 
+
+<p> As described in <a href="#AppWidgetProvider">Using the AppWidgetProvider
+Class</a>, you  normally use {@link
+android.widget.RemoteViews#setOnClickPendingIntent(int,
+android.app.PendingIntent) setOnClickPendingIntent()} to set an object's click
+behavior&mdash;such as to cause a button to launch an {@link
+android.app.Activity}. But this approach is not allowed for child views in an
+individual collection item (to clarify, you could use {@link
+android.widget.RemoteViews#setOnClickPendingIntent(int,
+android.app.PendingIntent) setOnClickPendingIntent()} to set up a global button
+in the Gmail app widget that launches the app, for example, but not on the
+individual list items). Instead, to add click behavior to individual items in a
+collection, you  use {@link
+android.widget.RemoteViews#setOnClickFillInIntent(int, android.content.Intent)
+setOnClickFillInIntent()}. This entails setting up up a pending intent template
+for your collection view, and then setting a fill-in intent on each item in the
+collection via your {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory}.</p> 
+<p>This section uses the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a> to describe how to add behavior to individual items. In the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a>, if the user touches the top view, the app widget displays the {@link
+android.widget.Toast} message &quot;Touched view <em>n</em>,&quot; where
+<em>n</em> is the index (position) of the touched view. This is how it
+works:</p>
+
+<ul>
+  <li>The <code>StackWidgetProvider</code> (an {@link
+android.appwidget.AppWidgetProvider} subclass) creates a pending intent that has
+a custom action called <code>TOAST_ACTION</code>.</li>
+  <li>When the user touches a view, the intent is fired and it broadcasts
+<code>TOAST_ACTION</code>.</li>
+  
+  <li>This broadcast is intercepted by the <code>StackWidgetProvider</code>'s
+{@link android.appwidget.AppWidgetProvider#onReceive(android.content.Context,
+android.content.Intent) onReceive()} method, and the app widget displays the
+{@link
+android.widget.Toast} message for the touched view. The data for the collection
+items is provided by the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, via
+the {@link android.widget.RemoteViewsService}.</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> The <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a> uses a broadcast, but typically an app widget would simply launch an
+activity in a scenario like this one.</p>
+
+<h5>Setting up the pending intent template</h5> 
+
+<p>The <code>StackWidgetProvider</code> ({@link
+android.appwidget.AppWidgetProvider} subclass) sets up a pending intent.
+Individuals items of a collection cannot set up their own pending intents.
+Instead, the collection as a whole sets up a pending intent template, and the
+individual items set a fill-in intent to create unique behavior on an
+item-by-item
+basis.</p> 
+
+<p>This class  also receives the broadcast that is sent when the user touches a
+view. It processes this event in its {@link
+android.appwidget.AppWidgetProvider#onReceive(android.content.Context,
+android.content.Intent) onReceive()} method. If the intent's action is
+<code>TOAST_ACTION</code>, the app widget displays a {@link
+android.widget.Toast}
+message for the current view.</p>
+
+<pre>public class StackWidgetProvider extends AppWidgetProvider {
+    public static final String TOAST_ACTION = &quot;com.example.android.stackwidget.TOAST_ACTION&quot;;
+    public static final String EXTRA_ITEM = &quot;com.example.android.stackwidget.EXTRA_ITEM&quot;;
+
+    ...
+
+    // Called when the BroadcastReceiver receives an Intent broadcast.
+    // Checks to see whether the intent's action is TOAST_ACTION. If it is, the app widget 
+    // displays a Toast message for the current item.
+    &#64;Override
+    public void onReceive(Context context, Intent intent) {
+        AppWidgetManager mgr = AppWidgetManager.getInstance(context);
+        if (intent.getAction().equals(TOAST_ACTION)) {
+            int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+                AppWidgetManager.INVALID_APPWIDGET_ID);
+            int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0);
+            Toast.makeText(context, &quot;Touched view &quot; + viewIndex, Toast.LENGTH_SHORT).show();
+        }
+        super.onReceive(context, intent);
+    }
+    
+    &#64;Override
+    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+        // update each of the app widgets with the remote adapter
+        for (int i = 0; i &lt; appWidgetIds.length; ++i) {
+    
+            // Sets up the intent that points to the StackViewService that will
+            // provide the views for this collection.
+            Intent intent = new Intent(context, StackWidgetService.class);
+            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
+            // When intents are compared, the extras are ignored, so we need to embed the extras
+            // into the data so that the extras will not be ignored.
+            intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
+            RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
+            rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
+    
+            // The empty view is displayed when the collection has no items. It should be a sibling
+            // of the collection view.
+            rv.setEmptyView(R.id.stack_view, R.id.empty_view);
+
+            // This section makes it possible for items to have individualized behavior.
+            // It does this by setting up a pending intent template. Individuals items of a collection
+            // cannot set up their own pending intents. Instead, the collection as a whole sets
+            // up a pending intent template, and the individual items set a fillInIntent
+            // to create unique behavior on an item-by-item basis.
+            Intent toastIntent = new Intent(context, StackWidgetProvider.class);
+            // Set the action for the intent.
+            // When the user touches a particular view, it will have the effect of
+            // broadcasting TOAST_ACTION.
+            toastIntent.setAction(StackWidgetProvider.TOAST_ACTION);
+            toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
+            intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
+            PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+            rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent);
+            
+            appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
+        }
+    super.onUpdate(context, appWidgetManager, appWidgetIds);
+    }
+}</pre>
+            
+<h5><strong>Setting the fill-in Intent</strong></h5>
+
+<p>Your {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} must set a fill-in intent on each item in the collection.
+This makes it possible to distinguish the individual on-click action of a given
+item. The fill-in intent is then combined with the {@link
+android.app.PendingIntent} template in order to determine the final intent that
+will be executed when the item is clicked. </p>
+
+<pre>
+public class StackWidgetService extends RemoteViewsService {
+    &#64;Override
+    public RemoteViewsFactory onGetViewFactory(Intent intent) {
+        return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
+    }
+}
+
+class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
+    private static final int mCount = 10;
+    private List&lt;WidgetItem&gt; mWidgetItems = new ArrayList&lt;WidgetItem&gt;();
+    private Context mContext;
+    private int mAppWidgetId;
+
+    public StackRemoteViewsFactory(Context context, Intent intent) {
+        mContext = context;
+        mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+                AppWidgetManager.INVALID_APPWIDGET_ID);
+    }
+
+    // Initialize the data set.
+        public void onCreate() {
+            // In onCreate() you set up any connections / cursors to your data source. Heavy lifting,
+            // for example downloading or creating content etc, should be deferred to onDataSetChanged()
+            // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.
+            for (int i = 0; i &lt; mCount; i++) {
+                mWidgetItems.add(new WidgetItem(i + &quot;!&quot;));
+            }
+           ...
+        }
+        ...
+    
+        // Given the position (index) of a WidgetItem in the array, use the item's text value in 
+        // combination with the app widget item XML file to construct a RemoteViews object.
+        public RemoteViews getViewAt(int position) {
+            // position will always range from 0 to getCount() - 1.
+    
+            // Construct a RemoteViews item based on the app widget item XML file, and set the
+            // text based on the position.
+            RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
+            rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);
+    
+            // Next, set a fill-intent, which will be used to fill in the pending intent template
+            // that is set on the collection view in StackWidgetProvider.
+            Bundle extras = new Bundle();
+            extras.putInt(StackWidgetProvider.EXTRA_ITEM, position);
+            Intent fillInIntent = new Intent();
+            fillInIntent.putExtras(extras);
+            // Make it possible to distinguish the individual on-click
+            // action of a given item
+            rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
+        
+            ...
+        
+            // Return the RemoteViews object.
+            return rv;
+        }
+    ...
+    }</pre>
+
+<h3 id="fresh">Keeping Collection Data Fresh</h3>
+
+<p>The following figure illustrates the flow that occurs in an App Widget that
+uses
+collections when updates occur. It shows how the App Widget code interacts with
+the  {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory}, and how you can trigger updates:</p>
+
+<img src="{@docRoot}images/appwidget_collections.png" alt="" />
+
+<p>One feature of App Widgets that use collections is the ability to provide
+users with up-to-date content. For example, consider the Android 3.0 Gmail
+app widget, which provides users with a snapshot of their inbox. To make this
+possible, you need to be able to trigger your {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} and
+collection view to fetch and display new data. You achieve this with the {@link
+android.appwidget.AppWidgetManager} call {@link
+android.appwidget.AppWidgetManager#notifyAppWidgetViewDataChanged(int, int)
+notifyAppWidgetViewDataChanged()}. This call results in a callback to your
+<code>RemoteViewsFactory</code>’s {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged()
+onDataSetChanged()} method, which gives you the opportunity to fetch any new
+data. Note that you can perform
+processing-intensive operations synchronously within the  {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged()
+onDataSetChanged()} callback. You are guaranteed that this call will be
+completed before the metadata or view data is fetched from the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}. In
+addition, you can perform processing-intensive operations within the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()}
+method. If this call takes a long time, the loading view (specified by the
+<code>RemoteViewsFactory</code>’s  {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#getLoadingView()} method)
+will be displayed in the corresponding position of the collection view until it
+returns.</p>
 
 
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index a8125b3..598e88f 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -141,9 +141,14 @@
 </tr>
 </table>
 
+<p class="caution"><strong>Caution:</strong> If your application uses the Android Market's Copy 
+  Protection feature, it cannot be installed to a device's SD card. However, if you use Android 
+  Market's <a href="{@docRoot}guide/publishing/licensing.html">Application Licensing</a> instead, 
+  your application <em>can</em> be installed to internal or external storage, including SD cards.</p>
+
 <p class="note"><strong>Note:</strong> By default, your application will be installed on the
-internal storage and cannot be installed on the external storage unless you define this attribute
-to be either "{@code auto}" or "{@code preferExternal}".</p>
+  internal storage and cannot be installed on the external storage unless you define this attribute
+  to be either "{@code auto}" or "{@code preferExternal}".</p>
 
 <p>When an application is installed on the external storage:</p>
 <ul>
diff --git a/docs/html/images/appwidget.png b/docs/html/images/appwidget.png
index b72b80b..ab6e3de 100644
--- a/docs/html/images/appwidget.png
+++ b/docs/html/images/appwidget.png
Binary files differ
diff --git a/docs/html/images/appwidget_collections.png b/docs/html/images/appwidget_collections.png
new file mode 100644
index 0000000..4bce4a7
--- /dev/null
+++ b/docs/html/images/appwidget_collections.png
Binary files differ
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index 454fc99..9057f98 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -30,14 +30,18 @@
  * Error code for DRM Frameowrk
  */
 enum {
-    DRM_ERROR_BASE = -2000,
+    // The following constant values should be in sync with
+    // media/stagefright/MediaErrors.h
+    ERROR_BASE = -2000,
 
-    DRM_ERROR_UNKNOWN                       = DRM_ERROR_BASE,
-    DRM_ERROR_LICENSE_EXPIRED               = DRM_ERROR_BASE - 1,
-    DRM_ERROR_SESSION_NOT_OPENED            = DRM_ERROR_BASE - 2,
-    DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED  = DRM_ERROR_BASE - 3,
-    DRM_ERROR_DECRYPT                       = DRM_ERROR_BASE - 4,
-    DRM_ERROR_CANNOT_HANDLE                 = DRM_ERROR_BASE - 5,
+    DRM_ERROR_UNKNOWN                       = ERROR_BASE,
+    DRM_ERROR_NO_LICENSE                    = ERROR_BASE - 1,
+    DRM_ERROR_LICENSE_EXPIRED               = ERROR_BASE - 2,
+    DRM_ERROR_SESSION_NOT_OPENED            = ERROR_BASE - 3,
+    DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED  = ERROR_BASE - 4,
+    DRM_ERROR_DECRYPT                       = ERROR_BASE - 5,
+    DRM_ERROR_CANNOT_HANDLE                 = ERROR_BASE - 6,
+    DRM_ERROR_TAMPER_DETECTED               = ERROR_BASE - 7,
 
     DRM_NO_ERROR                            = NO_ERROR
 };
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index 1a6d548..21d00b8 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -41,7 +41,18 @@
     INFO_FORMAT_CHANGED    = MEDIA_ERROR_BASE - 12,
     INFO_DISCONTINUITY     = MEDIA_ERROR_BASE - 13,
 
-    ERROR_NO_LICENSE       = MEDIA_ERROR_BASE - 14,
+    // The following constant values should be in sync with
+    // drm/drm_framework_common.h
+    DRM_ERROR_BASE = -2000,
+
+    ERROR_DRM_UNKNOWN                       = DRM_ERROR_BASE,
+    ERROR_DRM_NO_LICENSE                    = DRM_ERROR_BASE - 1,
+    ERROR_DRM_LICENSE_EXPIRED               = DRM_ERROR_BASE - 2,
+    ERROR_DRM_SESSION_NOT_OPENED            = DRM_ERROR_BASE - 3,
+    ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED  = DRM_ERROR_BASE - 4,
+    ERROR_DRM_DECRYPT                       = DRM_ERROR_BASE - 5,
+    ERROR_DRM_CANNOT_HANDLE                 = DRM_ERROR_BASE - 6,
+    ERROR_DRM_TAMPER_DETECTED               = DRM_ERROR_BASE - 7,
 
     // Heartbeat Error Codes
     HEARTBEAT_ERROR_BASE = -3000,
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 21a18ca..7932d34 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -16,6 +16,8 @@
 
 package android.mtp;
 
+import android.os.storage.StorageVolume;
+
 /**
  * This class represents a storage unit on an MTP device.
  * Used only for MTP support in USB responder mode.
@@ -31,13 +33,12 @@
     private final long mReserveSpace;
     private final boolean mRemovable;
 
-    public MtpStorage(int id, String path, String description,
-            long reserveSpace, boolean removable) {
-        mStorageId = id;
-        mPath = path;
-        mDescription = description;
-        mReserveSpace = reserveSpace;
-        mRemovable = removable;
+    public MtpStorage(StorageVolume volume) {
+        mStorageId = volume.getStorageId();
+        mPath = volume.getPath();
+        mDescription = volume.getDescription();
+        mReserveSpace = volume.getMtpReserveSpace();
+        mRemovable = volume.isRemovable();
     }
 
     /**
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 027a1ce..a8e0a4d 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -24,10 +24,12 @@
 
 #include "include/ARTSPController.h"
 #include "include/AwesomePlayer.h"
+#include "include/DRMExtractor.h"
 #include "include/SoftwareRenderer.h"
 #include "include/NuCachedSource2.h"
 #include "include/ThrottledSource.h"
 #include "include/MPEG2TSExtractor.h"
+#include "include/WVMExtractor.h"
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -312,7 +314,7 @@
     if (mDecryptHandle != NULL) {
         CHECK(mDrmManagerClient);
         if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
-            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
+            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
         }
     }
 
@@ -447,6 +449,7 @@
 
     cancelPlayerEvents();
 
+    mWVMExtractor.clear();
     mCachedSource.clear();
     mAudioTrack.clear();
     mVideoTrack.clear();
@@ -554,6 +557,11 @@
         *durationUs = cachedDataRemaining * 8000000ll / bitrate;
         *eos = (finalStatus != OK);
         return true;
+    } else if (mWVMExtractor != NULL) {
+        status_t finalStatus;
+        *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus);
+        *eos = (finalStatus != OK);
+        return true;
     }
 
     return false;
@@ -646,6 +654,30 @@
                 }
             }
         }
+    } else if (mWVMExtractor != NULL) {
+        status_t finalStatus;
+
+        int64_t cachedDurationUs
+            = mWVMExtractor->getCachedDurationUs(&finalStatus);
+
+        bool eos = (finalStatus != OK);
+
+        if (eos) {
+            if (finalStatus == ERROR_END_OF_STREAM) {
+                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+            }
+            if (mFlags & PREPARING) {
+                LOGV("cache has reached EOS, prepare is done.");
+                finishAsyncPrepare_l();
+            }
+        } else {
+            int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
+            if (percentage > 100) {
+                percentage = 100;
+            }
+
+            notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
+        }
     }
 
     int64_t cachedDurationUs;
@@ -1320,7 +1352,7 @@
             mVideoBuffer = NULL;
         }
 
-        if (mSeeking == SEEK && mCachedSource != NULL && mAudioSource != NULL
+        if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL
                 && !(mFlags & SEEK_PREVIEW)) {
             // We're going to seek the video source first, followed by
             // the audio source.
@@ -1654,8 +1686,19 @@
 status_t AwesomePlayer::finishSetDataSource_l() {
     sp<DataSource> dataSource;
 
+    bool isWidevineStreaming = false;
+    if (!strncasecmp("widevine://", mUri.string(), 11)) {
+        isWidevineStreaming = true;
+
+        String8 newURI = String8("http://");
+        newURI.append(mUri.string() + 11);
+
+        mUri = newURI;
+    }
+
     if (!strncasecmp("http://", mUri.string(), 7)
-            || !strncasecmp("https://", mUri.string(), 8)) {
+            || !strncasecmp("https://", mUri.string(), 8)
+            || isWidevineStreaming) {
         mConnectingDataSource = new NuHTTPDataSource(
                 (mFlags & INCOGNITO) ? NuHTTPDataSource::kFlagIncognito : 0);
 
@@ -1670,39 +1713,48 @@
             return err;
         }
 
+        if (!isWidevineStreaming) {
+            // The widevine extractor does its own caching.
+
 #if 0
-        mCachedSource = new NuCachedSource2(
-                new ThrottledSource(
-                    mConnectingDataSource, 50 * 1024 /* bytes/sec */));
+            mCachedSource = new NuCachedSource2(
+                    new ThrottledSource(
+                        mConnectingDataSource, 50 * 1024 /* bytes/sec */));
 #else
-        mCachedSource = new NuCachedSource2(mConnectingDataSource);
+            mCachedSource = new NuCachedSource2(mConnectingDataSource);
 #endif
-        mConnectingDataSource.clear();
 
-        dataSource = mCachedSource;
-
-        // We're going to prefill the cache before trying to instantiate
-        // the extractor below, as the latter is an operation that otherwise
-        // could block on the datasource for a significant amount of time.
-        // During that time we'd be unable to abort the preparation phase
-        // without this prefill.
-
-        mLock.unlock();
-
-        for (;;) {
-            status_t finalStatus;
-            size_t cachedDataRemaining =
-                mCachedSource->approxDataRemaining(&finalStatus);
-
-            if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
-                    || (mFlags & PREPARE_CANCELLED)) {
-                break;
-            }
-
-            usleep(200000);
+            dataSource = mCachedSource;
+        } else {
+            dataSource = mConnectingDataSource;
         }
 
-        mLock.lock();
+        mConnectingDataSource.clear();
+
+        if (mCachedSource != NULL) {
+            // We're going to prefill the cache before trying to instantiate
+            // the extractor below, as the latter is an operation that otherwise
+            // could block on the datasource for a significant amount of time.
+            // During that time we'd be unable to abort the preparation phase
+            // without this prefill.
+
+            mLock.unlock();
+
+            for (;;) {
+                status_t finalStatus;
+                size_t cachedDataRemaining =
+                    mCachedSource->approxDataRemaining(&finalStatus);
+
+                if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
+                        || (mFlags & PREPARE_CANCELLED)) {
+                    break;
+                }
+
+                usleep(200000);
+            }
+
+            mLock.lock();
+        }
 
         if (mFlags & PREPARE_CANCELLED) {
             LOGI("Prepare cancelled while waiting for initial cache fill.");
@@ -1740,21 +1792,48 @@
         return UNKNOWN_ERROR;
     }
 
-    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+    sp<MediaExtractor> extractor;
 
-    if (extractor == NULL) {
-        return UNKNOWN_ERROR;
+    if (isWidevineStreaming) {
+        String8 mimeType;
+        float confidence;
+        sp<AMessage> dummy;
+        bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy);
+
+        if (!success
+                || strcasecmp(
+                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
+            return ERROR_UNSUPPORTED;
+        }
+
+        mWVMExtractor = new WVMExtractor(dataSource);
+        mWVMExtractor->setAdaptiveStreamingMode(true);
+        extractor = mWVMExtractor;
+    } else {
+        extractor = MediaExtractor::Create(dataSource);
+
+        if (extractor == NULL) {
+            return UNKNOWN_ERROR;
+        }
     }
 
     dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
     if (mDecryptHandle != NULL) {
         CHECK(mDrmManagerClient);
         if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
-            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
+            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
         }
     }
 
-    return setDataSource_l(extractor);
+    status_t err = setDataSource_l(extractor);
+
+    if (err != OK) {
+        mWVMExtractor.clear();
+
+        return err;
+    }
+
+    return OK;
 }
 
 void AwesomePlayer::abortPrepare(status_t err) {
@@ -1815,7 +1894,7 @@
 
     mFlags |= PREPARING_CONNECTED;
 
-    if (mCachedSource != NULL || mRTSPController != NULL) {
+    if (isStreamingHTTP() || mRTSPController != NULL) {
         postBufferingEvent_l();
     } else {
         finishAsyncPrepare_l();
@@ -1852,4 +1931,8 @@
     postCheckAudioStatusEvent_l();
 }
 
+bool AwesomePlayer::isStreamingHTTP() const {
+    return mCachedSource != NULL || mWVMExtractor != NULL;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 2809df5..6db922e 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -146,18 +146,14 @@
     DrmBuffer *pDecryptedDrmBuffer = &decryptedDrmBuffer;
 
     if ((err = mDrmManagerClient->decrypt(mDecryptHandle, mTrackId,
-            &encryptedDrmBuffer, &pDecryptedDrmBuffer)) != DRM_NO_ERROR) {
+            &encryptedDrmBuffer, &pDecryptedDrmBuffer)) != NO_ERROR) {
 
         if (decryptedDrmBuffer.data) {
             delete [] decryptedDrmBuffer.data;
             decryptedDrmBuffer.data = NULL;
         }
 
-        if (err == DRM_ERROR_LICENSE_EXPIRED) {
-            return ERROR_NO_LICENSE;
-        } else {
-            return ERROR_IO;
-        }
+        return err;
     }
     CHECK(pDecryptedDrmBuffer == &decryptedDrmBuffer);
 
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 7c72852..83a1eaa 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -45,7 +45,8 @@
 static Mutex gWVMutex;
 
 WVMExtractor::WVMExtractor(const sp<DataSource> &source)
-    : mDataSource(source) {
+    : mDataSource(source),
+      mUseAdaptiveStreaming(false) {
     {
         Mutex::Autolock autoLock(gWVMutex);
         if (gVendorLibHandle == NULL) {
@@ -100,5 +101,21 @@
     return mImpl->getMetaData();
 }
 
+int64_t WVMExtractor::getCachedDurationUs(status_t *finalStatus) {
+    // TODO: Fill this with life.
+
+    *finalStatus = OK;
+
+    return 0;
+}
+
+void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) {
+    mUseAdaptiveStreaming = adaptive;
+}
+
+bool WVMExtractor::getAdaptiveStreamingMode() const {
+    return mUseAdaptiveStreaming;
+}
+
 } //namespace android
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 4e6f75c..3a21f25 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -44,6 +44,8 @@
 class DrmManagerClinet;
 class DecryptHandle;
 
+struct WVMExtractor;
+
 struct AwesomeRenderer : public RefBase {
     AwesomeRenderer() {}
 
@@ -219,6 +221,8 @@
     DrmManagerClient *mDrmManagerClient;
     DecryptHandle *mDecryptHandle;
 
+    sp<WVMExtractor> mWVMExtractor;
+
     status_t setDataSource_l(
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL);
@@ -268,6 +272,8 @@
 
     status_t startAudioPlayer_l();
 
+    bool isStreamingHTTP() const;
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index 0da45a8..62e5aa5 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -19,6 +19,7 @@
 #define WVM_EXTRACTOR_H_
 
 #include <media/stagefright/MediaExtractor.h>
+#include <utils/Errors.h>
 
 namespace android {
 
@@ -33,12 +34,31 @@
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
     virtual sp<MetaData> getMetaData();
 
+    // Return the amount of data cached from the current
+    // playback positiion (in us).
+    // While more data is still being fetched *finalStatus == OK,
+    // Once fetching is completed (no more data available), *finalStatus != OK
+    // If fetching completed normally (i.e. reached EOS instead of IO error)
+    // *finalStatus == ERROR_END_OF_STREAM
+    int64_t getCachedDurationUs(status_t *finalStatus);
+
+    // Set to use adaptive streaming mode by the WV component.
+    // If adaptive == true, adaptive streaming mode will be used.
+    // Default mode is non-adaptive streaming mode.
+    // Should set to use adaptive streaming mode only if widevine:// protocol
+    // is used.
+    void setAdaptiveStreamingMode(bool adaptive);
+
+    // Retrieve the adaptive streaming mode used by the WV component.
+    bool getAdaptiveStreamingMode() const;
+
 protected:
     virtual ~WVMExtractor();
 
 private:
     sp<DataSource> mDataSource;
     sp<MediaExtractor> mImpl;
+    bool mUseAdaptiveStreaming;
 
     WVMExtractor(const WVMExtractor &);
     WVMExtractor &operator=(const WVMExtractor &);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 376d42f..347d70a 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1145,6 +1145,11 @@
         } catch (IOException e) {
             throw new RuntimeException(e);
         } finally {
+            // compute storage ID for each volume
+            int length = mVolumes.size();
+            for (int i = 0; i < length; i++) {
+                mVolumes.get(i).setStorageId(i);
+            }
             parser.close();
         }
     }
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index c8f8ff3..118cd55 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -156,9 +156,8 @@
         }
 
         if (mDragInProgress && newWin.isPotentialDragTarget()) {
-            DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED,
-                    touchX - newWin.mFrame.left, touchY - newWin.mFrame.top,
-                    null, desc, null, false);
+            DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
+                    touchX, touchY, null, desc, null, false);
             try {
                 newWin.mClient.dispatchDragEvent(event);
                 // track each window that we've notified that the drag is starting
@@ -267,9 +266,8 @@
                     Slog.d(WindowManagerService.TAG, "sending DRAG_EXITED to " + mTargetWindow);
                 }
                 // force DRAG_EXITED_EVENT if appropriate
-                DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED,
-                        x - mTargetWindow.mFrame.left, y - mTargetWindow.mFrame.top,
-                        null, null, null, false);
+                DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
+                        x, y, null, null, null, false);
                 mTargetWindow.mClient.dispatchDragEvent(evt);
                 if (myPid != mTargetWindow.mSession.mPid) {
                     evt.recycle();
@@ -279,9 +277,8 @@
                 if (false && WindowManagerService.DEBUG_DRAG) {
                     Slog.d(WindowManagerService.TAG, "sending DRAG_LOCATION to " + touchedWin);
                 }
-                DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION,
-                        x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
-                        null, null, null, false);
+                DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
+                        x, y, null, null, null, false);
                 touchedWin.mClient.dispatchDragEvent(evt);
                 if (myPid != touchedWin.mSession.mPid) {
                     evt.recycle();
@@ -310,8 +307,7 @@
         }
         final int myPid = Process.myPid();
         final IBinder token = touchedWin.mClient.asBinder();
-        DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP,
-                x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
+        DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
                 null, null, mData, false);
         try {
             touchedWin.mClient.dispatchDragEvent(evt);
@@ -365,4 +361,16 @@
 
         return touchedWin;
     }
+
+    private static DragEvent obtainDragEvent(WindowState win, int action,
+            float x, float y, Object localState,
+            ClipDescription description, ClipData data, boolean result) {
+        float winX = x - win.mFrame.left;
+        float winY = y - win.mFrame.top;
+        if (win.mEnforceSizeCompat) {
+            winX *= win.mGlobalScale;
+            winY *= win.mGlobalScale;
+        }
+        return DragEvent.obtain(action, winX, winY, localState, description, data, result);
+    }
 }
\ No newline at end of file
diff --git a/services/java/com/android/server/wm/FadeInOutAnimation.java b/services/java/com/android/server/wm/FadeInOutAnimation.java
deleted file mode 100644
index 06f7657..0000000
--- a/services/java/com/android/server/wm/FadeInOutAnimation.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.Animation;
-import android.view.animation.Transformation;
-
-/**
- * Animation that fade in after 0.5 interpolate time, or fade out in reverse order.
- * This is used for opening/closing transition for apps in compatible mode.
- */
-class FadeInOutAnimation extends Animation {
-    boolean mFadeIn;
-
-    public FadeInOutAnimation(boolean fadeIn) {
-        setInterpolator(new AccelerateInterpolator());
-        setDuration(WindowManagerService.DEFAULT_FADE_IN_OUT_DURATION);
-        mFadeIn = fadeIn;
-    }
-
-    @Override
-    protected void applyTransformation(float interpolatedTime, Transformation t) {
-        float x = interpolatedTime;
-        if (!mFadeIn) {
-            x = 1.0f - x; // reverse the interpolation for fade out
-        }
-        t.setAlpha(x);
-    }
-}
\ No newline at end of file
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index a3e8be0..9dc92d3 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -205,7 +205,7 @@
             inputWindow.ownerPid = child.mSession.mPid;
             inputWindow.ownerUid = child.mSession.mUid;
             
-            final Rect frame = child.mScaledFrame;
+            final Rect frame = child.mFrame;
             inputWindow.frameLeft = frame.left;
             inputWindow.frameTop = frame.top;
             inputWindow.frameRight = frame.right;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 6103b0f..607c60a 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -603,9 +603,6 @@
     // The frame use to limit the size of the app running in compatibility mode.
     Rect mCompatibleScreenFrame = new Rect();
     float mCompatibleScreenScale;
-    // The surface used to fill the outer rim of the app running in compatibility mode.
-    Surface mBackgroundFillerSurface = null;
-    WindowState mBackgroundFillerTarget = null;
 
     public static WindowManagerService main(Context context,
             PowerManagerService pm, boolean haveInputMethods) {
@@ -1774,7 +1771,7 @@
         boolean rawChanged = false;
         float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
         float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
-        int availw = wallpaperWin.mScaledFrame.right-wallpaperWin.mScaledFrame.left-dw;
+        int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
         int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0;
         changed = wallpaperWin.mXOffset != offset;
         if (changed) {
@@ -2369,6 +2366,11 @@
                     w.mGivenVisibleInsets.set(visibleInsets);
                     w.mGivenTouchableRegion.set(touchableRegion);
                     w.mTouchableInsets = touchableInsets;
+                    if (w.mGlobalScale != 1) {
+                        w.mGivenContentInsets.scale(w.mGlobalScale);
+                        w.mGivenVisibleInsets.scale(w.mGlobalScale);
+                        w.mGivenTouchableRegion.scale(w.mGlobalScale);
+                    }
                     mLayoutNeeded = true;
                     performLayoutAndPlaceSurfacesLocked();
                 }
@@ -2704,7 +2706,7 @@
             if (win.mAppToken != null) {
                 win.mAppToken.updateReportedVisibilityLocked();
             }
-            outFrame.set(win.mFrame);
+            outFrame.set(win.mCompatFrame);
             outContentInsets.set(win.mContentInsets);
             outVisibleInsets.set(win.mVisibleInsets);
             if (localLOGV) Slog.v(
@@ -2903,18 +2905,14 @@
     }
 
     private boolean applyAnimationLocked(AppWindowToken wtoken,
-            WindowManager.LayoutParams lp, int transit, boolean enter, boolean bgFiller) {
+            WindowManager.LayoutParams lp, int transit, boolean enter) {
         // Only apply an animation if the display isn't frozen.  If it is
         // frozen, there is no reason to animate and it can cause strange
         // artifacts when we unfreeze the display if some different animation
         // is running.
         if (!mDisplayFrozen && mPolicy.isScreenOn()) {
             Animation a;
-            if (bgFiller) {
-                a = new FadeInOutAnimation(enter);
-                if (DEBUG_ANIM) Slog.v(TAG,
-                        "applying FadeInOutAnimation for a window in compatibility mode");
-            } else if (mNextAppTransitionPackage != null) {
+            if (mNextAppTransitionPackage != null) {
                 a = loadAnimation(mNextAppTransitionPackage, enter ?
                         mNextAppTransitionEnter : mNextAppTransitionExit);
             } else {
@@ -3706,7 +3704,7 @@
     }
 
     boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
-            boolean visible, int transit, boolean performLayout, boolean bgFiller) {
+            boolean visible, int transit, boolean performLayout) {
         boolean delayed = false;
 
         if (wtoken.clientHidden == visible) {
@@ -3728,7 +3726,7 @@
                 if (wtoken.animation == sDummyAnimation) {
                     wtoken.animation = null;
                 }
-                applyAnimationLocked(wtoken, lp, transit, visible, bgFiller);
+                applyAnimationLocked(wtoken, lp, transit, visible);
                 changed = true;
                 if (wtoken.animation != null) {
                     delayed = runningAppAnimation = true;
@@ -3882,7 +3880,7 @@
 
             final long origId = Binder.clearCallingIdentity();
             setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET,
-                    true, false);
+                    true);
             wtoken.updateReportedVisibilityLocked();
             Binder.restoreCallingIdentity(origId);
         }
@@ -4009,7 +4007,7 @@
             if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
                 delayed = setTokenVisibilityLocked(wtoken, null, false,
-                        WindowManagerPolicy.TRANSIT_UNSET, true, false);
+                        WindowManagerPolicy.TRANSIT_UNSET, true);
                 wtoken.inPendingTransaction = false;
                 mOpeningApps.remove(wtoken);
                 wtoken.waitingToShow = false;
@@ -4830,7 +4828,7 @@
                 
                 // Don't include wallpaper in bounds calculation
                 if (!ws.mIsWallpaper) {
-                    final Rect wf = ws.mScaledFrame;
+                    final Rect wf = ws.mFrame;
                     final Rect cr = ws.mContentInsets;
                     int left = wf.left + cr.left;
                     int top = wf.top + cr.top;
@@ -5549,8 +5547,8 @@
 
         // Override display width and height with what we are computing,
         // to be sure they remain consistent.
-        dm.widthPixels = mPolicy.getNonDecorDisplayWidth(dw);
-        dm.heightPixels = mPolicy.getNonDecorDisplayHeight(dh);
+        dm.widthPixels = dm.realWidthPixels = mPolicy.getNonDecorDisplayWidth(dw);
+        dm.heightPixels = dm.realHeightPixels = mPolicy.getNonDecorDisplayHeight(dh);
 
         mCompatibleScreenScale = CompatibilityInfo.updateCompatibleScreenFrame(
                 dm, mCompatibleScreenFrame, null);
@@ -6500,8 +6498,22 @@
             }
             if (mBaseDisplayWidth < mInitialDisplayWidth
                     || mBaseDisplayHeight < mInitialDisplayHeight) {
-                Rect outer = new Rect(0, 0, mInitialDisplayWidth, mInitialDisplayHeight);
-                Rect inner = new Rect(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+                int initW, initH, baseW, baseH;
+                final boolean rotated = (mRotation == Surface.ROTATION_90
+                        || mRotation == Surface.ROTATION_270);
+                if (rotated) {
+                    initW = mInitialDisplayHeight;
+                    initH = mInitialDisplayWidth;
+                    baseW = mBaseDisplayHeight;
+                    baseH = mBaseDisplayWidth;
+                } else {
+                    initW = mInitialDisplayWidth;
+                    initH = mInitialDisplayHeight;
+                    baseW = mBaseDisplayWidth;
+                    baseH = mBaseDisplayHeight;
+                }
+                Rect outer = new Rect(0, 0, initW, initH);
+                Rect inner = new Rect(0, 0, baseW, baseH);
                 try {
                     mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
                 } catch (Surface.OutOfResourcesException e) {
@@ -6851,7 +6863,6 @@
                     }
                     win.prelayout();
                     mPolicy.layoutWindowLw(win, win.mAttrs, null);
-                    win.evalNeedsBackgroundFiller(innerDw, innerDh);
                     win.mLayoutSeq = seq;
                     if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
                             + win.mFrame + " mContainingFrame="
@@ -6888,7 +6899,6 @@
                     }
                     win.prelayout();
                     mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
-                    win.evalNeedsBackgroundFiller(innerDw, innerDh);
                     win.mLayoutSeq = seq;
                     if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
                             + win.mFrame + " mContainingFrame="
@@ -7340,7 +7350,6 @@
                         LayoutParams animLp = null;
                         int bestAnimLayer = -1;
                         boolean fullscreenAnim = false;
-                        boolean needBgFiller = false;
 
                         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                                 "New wallpaper target=" + mWallpaperTarget
@@ -7378,16 +7387,8 @@
                             if (wtoken.appFullscreen) {
                                 WindowState ws = wtoken.findMainWindow();
                                 if (ws != null) {
-                                    // If this is a compatibility mode
-                                    // window, we will always use its anim.
-                                    if (ws.mNeedsBackgroundFiller) {
-                                        animLp = ws.mAttrs;
-                                        bestAnimLayer = Integer.MAX_VALUE;
-                                        needBgFiller = true;
-                                    } else if (!fullscreenAnim || ws.mLayer > bestAnimLayer) {
-                                        animLp = ws.mAttrs;
-                                        bestAnimLayer = ws.mLayer;
-                                    }
+                                    animLp = ws.mAttrs;
+                                    bestAnimLayer = ws.mLayer;
                                     fullscreenAnim = true;
                                 }
                             } else if (!fullscreenAnim) {
@@ -7449,7 +7450,7 @@
                             wtoken.inPendingTransaction = false;
                             wtoken.animation = null;
                             setTokenVisibilityLocked(wtoken, animLp, true,
-                                    transit, false, needBgFiller);
+                                    transit, false);
                             wtoken.updateReportedVisibilityLocked();
                             wtoken.waitingToShow = false;
                             wtoken.showAllWindowsLocked();
@@ -7462,7 +7463,7 @@
                             wtoken.inPendingTransaction = false;
                             wtoken.animation = null;
                             setTokenVisibilityLocked(wtoken, animLp, false,
-                                    transit, false, needBgFiller);
+                                    transit, false);
                             wtoken.updateReportedVisibilityLocked();
                             wtoken.waitingToHide = false;
                             // Force the allDrawn flag, because we want to start
@@ -7629,8 +7630,6 @@
             boolean dimming = false;
             boolean covered = false;
             boolean syswin = false;
-            boolean backgroundFillerWasShown = mBackgroundFillerTarget != null;
-            mBackgroundFillerTarget = null;
 
             final int N = mWindows.size();
 
@@ -7659,8 +7658,7 @@
                     w.computeShownFrameLocked();
                     if (localLOGV) Slog.v(
                             TAG, "Placing surface #" + i + " " + w.mSurface
-                            + ": new=" + w.mShownFrame + ", old="
-                            + w.mLastShownFrame);
+                            + ": new=" + w.mShownFrame);
 
                     int width, height;
                     if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
@@ -7668,13 +7666,9 @@
                         // the requested size.
                         width  = w.mRequestedWidth;
                         height = w.mRequestedHeight;
-                        w.mLastRequestedWidth = width;
-                        w.mLastRequestedHeight = height;
-                        w.mLastShownFrame.set(w.mShownFrame);
                     } else {
-                        width = w.mShownFrame.width();
-                        height = w.mShownFrame.height();
-                        w.mLastShownFrame.set(w.mShownFrame);
+                        width = w.mCompatFrame.width();
+                        height = w.mCompatFrame.height();
                     }
 
                     if (w.mSurface != null) {
@@ -7741,8 +7735,8 @@
                         }
                         if (localLOGV) Slog.v(TAG, "Resizing " + w
                                 + ": configChanged=" + configChanged
-                                + " last=" + w.mLastFrame + " frame=" + w.mFrame);
-                        boolean frameChanged = !w.mLastFrame.equals(w.mFrame);
+                                + " last=" + w.mLastCompatFrame + " frame=" + w.mCompatFrame);
+                        boolean frameChanged = !w.mLastCompatFrame.equals(w.mCompatFrame);
                         if (frameChanged
                                 || w.mContentInsetsChanged
                                 || w.mVisibleInsetsChanged
@@ -7758,6 +7752,7 @@
                             }
 
                             w.mLastFrame.set(w.mFrame);
+                            w.mLastCompatFrame.set(w.mCompatFrame);
                             w.mLastContentInsets.set(w.mContentInsets);
                             w.mLastVisibleInsets.set(w.mVisibleInsets);
                             // If the screen is currently frozen, then keep
@@ -7793,7 +7788,7 @@
                                 }
                             }
                             if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
-                                    "Resizing window " + w + " to " + w.mFrame);
+                                    "Resizing window " + w + " to " + w.mCompatFrame);
                             mResizingWindows.add(w);
                         } else if (w.mOrientationChanging) {
                             if (!w.mDrawPending && !w.mCommitDrawPending) {
@@ -7932,16 +7927,6 @@
 
                 final boolean obscuredChanged = w.mObscured != obscured;
 
-                if (mBackgroundFillerTarget != null) {
-                    if (w.isAnimating()) {
-                        // Background filler is below all other windows that
-                        // are animating.
-                        mBackgroundFillerTarget = w;
-                    } else if (w.mIsWallpaper) {
-                        mBackgroundFillerTarget = w;
-                    }
-                }
-
                 // Update effect.
                 if (!(w.mObscured=obscured)) {
                     if (w.mSurface != null) {
@@ -7970,12 +7955,6 @@
                         // so we want to leave all of them as unblurred (for
                         // performance reasons).
                         obscured = true;
-                    } else if (w.mNeedsBackgroundFiller && w.mHasDrawn
-                            && w.mViewVisibility == View.VISIBLE
-                            && (canBeSeen || w.isAnimating())) {
-                        // This window is in compatibility mode, and needs background filler.
-                        obscured = true;
-                        mBackgroundFillerTarget = w;
                     } else if (canBeSeen && !obscured &&
                             (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
                         if (localLOGV) Slog.v(TAG, "Win " + w
@@ -8042,47 +8021,6 @@
                 }
             }
 
-            if (mBackgroundFillerTarget != null) {
-                if (mBackgroundFillerSurface == null) {
-                    try {
-                        mBackgroundFillerSurface = new Surface(mFxSession, 0,
-                                "BackGroundFiller",
-                                0, dw, dh,
-                                PixelFormat.OPAQUE,
-                                Surface.FX_SURFACE_NORMAL);
-                    } catch (Exception e) {
-                        Slog.e(TAG, "Exception creating filler surface", e);
-                    }
-                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BG FILLER "
-                            + mBackgroundFillerSurface + ": CREATE");
-                }
-                try {
-                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BG FILLER "
-                            + mBackgroundFillerSurface + " SHOW: pos=(0,0) ("
-                            + dw + "x" + dh + ") layer="
-                            + (mBackgroundFillerTarget.mLayer - 1));
-                    mBackgroundFillerSurface.setPosition(0, 0);
-                    mBackgroundFillerSurface.setSize(dw, dh);
-                    // Using the same layer as Dim because they will never be shown at the
-                    // same time.  NOTE: we do NOT use mAnimLayer, because we don't
-                    // want this surface dragged up in front of stuff that is animating.
-                    mBackgroundFillerSurface.setLayer(mBackgroundFillerTarget.mLayer
-                            - LAYER_OFFSET_DIM);
-                    mBackgroundFillerSurface.show();
-                } catch (RuntimeException e) {
-                    Slog.e(TAG, "Exception showing filler surface");
-                }
-            } else if (backgroundFillerWasShown) {
-                mBackgroundFillerTarget = null;
-                if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BG FILLER "
-                        + mBackgroundFillerSurface + " HIDE");
-                try {
-                    mBackgroundFillerSurface.hide();
-                } catch (RuntimeException e) {
-                    Slog.e(TAG, "Exception hiding filler surface", e);
-                }
-            }
-
             if (mDimAnimator != null && mDimAnimator.mDimShown) {
                 animating |= mDimAnimator.updateSurface(dimming, currentTime,
                         mDisplayFrozen || !mPolicy.isScreenOn());
@@ -8137,7 +8075,7 @@
                 WindowState win = mResizingWindows.get(i);
                 try {
                     if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Reporting new frame to " + win + ": " + win.mFrame);
+                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
                     int diff = 0;
                     boolean configChanged =
                         win.mConfiguration != mCurConfiguration
@@ -8146,13 +8084,13 @@
                     if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
                             && configChanged) {
                         Slog.i(TAG, "Sending new config to window " + win + ": "
-                                + win.mFrame.width() + "x" + win.mFrame.height()
+                                + win.mCompatFrame.width() + "x" + win.mCompatFrame.height()
                                 + " / " + mCurConfiguration + " / 0x"
                                 + Integer.toHexString(diff));
                     }
                     win.mConfiguration = mCurConfiguration;
-                    win.mClient.resized(win.mFrame.width(),
-                            win.mFrame.height(), win.mLastContentInsets,
+                    win.mClient.resized(win.mCompatFrame.width(),
+                            win.mCompatFrame.height(), win.mLastContentInsets,
                             win.mLastVisibleInsets, win.mDrawPending,
                             configChanged ? win.mConfiguration : null);
                     win.mContentInsetsChanged = false;
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 2014e9d..144341b 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -18,7 +18,6 @@
 
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -83,23 +82,30 @@
     boolean mAttachedHidden;    // is our parent window hidden?
     boolean mLastHidden;        // was this window last hidden?
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
+
+    /**
+     * The window size that was requested by the application.  These are in
+     * the application's coordinate space (without compatibility scale applied).
+     */
     int mRequestedWidth;
     int mRequestedHeight;
-    int mLastRequestedWidth;
-    int mLastRequestedHeight;
+
     int mLayer;
     int mAnimLayer;
     int mLastLayer;
     boolean mHaveFrame;
     boolean mObscured;
-    boolean mNeedsBackgroundFiller;
     boolean mTurnOnScreen;
 
     int mLayoutSeq = -1;
     
     Configuration mConfiguration = null;
     
-    // Actual frame shown on-screen (may be modified by animation)
+    /**
+     * Actual frame shown on-screen (may be modified by animation).  These
+     * are in the screen's coordinate space (WITH the compatibility scale
+     * applied).
+     */
     final Rect mShownFrame = new Rect();
     final Rect mLastShownFrame = new Rect();
 
@@ -110,14 +116,16 @@
     boolean mSurfaceResized;
     
     /**
-     * Insets that determine the actually visible area
+     * Insets that determine the actually visible area.  These are in the application's
+     * coordinate space (without compatibility scale applied).
      */
     final Rect mVisibleInsets = new Rect();
     final Rect mLastVisibleInsets = new Rect();
     boolean mVisibleInsetsChanged;
 
     /**
-     * Insets that are covered by system windows
+     * Insets that are covered by system windows.  These are in the application's
+     * coordinate space (without compatibility scale applied).
      */
     final Rect mContentInsets = new Rect();
     final Rect mLastContentInsets = new Rect();
@@ -157,16 +165,20 @@
     // Current transformation being applied.
     boolean mHaveMatrix;
     float mGlobalScale=1;
+    float mInvGlobalScale=1;
     float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
     float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
     float mHScale=1, mVScale=1;
     float mLastHScale=1, mLastVScale=1;
     final Matrix mTmpMatrix = new Matrix();
 
-    // "Real" frame that the application sees.
+    // "Real" frame that the application sees, in display coordinate space.
     final Rect mFrame = new Rect();
     final Rect mLastFrame = new Rect();
-    final Rect mScaledFrame = new Rect();
+    // Frame that is scaled to the application's coordinate space when in
+    // screen size compatibility mode.
+    final Rect mCompatFrame = new Rect();
+    final Rect mLastCompatFrame = new Rect();
 
     final Rect mContainingFrame = new Rect();
     final Rect mDisplayFrame = new Rect();
@@ -346,8 +358,6 @@
         mSurface = null;
         mRequestedWidth = 0;
         mRequestedHeight = 0;
-        mLastRequestedWidth = 0;
-        mLastRequestedHeight = 0;
         mXOffset = 0;
         mYOffset = 0;
         mLayer = 0;
@@ -373,23 +383,40 @@
         final Rect display = mDisplayFrame;
         display.set(df);
 
-        if (mEnforceSizeCompat) {
-            container.intersect(mService.mCompatibleScreenFrame);
-            if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) {
-                display.intersect(mService.mCompatibleScreenFrame);
-            }
-        }
-
         final int pw = container.right - container.left;
         final int ph = container.bottom - container.top;
 
         int w,h;
-        if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
-            w = mAttrs.width < 0 ? pw : mAttrs.width;
-            h = mAttrs.height< 0 ? ph : mAttrs.height;
+        if ((mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0) {
+            if (mAttrs.width < 0) {
+                w = pw;
+            } else if (mEnforceSizeCompat) {
+                w = (int)(mAttrs.width * mGlobalScale + .5f);
+            } else {
+                w = mAttrs.width;
+            }
+            if (mAttrs.height < 0) {
+                h = ph;
+            } else if (mEnforceSizeCompat) {
+                h = (int)(mAttrs.height * mGlobalScale + .5f);
+            } else {
+                h = mAttrs.height;
+            }
         } else {
-            w = mAttrs.width == mAttrs.MATCH_PARENT ? pw : mRequestedWidth;
-            h = mAttrs.height== mAttrs.MATCH_PARENT ? ph : mRequestedHeight;
+            if (mAttrs.width == WindowManager.LayoutParams.MATCH_PARENT) {
+                w = pw;
+            } else if (mEnforceSizeCompat) {
+                w = (int)(mRequestedWidth * mGlobalScale + .5f);
+            } else {
+                w = mRequestedWidth;
+            }
+            if (mAttrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
+                h = ph;
+            } else if (mEnforceSizeCompat) {
+                h = (int)(mRequestedHeight * mGlobalScale + .5f);
+            } else {
+                h = mRequestedHeight;
+            }
         }
 
         if (!mParentFrame.equals(pf)) {
@@ -412,37 +439,24 @@
         //System.out.println("In: w=" + w + " h=" + h + " container=" +
         //                   container + " x=" + mAttrs.x + " y=" + mAttrs.y);
 
+        float x, y;
+        if (mEnforceSizeCompat) {
+            x = mAttrs.x * mGlobalScale;
+            y = mAttrs.y * mGlobalScale;
+        } else {
+            x = mAttrs.x;
+            y = mAttrs.y;
+        }
+
         Gravity.apply(mAttrs.gravity, w, h, container,
-                (int) (mAttrs.x + mAttrs.horizontalMargin * pw),
-                (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame);
+                (int) (x + mAttrs.horizontalMargin * pw),
+                (int) (y + mAttrs.verticalMargin * ph), frame);
 
         //System.out.println("Out: " + mFrame);
 
         // Now make sure the window fits in the overall display.
         Gravity.applyDisplay(mAttrs.gravity, df, frame);
 
-        int adjRight=0, adjBottom=0;
-
-        if (mEnforceSizeCompat) {
-            // Adjust window offsets by the scaling factor.
-            int xoff = (int)((frame.left-mService.mCompatibleScreenFrame.left)*mGlobalScale)
-                    - (frame.left-mService.mCompatibleScreenFrame.left);
-            int yoff = (int)((frame.top-mService.mCompatibleScreenFrame.top)*mGlobalScale)
-                    - (frame.top-mService.mCompatibleScreenFrame.top);
-            frame.offset(xoff, yoff);
-
-            // We are temporarily going to apply the compatibility scale
-            // to the window so that we can correctly associate it with the
-            // content and visible frame.
-            adjRight = frame.right - frame.left;
-            adjRight = (int)((adjRight)*mGlobalScale + .5f) - adjRight;
-            adjBottom = frame.bottom - frame.top;
-            adjBottom = (int)((adjBottom)*mGlobalScale + .5f) - adjBottom;
-            frame.right += adjRight;
-            frame.bottom += adjBottom;
-        }
-        mScaledFrame.set(frame);
-
         // Make sure the content and visible frames are inside of the
         // final window frame.
         if (content.left < frame.left) content.left = frame.left;
@@ -466,20 +480,17 @@
         visibleInsets.right = frame.right-visible.right;
         visibleInsets.bottom = frame.bottom-visible.bottom;
 
+        mCompatFrame.set(frame);
         if (mEnforceSizeCompat) {
-            // Scale the computed insets back to the window's compatibility
-            // coordinate space, and put frame back to correct size.
-            final float invScale = 1.0f/mGlobalScale;
-            contentInsets.left = (int)(contentInsets.left*invScale);
-            contentInsets.top = (int)(contentInsets.top*invScale);
-            contentInsets.right = (int)(contentInsets.right*invScale);
-            contentInsets.bottom = (int)(contentInsets.bottom*invScale);
-            visibleInsets.left = (int)(visibleInsets.left*invScale);
-            visibleInsets.top = (int)(visibleInsets.top*invScale);
-            visibleInsets.right = (int)(visibleInsets.right*invScale);
-            visibleInsets.bottom = (int)(visibleInsets.bottom*invScale);
-            frame.right -= adjRight;
-            frame.bottom -= adjBottom;
+            // If there is a size compatibility scale being applied to the
+            // window, we need to apply this to its insets so that they are
+            // reported to the app in its coordinate space.
+            contentInsets.scale(mInvGlobalScale);
+            visibleInsets.scale(mInvGlobalScale);
+
+            // Also the scaled frame that we report to the app needs to be
+            // adjusted to be in its coordinate space.
+            mCompatFrame.scale(mInvGlobalScale);
         }
 
         if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
@@ -592,12 +603,12 @@
             if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(
                 WindowManagerService.TAG, "Creating surface in session "
                 + mSession.mSurfaceSession + " window " + this
-                + " w=" + mFrame.width()
-                + " h=" + mFrame.height() + " format="
+                + " w=" + mCompatFrame.width()
+                + " h=" + mCompatFrame.height() + " format="
                 + mAttrs.format + " flags=" + flags);
 
-            int w = mFrame.width();
-            int h = mFrame.height();
+            int w = mCompatFrame.width();
+            int h = mCompatFrame.height();
             if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
                 // for a scaled surface, we always want the requested
                 // size.
@@ -650,8 +661,9 @@
                 + ", animLayer=" + mAnimLayer);
             if (WindowManagerService.SHOW_TRANSACTIONS) {
                 Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
-                WindowManagerService.logSurface(this, "CREATE pos=(" + mFrame.left + "," + mFrame.top + ") (" +
-                        mFrame.width() + "x" + mFrame.height() + "), layer=" +
+                WindowManagerService.logSurface(this, "CREATE pos=(" + mFrame.left
+                        + "," + mFrame.top + ") (" +
+                        mCompatFrame.width() + "x" + mCompatFrame.height() + "), layer=" +
                         mAnimLayer + " HIDE", null);
             }
             Surface.openTransaction();
@@ -862,10 +874,10 @@
                 if (!mLocalAnimating) {
                     if (WindowManagerService.DEBUG_ANIM) Slog.v(
                         WindowManagerService.TAG, "Starting animation in " + this +
-                        " @ " + currentTime + ": ww=" + mScaledFrame.width() +
-                        " wh=" + mScaledFrame.height() +
+                        " @ " + currentTime + ": ww=" + mFrame.width() +
+                        " wh=" + mFrame.height() +
                         " dw=" + dw + " dh=" + dh + " scale=" + mService.mWindowAnimationScale);
-                    mAnimation.initialize(mScaledFrame.width(), mScaledFrame.height(), dw, dh);
+                    mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
                     mAnimation.setStartTime(currentTime);
                     mLocalAnimating = true;
                     mAnimating = true;
@@ -1035,8 +1047,9 @@
     void prelayout() {
         if (mEnforceSizeCompat) {
             mGlobalScale = mService.mCompatibleScreenScale;
+            mInvGlobalScale = 1/mGlobalScale;
         } else {
-            mGlobalScale = 1;
+            mGlobalScale = mInvGlobalScale = 1;
         }
     }
 
@@ -1334,35 +1347,9 @@
                 && mService.mPolicy.isScreenOn();
     }
 
-    void evalNeedsBackgroundFiller(int screenWidth, int screenHeight) {
-        mNeedsBackgroundFiller =
-             // only if the application is requesting compatible window
-             mEnforceSizeCompat &&
-             // only if it's visible
-             mHasDrawn && mViewVisibility == View.VISIBLE &&
-             // not needed if the compat window is actually full screen
-             !isFullscreenIgnoringCompat(screenWidth, screenHeight) &&
-             // and only if the application fills the compatible screen
-             mFrame.left <= mService.mCompatibleScreenFrame.left &&
-             mFrame.top <= mService.mCompatibleScreenFrame.top &&
-             mFrame.right >= mService.mCompatibleScreenFrame.right &&
-             mFrame.bottom >= mService.mCompatibleScreenFrame.bottom;
-    }
-
     boolean isFullscreen(int screenWidth, int screenHeight) {
-        if (mEnforceSizeCompat) {
-            return mFrame.left <= mService.mCompatibleScreenFrame.left &&
-                    mFrame.top <= mService.mCompatibleScreenFrame.top &&
-                    mFrame.right >= mService.mCompatibleScreenFrame.right &&
-                    mFrame.bottom >= mService.mCompatibleScreenFrame.bottom;
-        } else {
-            return isFullscreenIgnoringCompat(screenWidth, screenHeight);
-        }
-    }
-
-    boolean isFullscreenIgnoringCompat(int screenWidth, int screenHeight) {
-        return mScaledFrame.left <= 0 && mScaledFrame.top <= 0 &&
-                mScaledFrame.right >= screenWidth && mScaledFrame.bottom >= screenHeight;
+        return mFrame.left <= 0 && mFrame.top <= 0 &&
+                mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
     }
 
     void removeLocked() {
@@ -1492,38 +1479,28 @@
         return true;
     }
 
-    private static void applyScaledInsets(Region outRegion, Rect frame, Rect inset, float scale) {
-        if (scale != 1) {
-            outRegion.set(frame.left + (int)(inset.left*scale),
-                    frame.top + (int)(inset.top*scale),
-                    frame.right - (int)(inset.right*scale),
-                    frame.bottom - (int)(inset.bottom*scale));
-        } else {
-            outRegion.set(
-                    frame.left + inset.left, frame.top + inset.top,
-                    frame.right - inset.right, frame.bottom - inset.bottom);
-        }
+    private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
+        outRegion.set(
+                frame.left + inset.left, frame.top + inset.top,
+                frame.right - inset.right, frame.bottom - inset.bottom);
     }
 
     public void getTouchableRegion(Region outRegion) {
-        final Rect frame = mScaledFrame;
+        final Rect frame = mFrame;
         switch (mTouchableInsets) {
             default:
             case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
                 outRegion.set(frame);
                 break;
             case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT:
-                applyScaledInsets(outRegion, frame, mGivenContentInsets, mGlobalScale);
+                applyInsets(outRegion, frame, mGivenContentInsets);
                 break;
             case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE:
-                applyScaledInsets(outRegion, frame, mGivenVisibleInsets, mGlobalScale);
+                applyInsets(outRegion, frame, mGivenVisibleInsets);
                 break;
             case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: {
                 final Region givenTouchableRegion = mGivenTouchableRegion;
                 outRegion.set(givenTouchableRegion);
-                if (mGlobalScale != 1) {
-                    outRegion.scale(mGlobalScale);
-                }
                 outRegion.translate(frame.left, frame.top);
                 break;
             }
@@ -1586,8 +1563,7 @@
         }
         pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
                 pw.print(" h="); pw.print(mRequestedHeight);
-                pw.print(" mLayoutSeq="); pw.print(mLayoutSeq);
-                pw.print(" mNeedsBackgroundFiller="); pw.println(mNeedsBackgroundFiller);
+                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
         if (mXOffset != 0 || mYOffset != 0) {
             pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
                     pw.print(" y="); pw.println(mYOffset);
@@ -1608,8 +1584,12 @@
                 pw.println();
         pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
                 pw.print(" last="); mLastFrame.printShortString(pw);
-                pw.print(" scaled="); mScaledFrame.printShortString(pw);
                 pw.println();
+        if (mEnforceSizeCompat) {
+            pw.print(prefix); pw.print("mCompatFrame="); mCompatFrame.printShortString(pw);
+                    pw.print(" last="); mLastCompatFrame.printShortString(pw);
+                    pw.println();
+        }
         pw.print(prefix); pw.print("mContainingFrame=");
                 mContainingFrame.printShortString(pw);
                 pw.print(" mParentFrame=");
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 3c0c9a4..144ec42 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -201,7 +201,8 @@
                 Capability.VIEW_MANIPULATION,
                 Capability.PLAY_ANIMATION,
                 Capability.ANIMATED_VIEW_MANIPULATION,
-                Capability.ADAPTER_BINDING);
+                Capability.ADAPTER_BINDING,
+                Capability.EXTENDED_VIEWINFO);
 
 
         BridgeAssetManager.initSystem();
@@ -399,15 +400,6 @@
         throw new IllegalArgumentException("viewObject is not a View");
     }
 
-    @Override
-    public int getViewBaseline(Object viewObject) {
-        if (viewObject instanceof View) {
-            return ((View) viewObject).getBaseline();
-        }
-
-        throw new IllegalArgumentException("viewObject is not a View");
-    }
-
     /**
      * Returns the lock for the bridge
      */
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
index 1ca3182..3d50b2a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
@@ -19,21 +19,23 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.widget.TextView;
 
 /**
  * Base class for mocked views.
- * 
+ *
  * TODO: implement onDraw and draw a rectangle in a random color with the name of the class
  * (or better the id of the view).
  */
 public class MockView extends TextView {
-    
+
     public MockView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        
+
         setText(this.getClass().getSimpleName());
         setTextColor(0xFF000000);
+        setGravity(Gravity.CENTER);
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index c53cb23..b800519 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -74,6 +74,7 @@
 import android.view.View.AttachInfo;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.AbsListView;
 import android.widget.AbsSpinner;
 import android.widget.AdapterView;
@@ -513,7 +514,7 @@
                 mViewRoot.draw(mCanvas);
             }
 
-            mViewInfoList = startVisitingViews(mViewRoot, 0);
+            mViewInfoList = startVisitingViews(mViewRoot, 0, params.getExtendedViewInfoMode());
 
             // success!
             return SUCCESS.createResult();
@@ -1255,7 +1256,7 @@
         }
     }
 
-    private List<ViewInfo> startVisitingViews(View view, int offset) {
+    private List<ViewInfo> startVisitingViews(View view, int offset, boolean setExtendedInfo) {
         if (view == null) {
             return null;
         }
@@ -1264,7 +1265,7 @@
         offset += view.getTop();
 
         if (view == mContentRoot) {
-            return visitAllChildren(mContentRoot, offset);
+            return visitAllChildren(mContentRoot, offset, setExtendedInfo);
         }
 
         // otherwise, look for mContentRoot in the children
@@ -1272,7 +1273,8 @@
             ViewGroup group = ((ViewGroup) view);
 
             for (int i = 0; i < group.getChildCount(); i++) {
-                List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset);
+                List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset,
+                        setExtendedInfo);
                 if (list != null) {
                     return list;
                 }
@@ -1287,8 +1289,9 @@
      * bounds of all the views.
      * @param view the root View
      * @param offset an offset for the view bounds.
+     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
      */
-    private ViewInfo visit(View view, int offset) {
+    private ViewInfo visit(View view, int offset, boolean setExtendedInfo) {
         if (view == null) {
             return null;
         }
@@ -1298,9 +1301,22 @@
                 view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
                 view, view.getLayoutParams());
 
+        if (setExtendedInfo) {
+            MarginLayoutParams marginParams = null;
+            LayoutParams params = view.getLayoutParams();
+            if (params instanceof MarginLayoutParams) {
+                marginParams = (MarginLayoutParams) params;
+            }
+            result.setExtendedInfo(view.getBaseline(),
+                    marginParams != null ? marginParams.leftMargin : 0,
+                    marginParams != null ? marginParams.topMargin : 0,
+                    marginParams != null ? marginParams.rightMargin : 0,
+                    marginParams != null ? marginParams.bottomMargin : 0);
+        }
+
         if (view instanceof ViewGroup) {
             ViewGroup group = ((ViewGroup) view);
-            result.setChildren(visitAllChildren(group, 0 /*offset*/));
+            result.setChildren(visitAllChildren(group, 0 /*offset*/, setExtendedInfo));
         }
 
         return result;
@@ -1311,15 +1327,17 @@
      * containing the bounds of all the views.
      * @param view the root View
      * @param offset an offset for the view bounds.
+     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
      */
-    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset) {
+    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
+            boolean setExtendedInfo) {
         if (viewGroup == null) {
             return null;
         }
 
         List<ViewInfo> children = new ArrayList<ViewInfo>();
         for (int i = 0; i < viewGroup.getChildCount(); i++) {
-            children.add(visit(viewGroup.getChildAt(i), offset));
+            children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo));
         }
         return children;
     }