Merge change I8c0747cf into eclair-mr2

* changes:
  Make vCard parser invalid lines in vCard file which look like some comment.
diff --git a/api/current.xml b/api/current.xml
index caaa305..a59fc32 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1967,6 +1967,17 @@
  visibility="public"
 >
 </field>
+<field name="autoStart"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843446"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="autoText"
  type="int"
  transient="false"
@@ -123841,6 +123852,34 @@
 </parameter>
 </method>
 </class>
+<class name="WallpaperSettingsActivity"
+ extends="android.preference.PreferenceActivity"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="WallpaperSettingsActivity"
+ type="android.service.wallpaper.WallpaperSettingsActivity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="EXTRA_PREVIEW_MODE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.service.wallpaper.PREVIEW_MODE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 </package>
 <package name="android.speech"
 >
@@ -173626,6 +173665,17 @@
  visibility="public"
 >
 </constructor>
+<method name="getContentDisposition"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getContentLength"
  return="long"
  abstract="false"
@@ -173670,6 +173720,17 @@
  visibility="public"
 >
 </method>
+<method name="getExpiresString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getHttpStatusCode"
  return="int"
  abstract="false"
@@ -173794,6 +173855,23 @@
 <parameter name="w" type="android.webkit.WebView">
 </parameter>
 </constructor>
+<method name="addMessageToConsole"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="lineNumber" type="int">
+</parameter>
+<parameter name="sourceID" type="java.lang.String">
+</parameter>
+</method>
 <method name="createWindow"
  return="android.webkit.WebView"
  abstract="false"
@@ -173846,6 +173924,30 @@
  visibility="public"
 >
 </method>
+<method name="getVisitedHistory"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.webkit.ValueCallback&lt;java.lang.String[]&gt;">
+</parameter>
+</method>
+<method name="getWebChromeClient"
+ return="android.webkit.WebChromeClient"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onCloseWindow"
  return="void"
  abstract="false"
@@ -173918,6 +174020,32 @@
 <parameter name="resend" type="android.os.Message">
 </parameter>
 </method>
+<method name="onGeolocationPermissionsHidePrompt"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onGeolocationPermissionsShowPrompt"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="origin" type="java.lang.String">
+</parameter>
+<parameter name="callback" type="android.webkit.GeolocationPermissions.Callback">
+</parameter>
+</method>
 <method name="onJsAlert"
  return="void"
  abstract="false"
@@ -173980,6 +174108,17 @@
 <parameter name="defaultValue" type="java.lang.String">
 </parameter>
 </method>
+<method name="onJsTimeout"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onLoadResource"
  return="void"
  abstract="false"
@@ -174034,6 +174173,23 @@
 <parameter name="newProgress" type="int">
 </parameter>
 </method>
+<method name="onReachedMaxAppCacheSize"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="spaceNeeded" type="long">
+</parameter>
+<parameter name="totalUsedQuota" type="long">
+</parameter>
+<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
+</parameter>
+</method>
 <method name="onReceivedError"
  return="void"
  abstract="false"
@@ -174520,6 +174676,82 @@
  visibility="public"
 >
 </constructor>
+<method name="allow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="origin" type="java.lang.String">
+</parameter>
+</method>
+<method name="clear"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="origin" type="java.lang.String">
+</parameter>
+</method>
+<method name="clearAll"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAllowed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="origin" type="java.lang.String">
+</parameter>
+<parameter name="callback" type="android.webkit.ValueCallback&lt;java.lang.Boolean&gt;">
+</parameter>
+</method>
+<method name="getInstance"
+ return="android.webkit.GeolocationPermissions"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getOrigins"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.webkit.ValueCallback&lt;java.util.Set&gt;">
+</parameter>
+</method>
 </class>
 <interface name="GeolocationPermissions.Callback"
  abstract="true"
@@ -175517,6 +175749,27 @@
 >
 </method>
 </class>
+<interface name="ValueCallback"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onReceiveValue"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="T">
+</parameter>
+</method>
+</interface>
 <class name="WebBackForwardList"
  extends="java.lang.Object"
  abstract="false"
@@ -175592,6 +175845,58 @@
  visibility="public"
 >
 </constructor>
+<method name="addMessageToConsole"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="lineNumber" type="int">
+</parameter>
+<parameter name="sourceID" type="java.lang.String">
+</parameter>
+</method>
+<method name="getDefaultVideoPoster"
+ return="android.graphics.Bitmap"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVideoLoadingProgressView"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVisitedHistory"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.webkit.ValueCallback&lt;java.lang.String[]&gt;">
+</parameter>
+</method>
 <method name="onCloseWindow"
  return="void"
  abstract="false"
@@ -175673,6 +175978,17 @@
 <parameter name="callback" type="android.webkit.GeolocationPermissions.Callback">
 </parameter>
 </method>
