Merge "Doc change: Google Play services 4.0 reference docs." into klp-dev
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bd52f49..6ddd3fe 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1153,7 +1153,7 @@
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
          targetSdkVersion}</a> is 4 or higher.-->
     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_sdcardRead"
         android:description="@string/permdesc_sdcardRead"
         android:protectionLevel="normal" />
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index 07b08f6..9169658 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -227,6 +227,12 @@
 <table>
   <tr><th>Platform Version</th><th>API Level</th><th>VERSION_CODE</th><th>Notes</th></tr>
 
+    <tr><td><a href="{@docRoot}about/versions/android-4.4.html">Android 4.4</a></td>
+    <td><a href="{@docRoot}sdk/api_diff/19/changes.html" title="Diff Report">19</a></td>
+    <td>{@link android.os.Build.VERSION_CODES#KITKAT}</td>
+    <td><a href="{@docRoot}about/versions/kitkat.html">Platform
+Highlights</a></td></tr>
+
     <tr><td><a href="{@docRoot}about/versions/android-4.3.html">Android 4.3</a></td>
     <td><a href="{@docRoot}sdk/api_diff/18/changes.html" title="Diff Report">18</a></td>
     <td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}</td>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index eb2d6a7..71212ec 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,43 +5,43 @@
 page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
 
 
-sdk.linux32_bundle_download=adt-bundle-linux-x86-20130917.zip
-sdk.linux32_bundle_bytes=474924071
-sdk.linux32_bundle_checksum=912b2dac6e0a4fa4ae1417271bf42863
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20131028.zip
+sdk.linux32_bundle_bytes=496856894
+sdk.linux32_bundle_checksum=dfc1b314a07b5260941360d3e7542493
 
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130917.zip
-sdk.linux64_bundle_bytes=475215747
-sdk.linux64_bundle_checksum=2f7523d4eba9a8302c3c4a3955785e18
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20131028.zip
+sdk.linux64_bundle_bytes=497152039
+sdk.linux64_bundle_checksum=c5db52afa4d7d3b6b78793ccc98b036f
 
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130917.zip
-sdk.mac64_bundle_bytes=448581372
-sdk.mac64_bundle_checksum=4e2d599486ecc935d24eeef5eb641364
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20131028.zip
+sdk.mac64_bundle_bytes=470367339
+sdk.mac64_bundle_checksum=446f013ab88ff873985369e5405fda70
 
-sdk.win32_bundle_download=adt-bundle-windows-x86-20130917.zip
-sdk.win32_bundle_bytes=481803289
-sdk.win32_bundle_checksum=5d6c79a47c8b47170cff3d231dcf7ad3
+sdk.win32_bundle_download=adt-bundle-windows-x86-20131028.zip
+sdk.win32_bundle_bytes=503579820
+sdk.win32_bundle_checksum=8cfb299b548c1017dbe66259e136d1e7
 
-sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130917.zip
-sdk.win64_bundle_bytes=481934982
-sdk.win64_bundle_checksum=918f80aad61ec21509d86a2fbd87fd44
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20131028.zip
+sdk.win64_bundle_bytes=503715722
+sdk.win64_bundle_checksum=fc2c638d32293df8874dbcff3ab06e63
 
 
 
-sdk.linux_download=android-sdk_r22.2.1-linux.tgz
-sdk.linux_bytes=100918342
-sdk.linux_checksum=05911d3052a1cbf678561104d35a1bc0
+sdk.linux_download=android-sdk_r22.3-linux.tgz
+sdk.linux_bytes=100968558
+sdk.linux_checksum=6ae581a906d6420ad67176dff25a31cc
 
-sdk.mac_download=android-sdk_r22.2.1-macosx.zip
-sdk.mac_bytes=74859877
-sdk.mac_checksum=727a51affa2af733eca1aa307c73c3bd
+sdk.mac_download=android-sdk_r22.3-macosx.zip
+sdk.mac_bytes=74893875
+sdk.mac_checksum=ecde88ca1f05955826697848fcb4a9e7
 
-sdk.win_download=android-sdk_r22.2.1-windows.zip
-sdk.win_bytes=108797377
-sdk.win_checksum=bea5d28cfb6c073b32643dd3ed0bc1e0
+sdk.win_download=android-sdk_r22.3-windows.zip
+sdk.win_bytes=108847452
+sdk.win_checksum=9f0fe8c8884d6aee2b298fee203c62dc
 