+<method name="onHideCustomView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onJsAlert"
  return="boolean"
  abstract="false"
@@ -175751,6 +176067,17 @@
 <parameter name="result" type="android.webkit.JsPromptResult">
 </parameter>
 </method>
+<method name="onJsTimeout"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onProgressChanged"
  return="void"
  abstract="false"
@@ -175766,6 +176093,23 @@
 <parameter name="newProgress" type="int">
 </parameter>
 </method>
+<method name="onReachedMaxAppCacheSize"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="spaceNeeded" type="long">
+</parameter>
+<parameter name="totalUsedQuota" type="long">
+</parameter>
+<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
+</parameter>
+</method>
 <method name="onReceivedIcon"
  return="void"
  abstract="false"
@@ -175796,6 +176140,23 @@
 <parameter name="title" type="java.lang.String">
 </parameter>
 </method>
+<method name="onReceivedTouchIconUrl"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.webkit.WebView">
+</parameter>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="precomposed" type="boolean">
+</parameter>
+</method>
 <method name="onRequestFocus"
  return="void"
  abstract="false"
@@ -175809,7 +176170,41 @@
 <parameter name="view" type="android.webkit.WebView">
 </parameter>
 </method>
+<method name="onShowCustomView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="callback" type="android.webkit.WebChromeClient.CustomViewCallback">
+</parameter>
+</method>
 </class>
+<interface name="WebChromeClient.CustomViewCallback"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onCustomViewHidden"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
 <class name="WebHistoryItem"
  extends="java.lang.Object"
  abstract="false"
@@ -176113,6 +176508,28 @@
  visibility="public"
 >
 </method>
+<method name="getDefaultZoom"
+ return="android.webkit.WebSettings.ZoomDensity"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDomStorageEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFantasyFontFamily"
  return="java.lang.String"
  abstract="false"
@@ -176179,6 +176596,17 @@
  visibility="public"
 >
 </method>
+<method name="getLoadWithOverviewMode"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getLoadsImagesAutomatically"
  return="boolean"
  abstract="false"
@@ -176368,6 +176796,45 @@
 <parameter name="allow" type="boolean">
 </parameter>
 </method>
+<method name="setAppCacheEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flag" type="boolean">
+</parameter>
+</method>
+<method name="setAppCacheMaxSize"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appCacheMaxSize" type="long">
+</parameter>
+</method>
+<method name="setAppCachePath"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appCachePath" type="java.lang.String">
+</parameter>
+</method>
 <method name="setBlockNetworkImage"
  return="void"
  abstract="false"
@@ -176485,6 +176952,32 @@
 <parameter name="encoding" type="java.lang.String">
 </parameter>
 </method>
+<method name="setDefaultZoom"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="zoom" type="android.webkit.WebSettings.ZoomDensity">
+</parameter>
+</method>
+<method name="setDomStorageEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flag" type="boolean">
+</parameter>
+</method>
 <method name="setFantasyFontFamily"
  return="void"
  abstract="false"
@@ -176589,6 +177082,19 @@
 <parameter name="enabled" type="boolean">
 </parameter>
 </method>
+<method name="setLoadWithOverviewMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="overview" type="boolean">
+</parameter>
+</method>
 <method name="setLoadsImagesAutomatically"
  return="void"
  abstract="false"
@@ -177026,6 +177532,39 @@
 >
 </method>
 </class>
+<class name="WebSettings.ZoomDensity"
+ extends="java.lang.Enum"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="valueOf"
+ return="android.webkit.WebSettings.ZoomDensity"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="values"
+ return="android.webkit.WebSettings.ZoomDensity[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
 <class name="WebStorage"
  extends="java.lang.Object"
  abstract="false"
@@ -177042,6 +177581,99 @@
  visibility="public"
 >
 </constructor>
+<method name="deleteAllData"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="deleteOrigin"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="origin" type="java.lang.String">
+</parameter>
+</method>
+<method name="getInstance"
+ return="android.webkit.WebStorage"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getOrigins"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.webkit.ValueCallback&lt;java.util.Map&gt;">
+</parameter>
+</method>
+<method name="getQuotaForOrigin"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="origin" type="java.lang.String">
+</parameter>
+<parameter name="callback" type="android.webkit.ValueCallback&lt;java.lang.Long&gt;">
+</parameter>
+</method>
+<method name="getUsageForOrigin"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="origin" type="java.lang.String">
+</parameter>
+<parameter name="callback" type="android.webkit.ValueCallback&lt;java.lang.Long&gt;">
+</parameter>
+</method>
+<method name="setQuotaForOrigin"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="origin" type="java.lang.String">
+</parameter>
+<parameter name="quota" type="long">
+</parameter>
+</method>
 </class>
 <interface name="WebStorage.QuotaUpdater"
  abstract="true"
@@ -177483,6 +178115,17 @@
 <parameter name="vy" type="int">
 </parameter>
 </method>
+<method name="freeMemory"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getCertificate"
  return="android.net.http.SslCertificate"
  abstract="false"
@@ -189709,6 +190352,21 @@
 <parameter name="parcel" type="android.os.Parcel">
 </parameter>
 </constructor>
+<method name="addView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="nestedView" type="android.widget.RemoteViews">
+</parameter>
+</method>
 <method name="apply"
  return="android.view.View"
  abstract="false"
@@ -189785,6 +190443,19 @@
 <parameter name="v" type="android.view.View">
 </parameter>
 </method>
+<method name="removeAllViews"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+</method>
 <method name="setBitmap"
  return="void"
  abstract="false"
@@ -196370,6 +197041,17 @@
 <parameter name="attrs" type="android.util.AttributeSet">
 </parameter>
 </constructor>
+<method name="isAutoStart"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isFlipping"
  return="boolean"
  abstract="false"
@@ -196381,6 +197063,19 @@
  visibility="public"
 >
 </method>
+<method name="setAutoStart"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="autoStart" type="boolean">
+</parameter>
+</method>
 <method name="setFlipInterval"
  return="void"
  abstract="false"
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index cd71682..a796fe9 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -240,6 +240,28 @@
         private static final String[] PROJECTION = new String[] {_ID, MediaColumns.DATA};
         static final int DEFAULT_GROUP_ID = 0;
 
+        private static Bitmap getMiniThumbFromFile(Cursor c, Uri baseUri, ContentResolver cr, BitmapFactory.Options options) {
+            Bitmap bitmap = null;
+            Uri thumbUri = null;
+            try {
+                long thumbId = c.getLong(0);
+                String filePath = c.getString(1);
+                thumbUri = ContentUris.withAppendedId(baseUri, thumbId);
+                ParcelFileDescriptor pfdInput = cr.openFileDescriptor(thumbUri, "r");
+                bitmap = BitmapFactory.decodeFileDescriptor(
+                        pfdInput.getFileDescriptor(), null, options);
+                pfdInput.close();
+            } catch (FileNotFoundException ex) {
+                Log.e(TAG, "couldn't open thumbnail " + thumbUri + "; " + ex);
+            } catch (IOException ex) {
+                Log.e(TAG, "couldn't open thumbnail " + thumbUri + "; " + ex);
+            } catch (OutOfMemoryError ex) {
+                Log.e(TAG, "failed to allocate memory for thumbnail "
+                        + thumbUri + "; " + ex);
+            }
+            return bitmap;
+        }
+
         /**
          * This method cancels the thumbnail request so clients waiting for getThumbnail will be
          * interrupted and return immediately. Only the original process which made the getThumbnail
@@ -283,11 +305,12 @@
             Bitmap bitmap = null;
             String filePath = null;
             // Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo);
-            // some optimization for MICRO_KIND: if the magic is non-zero, we don't bother
+            // If the magic is non-zero, we simply return thumbnail if it does exist.
             // querying MediaProvider and simply return thumbnail.
-            if (kind == MICRO_KIND) {
-                MiniThumbFile thumbFile = MiniThumbFile.instance(baseUri);
-                if (thumbFile.getMagic(origId) != 0) {
+            MiniThumbFile thumbFile = MiniThumbFile.instance(baseUri);
+            long magic = thumbFile.getMagic(origId);
+            if (magic != 0) {
+                if (kind == MICRO_KIND) {
                     byte[] data = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
                     if (thumbFile.getMiniThumbFromFile(origId, data) != null) {
                         bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
@@ -296,6 +319,20 @@
                         }
                     }
                     return bitmap;
+                } else if (kind == MINI_KIND) {
+                    String column = isVideo ? "video_id=" : "image_id=";
+                    Cursor c = null;
+                    try {
+                        c = cr.query(baseUri, PROJECTION, column + origId, null, null);
+                        if (c != null && c.moveToFirst()) {
+                            bitmap = getMiniThumbFromFile(c, baseUri, cr, options);
+                            if (bitmap != null) {
+                                return bitmap;
+                            }
+                        }
+                    } finally {
+                        if (c != null) c.close();
+                    }
                 }
             }
 
@@ -310,7 +347,6 @@
 
                 // Assuming thumbnail has been generated, at least original image exists.
                 if (kind == MICRO_KIND) {
-                    MiniThumbFile thumbFile = MiniThumbFile.instance(baseUri);
                     byte[] data = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
                     if (thumbFile.getMiniThumbFromFile(origId, data) != null) {
                         bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
@@ -320,24 +356,7 @@
                     }
                 } else if (kind == MINI_KIND) {
                     if (c.moveToFirst()) {
-                        ParcelFileDescriptor pfdInput;
-                        Uri thumbUri = null;
-                        try {
-                            long thumbId = c.getLong(0);
-                            filePath = c.getString(1);
-                            thumbUri = ContentUris.withAppendedId(baseUri, thumbId);
-                            pfdInput = cr.openFileDescriptor(thumbUri, "r");
-                            bitmap = BitmapFactory.decodeFileDescriptor(
-                                    pfdInput.getFileDescriptor(), null, options);
-                            pfdInput.close();
-                        } catch (FileNotFoundException ex) {
-                            Log.e(TAG, "couldn't open thumbnail " + thumbUri + "; " + ex);
-                        } catch (IOException ex) {
-                            Log.e(TAG, "couldn't open thumbnail " + thumbUri + "; " + ex);
-                        } catch (OutOfMemoryError ex) {
-                            Log.e(TAG, "failed to allocate memory for thumbnail "
-                                    + thumbUri + "; " + ex);
-                        }
+                        bitmap = getMiniThumbFromFile(c, baseUri, cr, options);
                     }
                 } else {
                     throw new IllegalArgumentException("Unsupported kind: " + kind);
diff --git a/core/java/android/service/wallpaper/WallpaperSettingsActivity.java b/core/java/android/service/wallpaper/WallpaperSettingsActivity.java
index cde5ab25..501947da 100644
--- a/core/java/android/service/wallpaper/WallpaperSettingsActivity.java
+++ b/core/java/android/service/wallpaper/WallpaperSettingsActivity.java
@@ -24,7 +24,6 @@
  * Base class for activities that will be used to configure the settings of
  * a wallpaper.  You should derive from this class to allow it to select the
  * proper theme of the activity depending on how it is being used.
- * @hide Live Wallpaper
  */
 public class WallpaperSettingsActivity extends PreferenceActivity {
     /**
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 02e8d6f..75028de 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -109,9 +109,6 @@
             return expires;
         }
 
-        /**
-         * @hide Pending API council approval
-         */
         public String getExpiresString() {
             return expiresString;
         }
@@ -136,9 +133,6 @@
             return encoding;
         }
 