-sdk.win_installer=installer_r22.2.1-windows.exe
-sdk.win_installer_bytes=88795776
-sdk.win_installer_checksum=07e6e47de6c4549bea6986453119b37c
+sdk.win_installer=installer_r22.3-windows.exe
+sdk.win_installer_bytes=88845794
+sdk.win_installer_checksum=ad50c4dd9e23cee65a1ed740ff3345fa
 
 
 
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 66b1c43..88fd7df 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
 page.title=Installing the Eclipse Plugin
-adt.zip.version=22.2.1
-adt.zip.download=ADT-22.2.1.zip
-adt.zip.bytes=14476845
-adt.zip.checksum=97176754a1e86adf2e5e05f44dc7229e
+adt.zip.version=22.3.0
+adt.zip.download=ADT-22.3.0.zip
+adt.zip.bytes=14493723
+adt.zip.checksum=0189080b23dfa0f866adafaaafcc34ab
 
 @jd:body
 
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index 02216de..f219784 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -50,13 +50,54 @@
 
 
 
-<h2 id="4.3">Android 4.3</h2>
+<h2 id="4.4">Android 4.4</h2>
 
 
 <div class="toggle-content opened">
 
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />Revision 1</a> <em>(October 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Initial release. The system version is 4.4.</p>
+    <dl>
+      <dt>Dependencies:</dt>
+      <dd>Android SDK Platform-tools r19 or higher is required.</dd>
+      <dd>Android SDK Tools 22.3 or higher is recommended.</dd>
+    </dl>
+
+  </div>
+</div>
+
+<h3 id="gsi-4.4">Google APIs System Image</h3>
+
+<div class="toggle-content opened">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />Revision 1</a> <em>(October 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Initial release. This release includes
+    <a href="{@docRoot}google/play-services/index.html">Google Play services</a> version 4.0.30,
+    allowing you to test your application in an emulator using the latest Google Play services.</p>
+
+  </div>
+</div>
+
+
+
+<h2 id="4.3">Android 4.3</h2>
+
+
+<div class="toggle-content closed">
+
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png"
 class="toggle-content-img" alt="" />Revision 2</a> <em>(August 2013)</em>
   </p>
 
@@ -91,11 +132,11 @@
   </div>
 </div>
 
-<h3 id="">Google APIs System Image</h3>
+<h3 id="gsi-4.3">Google APIs System Image</h3>
 
-<div class="toggle-content opened">
+<div class="toggle-content closed">
   <p><a href="#" onclick="return toggleContent(this)">
-    <img src="{@docRoot}assets/images/triangle-opened.png"
+    <img src="{@docRoot}assets/images/triangle-closed.png"
 class="toggle-content-img" alt="" />Revision 3</a> <em>(September 2013)</em>
   </p>
 
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index cfdf8cc..c584ae5 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,43 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 22.3.0</a> <em>(October 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 1.6 or higher is required.</li>
+      <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+      <li>This version of ADT is designed for use with
+        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.3</a>.
+        If you haven't already installed SDK Tools r22.3 into your SDK, use the
+        Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+      <li>Added support for Android 4.4 (API level 19).</li>
+      <li>Fixed problem with parsing view hierarchies containing classes in the java.*
+        name space.</li>
+      <li>Fixed problem importing Android projects that have the same name as an existing
+        project.</li>
+    </ul>
+  </dd>
+
+</dl>
+</div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 22.2.1</a> <em>(September 2013)</em>
   </p>
 
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 25c409e..c28b946 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -30,6 +30,38 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>SDK Tools, Revision 22.3</a> <em>(October 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+    <dd>
+      <ul>
+        <li>Android SDK Platform-tools revision 18 or later.</li>
+        <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
+          designed for use with ADT 22.3.0 and later. If you haven't already, update your
+        <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.3.0.</li>
+        <li>If you are developing outside Eclipse, you must have
+          <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+      <ul>
+        <li>Added support for Android 4.4 (API level 19).</li>
+        <li>Fixed a number of minor bugs in the SDK and build system.</li>
+      </ul>
+    </dd>
+    </dl>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>SDK Tools, Revision 22.2.1</a> <em>(September 2013)</em>
   </p>
 
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 4ee8c12..dba4e74 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -62,6 +62,58 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
+/>Android Support Library, revision 19</a> <em>(October 2013)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <dl>
+      <dt>Changes for v4 support library:</dt>
+      <dd>
+        <ul>
+          <li>Added support for external Storage APIs with the
+            {@link android.support.v4.content.ContextCompat#getObbDirs getObbDirs()},
+            {@link android.support.v4.content.ContextCompat#getExternalFilesDirs getExternalFilesDirs()},
+            {@link android.support.v4.content.ContextCompat#getExternalCacheDirs getExternalCacheDirs()},
+            and {@link android.support.v4.os.EnvironmentCompat#getStorageState getStorageState()}.
+            These helper methods always return a single file object on devices running Android
+            4.3 (API level 18) and earlier. When running on Android 4.4 (API level 19) and higher,
+            these methods may return more than one file object.</li>
+          <li>Added {@link android.support.v4.print.PrintHelper} class that works with the
+            Print APIs to print images with a minimum of code.</li>
+          <li>Added drag-to-open user interface support for pop-up menus. For more information, see
+            {@link android.support.v4.widget.PopupMenuCompat} and
+            {@link android.support.v4.widget.ListPopupWindowCompat}.</li>
+          <li>Improved accessibility support with the addition of a
+            {@link android.support.v4.view.accessibility.AccessibilityNodeProviderCompat#findFocus
+            findFocus()} method in
+            {@link android.support.v4.view.accessibility.AccessibilityNodeProviderCompat} and the
+            {@link android.support.v4.view.accessibility.AccessibilityNodeInfoCompat#getLiveRegion
+            getLiveRegion()} method in
+            {@link android.support.v4.view.accessibility.AccessibilityNodeInfoCompat}.</li>
+          <li>Added helper class {@link android.support.v4.view.ScaleGestureDetectorCompat} for
+            accessing new scaling gesture methods.</li>
+          <li>Fixed problem with {@link android.support.v4.app.ActionBarDrawerToggle} in
+            right-to-left language displays.</li>
+          <li>Modified {@link android.support.v4.widget.AutoScrollHelper} option to consume
+            touch events or allow them to be passed through to other views.</li>
+        </ul>
+      </dd>
+
+      <dt>Changes for v7 mediarouter library:</dt>
+      <dd>
+        <ul>
+          <li>Added support for media playback queuing, setting HTTP header values and media
+            playback duration.</li>
+          <li>Added explicit start, get, and end session actions for explicitly managing media
+            playback sessions with media router.</li>
+        </ul>
+      </dd>
+    </dl>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
 />Android Support Library, revision 18</a> <em>(July 2013)</em>
   </p>
   <div class="toggle-content-toggleme">
diff --git a/packages/WallpaperCropper/res/values/strings.xml b/packages/WallpaperCropper/res/values/strings.xml
index 2b8111d..091869a 100644
--- a/packages/WallpaperCropper/res/values/strings.xml
+++ b/packages/WallpaperCropper/res/values/strings.xml
@@ -17,4 +17,9 @@
     <string name="crop_wallpaper">Crop wallpaper</string>
     <!-- Button label on Wallpaper picker screen; user selects this button to set a specific wallpaper -->
     <string name="wallpaper_instructions">Set wallpaper</string>
+    <!-- Error message when an image is selected as a wallpaper,
+         but the wallpaper cropper cannot load it. The user will
+         usually see this when using another app and trying to set
+         an image as the wallpaper -->
+    <string name="wallpaper_load_fail">Couldn\'t load image as wallpaper</string>
 </resources>
diff --git a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
index b5774f4..e14f89a 100644
--- a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
+++ b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
@@ -31,6 +31,7 @@
 import android.util.Log;
 
 import com.android.gallery3d.common.BitmapUtils;
+import com.android.gallery3d.common.Utils;
 import com.android.gallery3d.exif.ExifInterface;
 import com.android.gallery3d.glrenderer.BasicTexture;
 import com.android.gallery3d.glrenderer.BitmapTexture;
@@ -41,6 +42,85 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+interface SimpleBitmapRegionDecoder {
+    int getWidth();
+    int getHeight();
+    Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options);
+}
+
+class SimpleBitmapRegionDecoderWrapper implements SimpleBitmapRegionDecoder {
+    BitmapRegionDecoder mDecoder;
+    private SimpleBitmapRegionDecoderWrapper(BitmapRegionDecoder decoder) {
+        mDecoder = decoder;
+    }
+    public static SimpleBitmapRegionDecoderWrapper newInstance(String pathName, boolean isShareable) {
+        try {
+            BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(pathName, isShareable);
+            if (d != null) {
+                return new SimpleBitmapRegionDecoderWrapper(d);
+            }
+        } catch (IOException e) {
+            Log.w("BitmapRegionTileSource", "getting decoder failed for path " + pathName, e);
+            return null;
+        }
+        return null;
+    }
+    public static SimpleBitmapRegionDecoderWrapper newInstance(InputStream is, boolean isShareable) {
+        try {
+            BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(is, isShareable);
+            if (d != null) {
+                return new SimpleBitmapRegionDecoderWrapper(d);
+            }
+        } catch (IOException e) {
+            Log.w("BitmapRegionTileSource", "getting decoder failed", e);
+            return null;
+        }
+        return null;
+    }
+    public int getWidth() {
+        return mDecoder.getWidth();
+    }
+    public int getHeight() {
+        return mDecoder.getHeight();
+    }
+    public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) {
+        return mDecoder.decodeRegion(wantRegion, options);
+    }
+}
+
+class DumbBitmapRegionDecoder implements SimpleBitmapRegionDecoder {
+    //byte[] streamCopy;
+    Bitmap mBuffer;
+    private DumbBitmapRegionDecoder(Bitmap b) {
+        mBuffer = b;
+    }
+    public static DumbBitmapRegionDecoder newInstance(String pathName) {
+        Bitmap b = BitmapFactory.decodeFile(pathName);
+        if (b != null) {
+            return new DumbBitmapRegionDecoder(b);
+        }
+        return null;
+    }
+    public static DumbBitmapRegionDecoder newInstance(InputStream is) {
+        Bitmap b = BitmapFactory.decodeStream(is);
+        if (b != null) {
+            return new DumbBitmapRegionDecoder(b);
+        }
+        return null;
+    }
+    public int getWidth() {
+        return mBuffer.getWidth();
+    }
+    public int getHeight() {
+        return mBuffer.getHeight();
+    }
+    public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) {
+        System.out.println("DECODING WITH SAMPLE LEVEL OF " + options.inSampleSize);
+        return Bitmap.createBitmap(
+                mBuffer, wantRegion.left, wantRegion.top, wantRegion.width(), wantRegion.height());
+    }
+}
+
 /**
  * A {@link com.android.photos.views.TiledImageRenderer.TileSource} using
  * {@link BitmapRegionDecoder} to wrap a local file
@@ -58,14 +138,16 @@
     public static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2;
 
     public static abstract class BitmapSource {
-        private BitmapRegionDecoder mDecoder;
+        private SimpleBitmapRegionDecoder mDecoder;
         private Bitmap mPreview;
         private int mPreviewSize;
         private int mRotation;
+        public enum State { NOT_LOADED, LOADED, ERROR_LOADING };
+        private State mState = State.NOT_LOADED;
         public BitmapSource(int previewSize) {
             mPreviewSize = previewSize;
         }
-        public void loadInBackground() {
+        public boolean loadInBackground() {
             ExifInterface ei = new ExifInterface();
             if (readExif(ei)) {
                 Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
@@ -74,22 +156,33 @@
                 }
             }
             mDecoder = loadBitmapRegionDecoder();
-            int width = mDecoder.getWidth();
-            int height = mDecoder.getHeight();
-            if (mPreviewSize != 0) {
-                int previewSize = Math.min(mPreviewSize, MAX_PREVIEW_SIZE);
-                BitmapFactory.Options opts = new BitmapFactory.Options();
-                opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
-                opts.inPreferQualityOverSpeed = true;
+            if (mDecoder == null) {
+                mState = State.ERROR_LOADING;
+                return false;
+            } else {
+                int width = mDecoder.getWidth();
+                int height = mDecoder.getHeight();
+                if (mPreviewSize != 0) {
+                    int previewSize = Math.min(mPreviewSize, MAX_PREVIEW_SIZE);
+                    BitmapFactory.Options opts = new BitmapFactory.Options();
+                    opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
+                    opts.inPreferQualityOverSpeed = true;
 
-                float scale = (float) previewSize / Math.max(width, height);
-                opts.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
-                opts.inJustDecodeBounds = false;
-                mPreview = loadPreviewBitmap(opts);
+                    float scale = (float) previewSize / Math.max(width, height);
+                    opts.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
+                    opts.inJustDecodeBounds = false;
+                    mPreview = loadPreviewBitmap(opts);
+                }
+                mState = State.LOADED;
+                return true;
             }
         }
 
-        public BitmapRegionDecoder getBitmapRegionDecoder() {
+        public State getLoadingState() {
+            return mState;
+        }
+
+        public SimpleBitmapRegionDecoder getBitmapRegionDecoder() {
             return mDecoder;
         }
 
@@ -106,7 +199,7 @@
         }
 
         public abstract boolean readExif(ExifInterface ei);
-        public abstract BitmapRegionDecoder loadBitmapRegionDecoder();
+        public abstract SimpleBitmapRegionDecoder loadBitmapRegionDecoder();
         public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options);
     }
 
@@ -117,13 +210,13 @@
             mPath = path;
         }
         @Override
-        public BitmapRegionDecoder loadBitmapRegionDecoder() {
-            try {
-                return BitmapRegionDecoder.newInstance(mPath, true);
-            } catch (IOException e) {
-                Log.w("BitmapRegionTileSource", "getting decoder failed", e);
-                return null;
+        public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() {
+            SimpleBitmapRegionDecoder d;
+            d = SimpleBitmapRegionDecoderWrapper.newInstance(mPath, true);
+            if (d == null) {
+                d = DumbBitmapRegionDecoder.newInstance(mPath);
             }
+            return d;
         }
         @Override
         public Bitmap loadPreviewBitmap(BitmapFactory.Options options) {
@@ -154,9 +247,17 @@
             return new BufferedInputStream(is);
         }
         @Override
-        public BitmapRegionDecoder loadBitmapRegionDecoder() {
+        public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() {
             try {
-                return BitmapRegionDecoder.newInstance(regenerateInputStream(), true);
+                InputStream is = regenerateInputStream();
+                SimpleBitmapRegionDecoder regionDecoder =
+                        SimpleBitmapRegionDecoderWrapper.newInstance(is, false);
+                Utils.closeSilently(is);
+                if (regionDecoder == null) {
+                    is = regenerateInputStream();
+                    regionDecoder = DumbBitmapRegionDecoder.newInstance(is);
+                }
+                return regionDecoder;
             } catch (FileNotFoundException e) {
                 Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
                 return null;
@@ -168,7 +269,10 @@
         @Override
         public Bitmap loadPreviewBitmap(BitmapFactory.Options options) {
             try {
-                return BitmapFactory.decodeStream(regenerateInputStream(), null, options);
+                InputStream is = regenerateInputStream();
+                Bitmap b = BitmapFactory.decodeStream(is, null, options);
+                Utils.closeSilently(is);
+                return b;
             } catch (FileNotFoundException e) {
                 Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
                 return null;
@@ -177,13 +281,15 @@
         @Override
         public boolean readExif(ExifInterface ei) {
             try {
-                ei.readExif(regenerateInputStream());
+                InputStream is = regenerateInputStream();
+                ei.readExif(is);
+                Utils.closeSilently(is);
                 return true;
             } catch (FileNotFoundException e) {
                 Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
                 return false;
             } catch (IOException e) {
-                Log.e("BitmapRegionTileSource", "Failure while reading URI " + mUri, e);
+                Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
                 return false;
             }
         }
@@ -202,13 +308,16 @@
             return new BufferedInputStream(is);
         }
         @Override
-        public BitmapRegionDecoder loadBitmapRegionDecoder() {
-            try {
-                return BitmapRegionDecoder.newInstance(regenerateInputStream(), true);
-            } catch (IOException e) {
-                Log.e("BitmapRegionTileSource", "Error reading resource", e);
-                return null;
+        public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() {
+            InputStream is = regenerateInputStream();
+            SimpleBitmapRegionDecoder regionDecoder =
+                    SimpleBitmapRegionDecoderWrapper.newInstance(is, false);
+            Utils.closeSilently(is);
+            if (regionDecoder == null) {
+                is = regenerateInputStream();
+                regionDecoder = DumbBitmapRegionDecoder.newInstance(is);
             }
+            return regionDecoder;
         }
         @Override
         public Bitmap loadPreviewBitmap(BitmapFactory.Options options) {
@@ -217,7 +326,9 @@
         @Override
         public boolean readExif(ExifInterface ei) {
             try {
-                ei.readExif(regenerateInputStream());
+                InputStream is = regenerateInputStream();
+                ei.readExif(is);
+                Utils.closeSilently(is);
                 return true;
             } catch (IOException e) {
                 Log.e("BitmapRegionTileSource", "Error reading resource", e);
@@ -226,7 +337,7 @@
         }
     }
 
-    BitmapRegionDecoder mDecoder;
+    SimpleBitmapRegionDecoder mDecoder;
     int mWidth;
     int mHeight;
     int mTileSize;
@@ -243,27 +354,29 @@
         mTileSize = TiledImageRenderer.suggestedTileSize(context);
         mRotation = source.getRotation();
         mDecoder = source.getBitmapRegionDecoder();
-        mWidth = mDecoder.getWidth();
-        mHeight = mDecoder.getHeight();
-        mOptions = new BitmapFactory.Options();
-        mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
-        mOptions.inPreferQualityOverSpeed = true;
-        mOptions.inTempStorage = new byte[16 * 1024];
-        int previewSize = source.getPreviewSize();
-        if (previewSize != 0) {
-            previewSize = Math.min(previewSize, MAX_PREVIEW_SIZE);
-            // Although this is the same size as the Bitmap that is likely already
-            // loaded, the lifecycle is different and interactions are on a different
-            // thread. Thus to simplify, this source will decode its own bitmap.
-            Bitmap preview = decodePreview(source, previewSize);
-            if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) {
-                mPreview = new BitmapTexture(preview);
-            } else {
-                Log.w(TAG, String.format(
-                        "Failed to create preview of apropriate size! "
-                        + " in: %dx%d, out: %dx%d",
-                        mWidth, mHeight,
-                        preview.getWidth(), preview.getHeight()));
+        if (mDecoder != null) {
+            mWidth = mDecoder.getWidth();
+            mHeight = mDecoder.getHeight();
+            mOptions = new BitmapFactory.Options();
+            mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
+            mOptions.inPreferQualityOverSpeed = true;
+            mOptions.inTempStorage = new byte[16 * 1024];
+            int previewSize = source.getPreviewSize();
+            if (previewSize != 0) {
+                previewSize = Math.min(previewSize, MAX_PREVIEW_SIZE);
+                // Although this is the same size as the Bitmap that is likely already
+                // loaded, the lifecycle is different and interactions are on a different
+                // thread. Thus to simplify, this source will decode its own bitmap.
+                Bitmap preview = decodePreview(source, previewSize);
+                if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) {
+                    mPreview = new BitmapTexture(preview);
+                } else {
+                    Log.w(TAG, String.format(
+                            "Failed to create preview of apropriate size! "
+                            + " in: %dx%d, out: %dx%d",
+                            mWidth, mHeight,
+                            preview.getWidth(), preview.getHeight()));
+                }
             }
         }
     }
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index 220f567..d12140d 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -41,10 +41,12 @@
 import android.view.Display;
 import android.view.View;
 import android.view.WindowManager;
+import android.widget.Toast;
 
 import com.android.gallery3d.common.Utils;
 import com.android.gallery3d.exif.ExifInterface;
 import com.android.photos.BitmapRegionTileSource;
+import com.android.photos.BitmapRegionTileSource.BitmapSource;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
@@ -109,12 +111,24 @@
                 });
 
         // Load image in background
-        setCropViewTileSource(
-                new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024), true, false);
+        final BitmapRegionTileSource.UriBitmapSource bitmapSource =
+                new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024);
+        Runnable onLoad = new Runnable() {
+            public void run() {
+                if (bitmapSource.getLoadingState() != BitmapSource.State.LOADED) {
+                    Toast.makeText(WallpaperCropActivity.this,
+                            getString(R.string.wallpaper_load_fail),
+                            Toast.LENGTH_LONG).show();
+                    finish();
+                }
+            }
+        };
+        setCropViewTileSource(bitmapSource, true, false, onLoad);
     }
 
-    public void setCropViewTileSource(final BitmapRegionTileSource.BitmapSource bitmapSource,
-            final boolean touchEnabled, final boolean moveToLeft) {
+    public void setCropViewTileSource(
+            final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled,
+            final boolean moveToLeft, final Runnable postExecute) {
         final Context context = WallpaperCropActivity.this;
         final View progressView = findViewById(R.id.loading);
         final AsyncTask<Void, Void, Void> loadBitmapTask = new AsyncTask<Void, Void, Void>() {
@@ -127,13 +141,18 @@
             protected void onPostExecute(Void arg) {
                 if (!isCancelled()) {
                     progressView.setVisibility(View.INVISIBLE);
-                    mCropView.setTileSource(
-                            new BitmapRegionTileSource(context, bitmapSource), null);
-                    mCropView.setTouchEnabled(touchEnabled);
-                    if (moveToLeft) {
-                        mCropView.moveToLeft();
+                    if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
+                        mCropView.setTileSource(
+                                new BitmapRegionTileSource(context, bitmapSource), null);
+                        mCropView.setTouchEnabled(touchEnabled);
+                        if (moveToLeft) {
+                            mCropView.moveToLeft();
+                        }
                     }
                 }
+                if (postExecute != null) {
+                    postExecute.run();
+                }
             }
         };
         // We don't want to show the spinner every time we load an image, because that would be
@@ -235,10 +254,12 @@
                 InputStream is = context.getContentResolver().openInputStream(uri);
                 BufferedInputStream bis = new BufferedInputStream(is);
                 ei.readExif(bis);
+                bis.close();
             } else {
                 InputStream is = res.openRawResource(resId);
                 BufferedInputStream bis = new BufferedInputStream(is);
                 ei.readExif(bis);
+                bis.close();
             }
             Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
             if (ori != null) {
@@ -408,7 +429,6 @@
         String mInFilePath;
         byte[] mInImageBytes;
         int mInResId = 0;
-        InputStream mInStream;
         RectF mCropBounds = null;
         int mOutWidth, mOutHeight;
         int mRotation;
@@ -481,37 +501,36 @@
         }
 
         // Helper to setup input stream
-        private void regenerateInputStream() {
+        private InputStream regenerateInputStream() {
             if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) {
                 Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " +
                         "image byte array given");
             } else {
-                Utils.closeSilently(mInStream);
                 try {
                     if (mInUri != null) {
-                        mInStream = new BufferedInputStream(
+                        return new BufferedInputStream(
                                 mContext.getContentResolver().openInputStream(mInUri));
                     } else if (mInFilePath != null) {
-                        mInStream = mContext.openFileInput(mInFilePath);
+                        return mContext.openFileInput(mInFilePath);
                     } else if (mInImageBytes != null) {
-                        mInStream = new BufferedInputStream(
-                                new ByteArrayInputStream(mInImageBytes));
+                        return new BufferedInputStream(new ByteArrayInputStream(mInImageBytes));
                     } else {
-                        mInStream = new BufferedInputStream(
-                                mResources.openRawResource(mInResId));
+                        return new BufferedInputStream(mResources.openRawResource(mInResId));
                     }
                 } catch (FileNotFoundException e) {
                     Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);
                 }
             }
+            return null;
         }
 
         public Point getImageBounds() {
-            regenerateInputStream();
-            if (mInStream != null) {
+            InputStream is = regenerateInputStream();
+            if (is != null) {
                 BitmapFactory.Options options = new BitmapFactory.Options();
                 options.inJustDecodeBounds = true;
-                BitmapFactory.decodeStream(mInStream, null, options);
+                BitmapFactory.decodeStream(is, null, options);
+                Utils.closeSilently(is);
                 if (options.outWidth != 0 && options.outHeight != 0) {
                     return new Point(options.outWidth, options.outHeight);
                 }
@@ -529,22 +548,26 @@
         public boolean cropBitmap() {
             boolean failure = false;
 
-            regenerateInputStream();
 
             WallpaperManager wallpaperManager = null;
             if (mSetWallpaper) {
                 wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext());
             }
-            if (mSetWallpaper && mNoCrop && mInStream != null) {
+
+
+            if (mSetWallpaper && mNoCrop) {
                 try {
-                    wallpaperManager.setStream(mInStream);
+                    InputStream is = regenerateInputStream();
+                    if (is != null) {
+                        wallpaperManager.setStream(is);
+                        Utils.closeSilently(is);
+                    }
                 } catch (IOException e) {
                     Log.w(LOGTAG, "cannot write stream to wallpaper", e);
                     failure = true;
                 }
                 return !failure;
-            }
-            if (mInStream != null) {
+            } else {
                 // Find crop bounds (scaled to original image size)
                 Rect roundedTrueCrop = new Rect();
                 Matrix rotateMatrix = new Matrix();
@@ -557,6 +580,11 @@
                     mCropBounds = new RectF(roundedTrueCrop);
 
                     Point bounds = getImageBounds();
+                    if (bounds == null) {
+                        Log.w(LOGTAG, "cannot get bounds for image");
+                        failure = true;
+                        return false;
+                    }
 
                     float[] rotatedBounds = new float[] { bounds.x, bounds.y };
                     rotateMatrix.mapPoints(rotatedBounds);
@@ -567,7 +595,6 @@
                     inverseRotateMatrix.mapRect(mCropBounds);
                     mCropBounds.offset(bounds.x/2, bounds.y/2);
 
-                    regenerateInputStream();
                 }
 
                 mCropBounds.roundOut(roundedTrueCrop);
@@ -585,7 +612,14 @@
                 // Attempt to open a region decoder
                 BitmapRegionDecoder decoder = null;
                 try {
-                    decoder = BitmapRegionDecoder.newInstance(mInStream, true);
+                    InputStream is = regenerateInputStream();
+                    if (is == null) {
+                        Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString());
+                        failure = true;
+                        return false;
+                    }
+                    decoder = BitmapRegionDecoder.newInstance(is, false);
+                    Utils.closeSilently(is);
                 } catch (IOException e) {
                     Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
                 }
@@ -603,14 +637,15 @@
 
                 if (crop == null) {
                     // BitmapRegionDecoder has failed, try to crop in-memory
-                    regenerateInputStream();
+                    InputStream is = regenerateInputStream();
                     Bitmap fullSize = null;
-                    if (mInStream != null) {
+                    if (is != null) {
                         BitmapFactory.Options options = new BitmapFactory.Options();
                         if (scaleDownSampleSize > 1) {
                             options.inSampleSize = scaleDownSampleSize;
                         }
-                        fullSize = BitmapFactory.decodeStream(mInStream, null, options);
+                        fullSize = BitmapFactory.decodeStream(is, null, options);
+                        Utils.closeSilently(is);
                     }
                     if (fullSize != null) {
                         mCropBounds.left /= scaleDownSampleSize;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index dcaf3d6..faca949 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3466,6 +3466,8 @@
                 if (mStatusBarController.setBarShowingLw(true)) {
                     changes |= FINISH_LAYOUT_REDO_LAYOUT;
                 }
+                // Maintain fullscreen layout until incoming animation is complete.
+                topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
             } else if (mTopFullscreenOpaqueWindowState != null) {
                 if (localLOGV) {
                     Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
@@ -3499,7 +3501,13 @@
             }
         }
 
-        mTopIsFullscreen = topIsFullscreen;
+        if (mTopIsFullscreen != topIsFullscreen) {
+            if (!topIsFullscreen) {
+                // Force another layout when status bar becomes fully shown.
+                changes |= FINISH_LAYOUT_REDO_LAYOUT;
+            }
+            mTopIsFullscreen = topIsFullscreen;
+        }
 
         // Hide the key guard if a visible window explicitly specifies that it wants to be
         // displayed when the screen is locked.
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 2e5dedf..44ff3bc 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -3408,6 +3408,9 @@
             int numActivities = 0;
             int numRunning = 0;
             final ArrayList<ActivityRecord> activities = task.mActivities;
+            if (activities.isEmpty()) {
+                continue;
+            }
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 r = activities.get(activityNdx);
 
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index a781d5f..3d6b3c9 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -9965,6 +9965,10 @@
         // writer
         int callingUid = Binder.getCallingUid();
         enforceCrossUserPermission(callingUid, userId, true, "add preferred activity");
+        if (filter.countActions() == 0) {
+            Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
+            return;
+        }
         synchronized (mPackages) {
             if (mContext.checkCallingOrSelfPermission(
                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -10024,7 +10028,9 @@
                 String category = filter.getCategory(0);
                 while (it.hasNext()) {
                     PreferredActivity pa = it.next();
-                    if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
+                    if ((pa.countActions() == 0) || (pa.countCategories() == 0)
+                            || (pa.getAction(0).equals(action)
+                                    && pa.getCategory(0).equals(category))) {
                         if (removed == null) {
                             removed = new ArrayList<PreferredActivity>();
                         }
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index af00d83..c405170 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -360,6 +360,10 @@
                     + mWin.mToken + ": first real window done animating");
             mService.mFinishedStarting.add(mWin.mAppToken);
             mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
+        } else if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
+            // Upon completion of a not-visible to visible status bar animation a relayout is
+            // required.
+            mWin.mDisplayContent.layoutNeeded = true;
         }
 
         finishExit();