-        /**
-         * @hide Pending API council approval
-         */
         public String getContentDisposition() {
             return contentdisposition;
         }
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 4f8c227..4a8e758 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -170,8 +170,6 @@
     /**
      * Get the WebChromeClient.
      * @return the current WebChromeClient instance.
-     *
-     *@hide pending API council approval.
      */
     public WebChromeClient getWebChromeClient() {
        return mWebChromeClient;
@@ -1251,7 +1249,6 @@
      * @param quotaUpdater An instance of a class encapsulating a callback
      * to WebViewCore to run when the decision to allow or deny a bigger
      * app cache size has been made.
-     * @hide pending API council approval.
      */
     public void onReachedMaxAppCacheSize(long spaceNeeded,
             long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
@@ -1275,7 +1272,6 @@
      * @param origin The origin requesting Geolocation permsissions.
      * @param callback The callback to call once a permission state has been
      *     obtained.
-     * @hide pending API council review.
      */
     public void onGeolocationPermissionsShowPrompt(String origin,
             GeolocationPermissions.Callback callback) {
@@ -1295,8 +1291,6 @@
     /**
      * Called by WebViewCore to instruct the browser to hide the Geolocation
      * permissions prompt.
-     * origin.
-     * @hide pending API council review.
      */
     public void onGeolocationPermissionsHidePrompt() {
         if (mWebChromeClient == null) {
@@ -1315,7 +1309,6 @@
      *     occurred.
      * @param sourceID The filename of the source file in which the error
      *     occurred.
-     * @hide pending API counsel.
      */
     public void addMessageToConsole(String message, int lineNumber, String sourceID) {
         if (mWebChromeClient == null) {
@@ -1329,9 +1322,6 @@
         sendMessage(msg);
     }
 
-    /**
-     * @hide pending API council approval
-     */
     public boolean onJsTimeout() {
         //always interrupt timedout JS by default
         if (mWebChromeClient == null) {
@@ -1351,9 +1341,6 @@
         return result.getResult();
     }
 
-    /**
-     * @hide pending API council approval
-     */
     public void getVisitedHistory(ValueCallback<String[]> callback) {
         if (mWebChromeClient == null) {
             return;
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
index 483e9e9..64a9d9b 100755
--- a/core/java/android/webkit/GeolocationPermissions.java
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -71,7 +71,6 @@
 
     /**
      * Gets the singleton instance of the class.
-     * @hide
      */
     public static GeolocationPermissions getInstance() {
       if (sInstance == null) {
@@ -188,7 +187,6 @@
      * WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules'
      * (Database, Geolocation etc) do so, it's safe to match up origins for the
      * purposes of displaying UI.
-     * @hide
      */
     public void getOrigins(ValueCallback<Set> callback) {
         if (callback != null) {
@@ -212,7 +210,6 @@
 
     /**
      * Gets the permission state for the specified origin.
-     * @hide
      */
     public void getAllowed(String origin, ValueCallback<Boolean> callback) {
         if (callback == null) {
@@ -245,7 +242,6 @@
      * Clears the permission state for the specified origin. This method may be
      * called before the WebKit thread has intialized the message handler.
      * Messages will be queued until this time.
-     * @hide
      */
     public void clear(String origin) {
         // Called on the UI thread.
@@ -266,7 +262,6 @@
      * Allows the specified origin. This method may be called before the WebKit
      * thread has intialized the message handler. Messages will be queued until
      * this time.
-     * @hide
      */
     public void allow(String origin) {
         // Called on the UI thread.
@@ -285,7 +280,6 @@
 
     /**
      * Clears the permission state for all origins.
-     * @hide
      */
     public void clearAll() {
         // Called on the UI thread.
diff --git a/core/java/android/webkit/GeolocationService.java b/core/java/android/webkit/GeolocationService.java
index 646f8c5..24306f4 100755
--- a/core/java/android/webkit/GeolocationService.java
+++ b/core/java/android/webkit/GeolocationService.java
@@ -30,9 +30,8 @@
 
 /**
  * Implements the Java side of GeolocationServiceAndroid.
- * @hide Pending API council review.
  */
-public final class GeolocationService implements LocationListener {
+final class GeolocationService implements LocationListener {
 
     // Log tag
     private static final String TAG = "geolocationService";
diff --git a/core/java/android/webkit/GoogleLocationSettingManager.java b/core/java/android/webkit/GoogleLocationSettingManager.java
index 508df3b..ecac70a 100644
--- a/core/java/android/webkit/GoogleLocationSettingManager.java
+++ b/core/java/android/webkit/GoogleLocationSettingManager.java
@@ -32,7 +32,6 @@
  * Security - Share with Google' and the browser. When this setting is set
  * to true, we allow Geolocation for Google origins. When this setting is
  * set to false, we clear Geolocation permissions for Google origins.
- * @hide pending API council review
  */
 class GoogleLocationSettingManager {
     // The observer used to listen to the system setting.
diff --git a/core/java/android/webkit/MockGeolocation.java b/core/java/android/webkit/MockGeolocation.java
index 028cb19..fbda492 100644
--- a/core/java/android/webkit/MockGeolocation.java
+++ b/core/java/android/webkit/MockGeolocation.java
@@ -19,7 +19,7 @@
 /**
  * This class is simply a container for the methods used to configure WebKit's
  * mock Geolocation service for use in LayoutTests.
- * @hide Pending API council review.
+ * @hide
  */
 public final class MockGeolocation {
 
diff --git a/core/java/android/webkit/ValueCallback.java b/core/java/android/webkit/ValueCallback.java
index d8c5cdc..1a167e8 100644
--- a/core/java/android/webkit/ValueCallback.java
+++ b/core/java/android/webkit/ValueCallback.java
@@ -18,12 +18,10 @@
 
 /**
  * A callback interface used to returns values asynchronously
- *
- * @hide pending council approval
  */
-public interface ValueCallback<T>  {
-  /**
-   * Invoked when we have the result
-   */
-  public void onReceiveValue(T value);
+public interface ValueCallback<T> {
+    /**
+     * Invoked when we have the result
+     */
+    public void onReceiveValue(T value);
 };
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index ae4f7c2..6adac0b 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -50,7 +50,6 @@
      * @param view The WebView that initiated the callback.
      * @param url The icon url.
      * @param precomposed True if the url is for a precomposed touch icon.
-     * @hide pending council approval
      */
     public void onReceivedTouchIconUrl(WebView view, String url,
             boolean precomposed) {}
@@ -58,8 +57,6 @@
     /**
      * A callback interface used by the host application to notify
      * the current page that its custom view has been dismissed.
-     *
-     * @hide pending council approval
      */
     public interface CustomViewCallback {
         /**
@@ -75,16 +72,12 @@
      * @param view is the View object to be shown.
      * @param callback is the callback to be invoked if and when the view
      * is dismissed.
-     *
-     * @hide pending council approval
      */
     public void onShowCustomView(View view, CustomViewCallback callback) {};
 
     /**
      * Notify the host application that the current page would
      * like to hide its custom view.
-     *
-     * @hide pending council approval
      */
     public void onHideCustomView() {}
 
@@ -231,7 +224,6 @@
     * @param quotaUpdater A callback to inform the WebCore thread that a new
     * app cache size is available. This callback must always be executed at
     * some point to ensure that the sleeping WebCore thread is woken up.
-    * @hide pending API council approval.
     */
     public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
             WebStorage.QuotaUpdater quotaUpdater) {
@@ -259,7 +251,6 @@
      * will continue to occur if the script does not finish at the next check
      * point.
      * @return boolean Whether the JavaScript execution should be interrupted.
-     * @hide pending API Council approval
      */
     public boolean onJsTimeout() {
         return true;
@@ -271,7 +262,6 @@
      * @param message The error message to report.
      * @param lineNumber The line number of the error.
      * @param sourceID The name of the source file that caused the error.
-     * @hide pending API council.
      */
     public void addMessageToConsole(String message, int lineNumber, String sourceID) {}
 
@@ -280,7 +270,6 @@
      * This icon will be used if the Web page did not specify a poster attribute.
      *
      * @return Bitmap The icon or null if no such icon is available.
-     * @hide pending API Council approval
      */
     public Bitmap getDefaultVideoPoster() {
         return null;
@@ -291,14 +280,12 @@
      * a <video> is loading.
      *
      * @return View The progress view.
-     * @hide pending API Council approval
      */
     public View getVideoLoadingProgressView() {
         return null;
     }
 
     /** Obtains a list of all visited history items, used for link coloring
-     * @hide pending API Council approval
      */
     public void getVisitedHistory(ValueCallback<String[]> callback) {
     }
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 79d8c03..8e40b23 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -74,7 +74,6 @@
      * FAR makes 100% looking like in 240dpi
      * MEDIUM makes 100% looking like in 160dpi
      * CLOSE makes 100% looking like in 120dpi
-     * @hide Pending API council approval
      */
     public enum ZoomDensity {
         FAR(150),      // 240dpi
@@ -452,7 +451,6 @@
 
     /**
      * Set whether the WebView loads a page with overview mode.
-     * @hide Pending API council approval
      */
     public void setLoadWithOverviewMode(boolean overview) {
         mLoadWithOverviewMode = overview;
@@ -460,7 +458,6 @@
 
     /**
      * Returns true if this WebView loads page with overview mode
-     * @hide Pending API council approval
      */
     public boolean getLoadWithOverviewMode() {
         return mLoadWithOverviewMode;
@@ -522,7 +519,6 @@
      * thread.
      * @param zoom A ZoomDensity value
      * @see WebSettings.ZoomDensity
-     * @hide Pending API council approval
      */
     public void setDefaultZoom(ZoomDensity zoom) {
         if (mDefaultZoom != zoom) {
@@ -536,7 +532,6 @@
      * thread.
      * @return A ZoomDensity value
      * @see WebSettings.ZoomDensity
-     * @hide Pending API council approval
      */
     public ZoomDensity getDefaultZoom() {
         return mDefaultZoom;
@@ -1017,7 +1012,6 @@
     /**
      * Tell the WebView to enable Application Caches API.
      * @param flag True if the WebView should enable Application Caches.
-     * @hide pending api council approval
      */
     public synchronized void setAppCacheEnabled(boolean flag) {
         if (mAppCacheEnabled != flag) {
@@ -1032,7 +1026,6 @@
      * @param appCachePath String path to the directory containing Application
      * Caches files. The appCache path can be the empty string but should not
      * be null. Passing null for this parameter will result in a no-op.
-     * @hide pending api council approval
      */
     public synchronized void setAppCachePath(String appCachePath) {
         if (appCachePath != null && !appCachePath.equals(mAppCachePath)) {
@@ -1044,8 +1037,6 @@
     /**
      * Set the maximum size for the Application Caches content.
      * @param appCacheMaxSize the maximum size in bytes.
-     *
-     * @hide pending api council approval
      */
     public synchronized void setAppCacheMaxSize(long appCacheMaxSize) {
         if (appCacheMaxSize != mAppCacheMaxSize) {
@@ -1070,7 +1061,6 @@
      * Set whether the DOM storage API is enabled.
      * @param flag boolean True if the WebView should use the DOM storage
      *     API.
-     * @hide pending API council.
      */
     public synchronized void setDomStorageEnabled(boolean flag) {
        if (mDomStorageEnabled != flag) {
@@ -1082,7 +1072,6 @@
     /**
      * Returns true if the DOM Storage API's are enabled.
      * @return True if the DOM Storage API's are enabled.
-     * @hide pending API council.
      */
     public synchronized boolean getDomStorageEnabled() {
        return mDomStorageEnabled;
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 0022248..a182287 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -229,7 +229,6 @@
      */
 
     /**
-     * @hide
      * Returns a list of origins having a database
      */
     public void getOrigins(ValueCallback<Map> callback) {
@@ -256,7 +255,6 @@
     }
 
     /**
-     * @hide
      * Returns the use for a given origin
      */
     public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
@@ -280,7 +278,6 @@
     }
 
     /**
-     * @hide
      * Returns the quota for a given origin
      */
     public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
@@ -304,7 +301,6 @@
     }
 
     /**
-     * @hide
      * Set the quota for a given origin
      */
     public void setQuotaForOrigin(String origin, long quota) {
@@ -319,7 +315,6 @@
     }
 
     /**
-     * @hide
      * Delete a given origin
      */
     public void deleteOrigin(String origin) {
@@ -334,7 +329,6 @@
     }
 
     /**
-     * @hide
      * Delete all databases
      */
     public void deleteAllData() {
@@ -364,7 +358,6 @@
     }
 
     /**
-     * @hide
      * Get the global instance of WebStorage.
      * @return A single instance of WebStorage.
      */
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 630450d..9999573 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2277,7 +2277,6 @@
     /**
      * Call this to inform the view that memory is low so that it can
      * free any available memory.
-     * @hide
      */
     public void freeMemory() {
         mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 5991ad4..e353501 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2203,6 +2203,9 @@
                 clearScrollingCache();
             }
             mLastY = Integer.MIN_VALUE;
+            if (mTouchMode == TOUCH_MODE_FLING) {
+                return true;
+            }
             break;
         }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 6771711..3b1f7a0 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -457,6 +457,46 @@
         }
     }
 
+    /**
+     * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
+     * given {@link RemoteViews}, or calling {@link ViewGroup#removeAllViews()}
+     * when null. This allows users to build "nested" {@link RemoteViews}.
+     */
+    private class ViewGroupAction extends Action {
+        public ViewGroupAction(int viewId, RemoteViews nestedViews) {
+            this.viewId = viewId;
+            this.nestedViews = nestedViews;
+        }
+
+        public ViewGroupAction(Parcel parcel) {
+            viewId = parcel.readInt();
+            nestedViews = parcel.readParcelable(null);
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(TAG);
+            dest.writeInt(viewId);
+            dest.writeParcelable(nestedViews, 0 /* no flags */);
+        }
+
+        @Override
+        public void apply(View root) {
+            final Context context = root.getContext();
+            final ViewGroup target = (ViewGroup) root.findViewById(viewId);
+            if (nestedViews != null) {
+                // Inflate nested views and add as children
+                target.addView(nestedViews.apply(context, target));
+            } else if (target != null) {
+                // Clear all children when nested views omitted
+                target.removeAllViews();
+            }
+        }
+
+        int viewId;
+        RemoteViews nestedViews;
+
+        public final static int TAG = 4;
+    }
 
     /**
      * Create a new RemoteViews object that will display the views contained
@@ -493,6 +533,9 @@
                 case ReflectionAction.TAG:
                     mActions.add(new ReflectionAction(parcel));
                     break;
+                case ViewGroupAction.TAG:
+                    mActions.add(new ViewGroupAction(parcel));
+                    break;
                 default:
                     throw new ActionException("Tag " + tag + " not found");
                 }
@@ -519,7 +562,31 @@
         }
         mActions.add(a);
     }
-    
+
+    /**
+     * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
+     * given {@link RemoteViews}. This allows users to build "nested"
+     * {@link RemoteViews}. In cases where consumers of {@link RemoteViews} may
+     * recycle layouts, use {@link #removeAllViews(int)} to clear any existing
+     * children.
+     *
+     * @param viewId The id of the parent {@link ViewGroup} to add child into.
+     * @param nestedView {@link RemoteViews} that describes the child.
+     */
+    public void addView(int viewId, RemoteViews nestedView) {
+        addAction(new ViewGroupAction(viewId, nestedView));
+    }
+
+    /**
+     * Equivalent to calling {@link ViewGroup#removeAllViews()}.
+     *
+     * @param viewId The id of the parent {@link ViewGroup} to remove all
+     *            children from.
+     */
+    public void removeAllViews(int viewId) {
+        addAction(new ViewGroupAction(viewId, null));
+    }
+
     /**
      * Equivalent to calling View.setVisibility
      * 
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index 8a7946b..2dd79b2 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -16,8 +16,10 @@
 
 package android.widget;
 
-
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.TypedArray;
 import android.os.Handler;
 import android.os.Message;
@@ -30,10 +32,19 @@
  * requested, can automatically flip between each child at a regular interval.
  *
  * @attr ref android.R.styleable#ViewFlipper_flipInterval
+ * @attr ref android.R.styleable#ViewFlipper_autoStart
  */
+@RemoteView
 public class ViewFlipper extends ViewAnimator {
-    private int mFlipInterval = 3000;
-    private boolean mKeepFlipping = false;
+    private static final int DEFAULT_INTERVAL = 3000;
+
+    private int mFlipInterval = DEFAULT_INTERVAL;
+    private boolean mAutoStart = false;
+
+    private boolean mRunning = false;
+    private boolean mStarted = false;
+    private boolean mVisible = false;
+    private boolean mUserPresent = true;
 
     public ViewFlipper(Context context) {
         super(context);
@@ -44,14 +55,62 @@
 
         TypedArray a = context.obtainStyledAttributes(attrs,
                 com.android.internal.R.styleable.ViewFlipper);
-        mFlipInterval = a.getInt(com.android.internal.R.styleable.ViewFlipper_flipInterval,
-                3000);
+        mFlipInterval = a.getInt(
+                com.android.internal.R.styleable.ViewFlipper_flipInterval, DEFAULT_INTERVAL);
+        mAutoStart = a.getBoolean(
+                com.android.internal.R.styleable.ViewFlipper_autoStart, false);
         a.recycle();
     }
 
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+                mUserPresent = false;
+                updateRunning();
+            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
+                mUserPresent = true;
+                updateRunning();
+            }
+        }
+    };
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        // Listen for broadcasts related to user-presence
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(Intent.ACTION_USER_PRESENT);
+        getContext().registerReceiver(mReceiver, filter);
+
+        if (mAutoStart) {
+            // Automatically start when requested
+            startFlipping();
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mVisible = false;
+
+        getContext().unregisterReceiver(mReceiver);
+        updateRunning();
+    }
+
+    @Override
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        mVisible = visibility == VISIBLE;
+        updateRunning();
+    }
+
     /**
      * How long to wait before flipping to the next view
-     * 
+     *
      * @param milliseconds
      *            time in milliseconds
      */
@@ -64,26 +123,57 @@
      * Start a timer to cycle through child views
      */
     public void startFlipping() {
-        if (!mKeepFlipping) {
-            mKeepFlipping = true;
-            showOnly(mWhichChild);
-            Message msg = mHandler.obtainMessage(FLIP_MSG);
-            mHandler.sendMessageDelayed(msg, mFlipInterval);
-        }
+        mStarted = true;
+        updateRunning();
     }
 
     /**
      * No more flips
      */
     public void stopFlipping() {
-        mKeepFlipping = false;
+        mStarted = false;
+        updateRunning();
+    }
+
+    /**
+     * Internal method to start or stop dispatching flip {@link Message} based
+     * on {@link #mRunning} and {@link #mVisible} state.
+     */
+    private void updateRunning() {
+        boolean running = mVisible && mStarted && mUserPresent;
+        if (running != mRunning) {
+            if (running) {
+                showOnly(mWhichChild);
+                Message msg = mHandler.obtainMessage(FLIP_MSG);
+                mHandler.sendMessageDelayed(msg, mFlipInterval);
+            } else {
+                mHandler.removeMessages(FLIP_MSG);
+            }
+            mRunning = running;
+        }
     }
 
     /**
      * Returns true if the child views are flipping.
      */
     public boolean isFlipping() {
-        return mKeepFlipping;
+        return mStarted;
+    }
+
+    /**
+     * Set if this view automatically calls {@link #startFlipping()} when it
+     * becomes attached to a window.
+     */
+    public void setAutoStart(boolean autoStart) {
+        mAutoStart = autoStart;
+    }
+
+    /**
+     * Returns true if this view automatically calls {@link #startFlipping()}
+     * when it becomes attached to a window.
+     */
+    public boolean isAutoStart() {
+        return mAutoStart;
     }
 
     private final int FLIP_MSG = 1;
@@ -92,7 +182,7 @@
         @Override
         public void handleMessage(Message msg) {
             if (msg.what == FLIP_MSG) {
-                if (mKeepFlipping) {
+                if (mRunning) {
                     showNext();
                     msg = obtainMessage(FLIP_MSG);
                     sendMessageDelayed(msg, mFlipInterval);
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 81da739..df13403 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2138,6 +2138,8 @@
     </declare-styleable>
     <declare-styleable name="ViewFlipper">
         <attr name="flipInterval" format="integer" min="0" />
+        <!-- When true, automatically start animating -->
+        <attr name="autoStart" format="boolean" />
     </declare-styleable>
     <declare-styleable name="ViewSwitcher">
     </declare-styleable>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5eb1c8e..4ede620 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1201,8 +1201,8 @@
   <public type="attr" name="quickContactBadgeStyleSmallWindowSmall" />
   <public type="attr" name="quickContactBadgeStyleSmallWindowMedium" />
   <public type="attr" name="quickContactBadgeStyleSmallWindowLarge" />
-
   <public type="attr" name="wallpaperAuthor" />
   <public type="attr" name="wallpaperDescription" />
+  <public type="attr" name="autoStart" />
   
 </resources>