Merge Android 14 QPR3 to AOSP main

Bug: 346855327
Merged-In: I4dbe8a64fcdb66957924b18b9c2ad27b4ed61c20
Change-Id: Ibec9f0f5183fbf741638063f14bd0e8dd84a58dc
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
index 1f28572..2723c41 100644
--- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -29,7 +29,7 @@
  */
 public class ExtensionVersionImpl {
     private static final String TAG = "ExtenderVersionImpl";
-    private static final String VERSION = "1.4.0";
+    private static final String VERSION = "1.5.0";
 
     /**
      * @hide
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
index abcbf5f..821b11f 100644
--- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
@@ -216,4 +217,20 @@
      * @since 1.4
      */
     boolean isPostviewAvailable();
+
+    /**
+     * Returns a list of {@link CameraCharacteristics} key/value pairs for apps to use when
+     * querying the Extensions specific {@link CameraCharacteristics}.
+     *
+     * <p>To ensure the correct {@link CameraCharacteristics} are used when an extension is
+     * enabled, an application should prioritize the value returned from the list if the
+     * {@link CameraCharacteristics} key is present. If the key doesn't exist in the returned list,
+     * then the application should query the value using
+     * {@link CameraCharacteristics#get(CameraCharacteristics.Key)}.
+     *
+     * <p>For example, an extension may limit the zoom ratio range. In this case, an OEM can return
+     * a new zoom ratio range for the key {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE}.
+     * @since 1.5
+     */
+    List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues();
 }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java
index 00b5705..b97fdbd 100644
--- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java
@@ -26,11 +26,13 @@
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.DataSpace;
 import android.media.Image;
 import android.media.Image.Plane;
 import android.media.ImageWriter;
@@ -112,7 +114,8 @@
 
     @Override
     public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId) {
-        return filterOutputResolutions(Arrays.asList(ImageFormat.JPEG, ImageFormat.YUV_420_888));
+        return filterOutputResolutions(Arrays.asList(ImageFormat.JPEG, ImageFormat.YUV_420_888,
+                ImageFormat.JPEG_R));
     }
 
     @Override
@@ -157,6 +160,8 @@
 
         protected AtomicInteger mNextCaptureSequenceId = new AtomicInteger(1);
 
+        protected boolean mProcessCapture = true;
+
         protected void appendTag(String tag) {
             TAG += tag;
         }
@@ -192,17 +197,33 @@
 
             // Image Capture
             if (mCaptureOutputSurfaceConfig.getSurface() != null) {
-                Camera2OutputConfigImplBuilder captureOutputConfigBuilder;
 
-                captureOutputConfigBuilder =
-                        Camera2OutputConfigImplBuilder.newImageReaderConfig(
-                                mCaptureOutputSurfaceConfig.getSize(),
-                                ImageFormat.YUV_420_888,
-                                BASIC_CAPTURE_PROCESS_MAX_IMAGES);
+                // For this sample, JPEG_R will not be processed
+                if (isJpegR(mCaptureOutputSurfaceConfig)) {
+                    Camera2OutputConfigImplBuilder captureOutputConfigBuilder;
 
-                mCaptureOutputConfig = captureOutputConfigBuilder.build();
+                    captureOutputConfigBuilder =
+                            Camera2OutputConfigImplBuilder.newSurfaceConfig(
+                                        mCaptureOutputSurfaceConfig.getSurface());
 
-                builder.addOutputConfig(mCaptureOutputConfig);
+                    mCaptureOutputConfig = captureOutputConfigBuilder.build();
+
+                    builder.addOutputConfig(mCaptureOutputConfig);
+                    mProcessCapture = false;
+                } else {
+                    Camera2OutputConfigImplBuilder captureOutputConfigBuilder;
+
+                    captureOutputConfigBuilder =
+                            Camera2OutputConfigImplBuilder.newImageReaderConfig(
+                                    mCaptureOutputSurfaceConfig.getSize(),
+                                    ImageFormat.YUV_420_888,
+                                    BASIC_CAPTURE_PROCESS_MAX_IMAGES,
+                                    mCaptureOutputSurfaceConfig.getUsage());
+
+                    mCaptureOutputConfig = captureOutputConfigBuilder.build();
+
+                    builder.addOutputConfig(mCaptureOutputConfig);
+                }
             }
 
             addSessionParameter(builder);
@@ -263,6 +284,19 @@
             }
         }
 
+        protected boolean isJpegR(OutputSurfaceImpl surfaceConfig) {
+            // The surface configuration format for JPEG_R can be specified in either format.
+            // Camera2 uses HAL_PIXEL_FORMAT_BLOB and CameraX uses ImageFormat.JPEG_R.
+            return ((surfaceConfig.getImageFormat() == JpegEncoder.HAL_PIXEL_FORMAT_BLOB) &&
+                    (surfaceConfig.getDataspace() == DataSpace.DATASPACE_JPEG_R)) ||
+                    (surfaceConfig.getImageFormat() == ImageFormat.JPEG_R);
+        }
+
+        protected boolean isJpeg(OutputSurfaceImpl surfaceConfig) {
+            return (JpegEncoder.imageFormatToPublic(surfaceConfig.getImageFormat()) ==
+                    ImageFormat.JPEG) || (surfaceConfig.getImageFormat() == ImageFormat.JPEG);
+        }
+
         protected void addTriggerRequestKeys(RequestBuilder builder,
                 Map<CaptureRequest.Key<?>, Object> triggers) {
             HashSet<CaptureRequest.Key> supportedCaptureRequestKeys =
@@ -309,13 +343,13 @@
                 @Override
                 public void onCaptureFailed(RequestProcessorImpl.Request request,
                         CaptureFailure captureFailure) {
-                    captureCallback.onCaptureFailed(seqId);
+                    captureCallback.onCaptureFailed(seqId, captureFailure.getReason());
                 }
 
                 @Override
                 public void onCaptureBufferLost(RequestProcessorImpl.Request request,
                         long frameNumber, int outputStreamId) {
-                    captureCallback.onCaptureFailed(seqId);
+                    captureCallback.onCaptureFailed(seqId, CaptureFailure.REASON_ERROR);
                 }
 
                 @Override
@@ -340,16 +374,21 @@
 
             if (mCaptureOutputSurfaceConfig.getSurface() != null) {
                 synchronized (mLockCaptureSurfaceImageWriter) {
-                    if (JpegEncoder.imageFormatToPublic(mCaptureOutputSurfaceConfig
-                            .getImageFormat()) == ImageFormat.JPEG) {
+                    if (isJpegR(mCaptureOutputSurfaceConfig)) {
+                        return;
+                    }
+
+                    if (isJpeg(mCaptureOutputSurfaceConfig)) {
                         mCaptureSurfaceImageWriter = new ImageWriter
                                 .Builder(mCaptureOutputSurfaceConfig.getSurface())
                                 .setImageFormat(ImageFormat.JPEG)
                                 .setMaxImages(MAX_NUM_IMAGES)
                                 // For JPEG format, width x height should be set to (w*h) x 1
                                 // since the JPEG image is returned as a 1D byte array
-                                .setWidthAndHeight(mCaptureOutputSurfaceConfig.getSize().getWidth()
-                                        * mCaptureOutputSurfaceConfig.getSize().getHeight(), 1)
+                                .setWidthAndHeight(
+                                        mCaptureOutputSurfaceConfig.getSize().getWidth()
+                                        * mCaptureOutputSurfaceConfig.getSize().getHeight(),
+                                        1)
                                 .build();
                     } else {
                         mCaptureSurfaceImageWriter = new ImageWriter
@@ -402,13 +441,13 @@
                 @Override
                 public void onCaptureFailed(RequestProcessorImpl.Request request,
                         CaptureFailure captureFailure) {
-                    captureCallback.onCaptureFailed(seqId);
+                    captureCallback.onCaptureFailed(seqId, captureFailure.getReason());
                 }
 
                 @Override
                 public void onCaptureBufferLost(RequestProcessorImpl.Request request,
                         long frameNumber, int outputStreamId) {
-                    captureCallback.onCaptureFailed(seqId);
+                    captureCallback.onCaptureFailed(seqId, CaptureFailure.REASON_ERROR);
                 }
 
                 @Override
@@ -490,21 +529,25 @@
 
                     addCaptureResultKeys(seqId, totalCaptureResult, captureCallback);
 
-                    mImageCaptureCaptureResultImageMatcher.setCameraCaptureCallback(
-                            totalCaptureResult,
-                            requestProcessorRequest.getCaptureStageId());
+                    if (!mProcessCapture) {
+                        captureCallback.onCaptureProcessStarted(seqId);
+                    } else {
+                        mImageCaptureCaptureResultImageMatcher.setCameraCaptureCallback(
+                                totalCaptureResult,
+                                requestProcessorRequest.getCaptureStageId());
+                    }
                 }
 
                 @Override
                 public void onCaptureFailed(RequestProcessorImpl.Request request,
                         CaptureFailure captureFailure) {
-                    captureCallback.onCaptureFailed(seqId);
+                    captureCallback.onCaptureFailed(seqId, captureFailure.getReason());
                 }
 
                 @Override
                 public void onCaptureBufferLost(RequestProcessorImpl.Request request,
                         long frameNumber, int outputStreamId) {
-                    captureCallback.onCaptureFailed(seqId);
+                    captureCallback.onCaptureFailed(seqId, CaptureFailure.REASON_ERROR);
                 }
 
                 @Override
@@ -523,7 +566,7 @@
 
             mRequestProcessor.submit(requestList, callback);
 
-            if (mCaptureOutputSurfaceConfig.getSurface() != null) {
+            if (mCaptureOutputSurfaceConfig.getSurface() != null && mProcessCapture) {
                 mRequestProcessor.setImageProcessor(mCaptureOutputConfig.getId(),
                         new ImageProcessorImpl() {
                                 @Override
@@ -696,4 +739,21 @@
     public boolean isPostviewAvailable() {
         return false;
     }
+
+    @Override
+    public List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues() {
+        Range<Float> zoomRange = mCameraCharacteristics
+                    .get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE);
+        float zoomRangeLower = Math.max(1f, zoomRange.getLower());
+        float zoomRangeUpper = Math.min(10f, zoomRange.getUpper());
+        return Arrays.asList(
+                Pair.create(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE,
+                        Range.create(zoomRangeLower, zoomRangeUpper)),
+                Pair.create(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES,
+                        new int[]{
+                                CameraMetadata.CONTROL_AF_MODE_OFF,
+                                CameraMetadata.CONTROL_AF_MODE_AUTO
+                        })
+        );
+    }
 }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
index 868be83..9ae5f83 100644
--- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
@@ -49,9 +49,9 @@
      * with the given parameters.
      */
     public static Camera2OutputConfigImplBuilder newImageReaderConfig(
-            Size size, int imageFormat, int maxImages) {
+            Size size, int imageFormat, int maxImages, long usage) {
         return new Camera2OutputConfigImplBuilder(
-                new ImageReaderOutputConfigImplImpl(size, imageFormat, maxImages));
+                new ImageReaderOutputConfigImplImpl(size, imageFormat, maxImages, usage));
     }
 
     /**
@@ -181,11 +181,14 @@
         private Size mSize;
         private int mImageFormat;
         private int mMaxImages;
+        private long mUsage;
 
-        ImageReaderOutputConfigImplImpl(Size size, int imageFormat, int maxImages) {
+        ImageReaderOutputConfigImplImpl(Size size, int imageFormat, int maxImages,
+                long usage) {
             mSize = size;
             mImageFormat = imageFormat;
             mMaxImages = maxImages;
+            mUsage = usage;
         }
 
         @Override
@@ -202,6 +205,11 @@
         public int getMaxImages() {
             return mMaxImages;
         }
+
+        @Override
+        public long getUsage() {
+            return mUsage;
+        }
     }
 
     private static class MultiResolutionImageReaderOutputConfigImplImpl extends OutputConfigImplImpl
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/EyesFreeVideographyAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/EyesFreeVideographyAdvancedExtenderImpl.java
new file mode 100644
index 0000000..2f6d1cf
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/EyesFreeVideographyAdvancedExtenderImpl.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stub advanced extender implementation for eyes free videography.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.5
+ */
+@SuppressLint("UnknownNullness")
+public class EyesFreeVideographyAdvancedExtenderImpl implements AdvancedExtenderImpl {
+    public EyesFreeVideographyAdvancedExtenderImpl() {
+    }
+
+    @Override
+    public boolean isExtensionAvailable(String cameraId,
+            Map<String, CameraCharacteristics> characteristicsMap) {
+        return false;
+    }
+
+    @Override
+    public void init(String cameraId,
+            Map<String, CameraCharacteristics> characteristicsMap) {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public Range<Long> getEstimatedCaptureLatencyRange(
+            String cameraId, Size size, int imageFormat) {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+            String cameraId) {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+
+    @Override
+    public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+            String cameraId) {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public Map<Integer, List<Size>> getSupportedPostviewResolutions(
+            Size captureSize) {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public List<Size> getSupportedYuvAnalysisResolutions(
+            String cameraId) {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public SessionProcessorImpl createSessionProcessor() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public boolean isCaptureProcessProgressAvailable() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public boolean isPostviewAvailable() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+
+    @Override
+    public List<Pair<CameraCharacteristics.Key, Object>>
+            getAvailableCharacteristicsKeyValues() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
index d8b9928..68a84b7 100644
--- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
@@ -129,7 +129,11 @@
         @Override
         public int startCapture(@NonNull CaptureCallback captureCallback) {
             List<RequestProcessorImpl.Request> requestList = new ArrayList<>();
-            addCaptureRequestParameters(requestList);
+            if (mProcessCapture) {
+                addCaptureRequestParameters(requestList);
+            } else {
+                super.addCaptureRequestParameters(requestList);
+            }
             final int seqId = mNextCaptureSequenceId.getAndIncrement();
 
             RequestProcessorImpl.Callback callback = new RequestProcessorImpl.Callback() {
@@ -138,7 +142,7 @@
                 @Override
                 public void onCaptureStarted(RequestProcessorImpl.Request request,
                         long frameNumber, long timestamp) {
-                    if (!mCaptureStarted) {
+                    if (!mCaptureStarted || !mProcessCapture) {
                         mCaptureStarted = true;
                         captureCallback.onCaptureStarted(seqId, timestamp);
                     }
@@ -156,9 +160,14 @@
                     RequestBuilder.RequestProcessorRequest requestProcessorRequest =
                             (RequestBuilder.RequestProcessorRequest) request;
 
-                    mImageCaptureCaptureResultImageMatcher.setCameraCaptureCallback(
-                            totalCaptureResult,
-                            requestProcessorRequest.getCaptureStageId());
+                    if (!mProcessCapture) {
+                        captureCallback.onCaptureProcessStarted(seqId);
+                        addCaptureResultKeys(seqId, totalCaptureResult, captureCallback);
+                    } else {
+                        mImageCaptureCaptureResultImageMatcher.setCameraCaptureCallback(
+                                totalCaptureResult,
+                                requestProcessorRequest.getCaptureStageId());
+                    }
                 }
 
                 @Override
@@ -189,7 +198,7 @@
 
             mRequestProcessor.submit(requestList, callback);
 
-            if (mCaptureOutputSurfaceConfig.getSurface() != null) {
+            if (mCaptureOutputSurfaceConfig.getSurface() != null && mProcessCapture) {
                 mRequestProcessor.setImageProcessor(mCaptureOutputConfig.getId(),
                         new ImageProcessorImpl() {
                             boolean mCaptureStarted = false;
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
index ca4dcaf..8ce2733 100644
--- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
@@ -38,4 +38,9 @@
      * Gets the capacity for TYPE_IMAGEREADER.
      */
     int getMaxImages();
+
+    /**
+     * Get the surface usage bits.
+     */
+    long getUsage();
 }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
index 8294063..ba4ea4c 100644
--- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
@@ -105,7 +105,8 @@
                         Camera2OutputConfigImplBuilder.newImageReaderConfig(
                                 mPreviewOutputSurfaceConfig.getSize(),
                                 ImageFormat.YUV_420_888,
-                                BASIC_CAPTURE_PROCESS_MAX_IMAGES);
+                                BASIC_CAPTURE_PROCESS_MAX_IMAGES,
+                                mPreviewOutputSurfaceConfig.getUsage());
 
                 mPreviewOutputConfig = previewOutputConfigBuilder.build();
 
@@ -114,17 +115,33 @@
 
             // Image Capture
             if (mCaptureOutputSurfaceConfig.getSurface() != null) {
-                Camera2OutputConfigImplBuilder captureOutputConfigBuilder;
 
-                captureOutputConfigBuilder =
-                        Camera2OutputConfigImplBuilder.newImageReaderConfig(
-                                mCaptureOutputSurfaceConfig.getSize(),
-                                ImageFormat.YUV_420_888,
-                                BASIC_CAPTURE_PROCESS_MAX_IMAGES);
+                // For this sample, JPEG_R will not be processed
+                if (isJpegR(mCaptureOutputSurfaceConfig)) {
+                    Camera2OutputConfigImplBuilder captureOutputConfigBuilder;
 
-                mCaptureOutputConfig = captureOutputConfigBuilder.build();
+                    captureOutputConfigBuilder =
+                            Camera2OutputConfigImplBuilder.newSurfaceConfig(
+                                        mCaptureOutputSurfaceConfig.getSurface());
 
-                builder.addOutputConfig(mCaptureOutputConfig);
+                    mCaptureOutputConfig = captureOutputConfigBuilder.build();
+
+                    builder.addOutputConfig(mCaptureOutputConfig);
+                    mProcessCapture = false;
+                } else {
+                    Camera2OutputConfigImplBuilder captureOutputConfigBuilder;
+
+                    captureOutputConfigBuilder =
+                            Camera2OutputConfigImplBuilder.newImageReaderConfig(
+                                    mCaptureOutputSurfaceConfig.getSize(),
+                                    ImageFormat.YUV_420_888,
+                                    BASIC_CAPTURE_PROCESS_MAX_IMAGES,
+                                    mCaptureOutputSurfaceConfig.getUsage());
+
+                    mCaptureOutputConfig = captureOutputConfigBuilder.build();
+
+                    builder.addOutputConfig(mCaptureOutputConfig);
+                }
             }
 
             addSessionParameter(builder);
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
index f692029..f173c1b 100644
--- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
@@ -39,4 +39,14 @@
      * Gets the image format.
      */
     int getImageFormat();
+
+    /**
+     * Gets the dataspace.
+     */
+    int getDataspace();
+
+    /**
+     * Get the surface usage bits.
+     */
+    long getUsage();
 }
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
index d18aa92..c9eca43 100644
--- a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
@@ -19,6 +19,7 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.util.Pair;
@@ -390,5 +391,20 @@
          * @since 1.4
          */
         void onCaptureProcessProgressed(int progress);
+
+        /**
+         * This method is called instead of
+         * {@link #onCaptureProcessStarted} when the camera device failed
+         * to produce the required input for the device-specific extension. The
+         * cause could be a failed camera capture request, a failed
+         * capture result or dropped camera frame.
+         * The callback allows clients to be notified
+         * about failure reason.
+         *
+         * @param captureSequenceId id of the current capture sequence
+         * @param reason            The capture failure reason @see CaptureFailure#FailureReason
+         * @since 1.5
+         */
+        void onCaptureFailed(int captureSequenceId, int reason);
     }
 }
diff --git a/camera2/extensions/eyesFreeVidSample/Android.bp b/camera2/extensions/eyesFreeVidSample/Android.bp
index 64709bd..3d9567e 100644
--- a/camera2/extensions/eyesFreeVidSample/Android.bp
+++ b/camera2/extensions/eyesFreeVidSample/Android.bp
@@ -22,5 +22,6 @@
     static_libs: [
         "androidx.annotation_annotation"
     ],
-    platform_apis: true
+    platform_apis: true,
+    system_ext_specific: true
 }
diff --git a/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidService.java b/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidService.java
index cf669c7..d175c1a 100644
--- a/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidService.java
+++ b/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidService.java
@@ -16,6 +16,7 @@
 
 package android.camera.extensions.impl.service;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -26,15 +27,23 @@
 import android.annotation.FlaggedApi;
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
 import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.ExtensionCaptureRequest;
+import android.hardware.camera2.ExtensionCaptureResult;
 import android.hardware.camera2.extension.AdvancedExtender;
 import android.hardware.camera2.extension.CameraExtensionService;
 import android.hardware.camera2.extension.CharacteristicsMap;
 import android.hardware.camera2.extension.SessionProcessor;
+import android.hardware.camera2.params.StreamConfiguration;
+import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.os.IBinder;
+import android.util.Pair;
+import android.util.Range;
 import android.util.Size;
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
@@ -75,7 +84,13 @@
     @Override
     public AdvancedExtender onInitializeAdvancedExtension(int extensionType) {
         mCameraManager = getSystemService(CameraManager.class);
-        return new AdvancedExtenderEyesFreeImpl(mCameraManager);
+
+        switch (extensionType) {
+            case CameraExtensionCharacteristics.EXTENSION_EYES_FREE_VIDEOGRAPHY:
+                return new AdvancedExtenderEyesFreeImpl(mCameraManager);
+            default:
+                return new AdvancedExtenderImpl(mCameraManager);
+        }
     }
 
     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@@ -96,7 +111,7 @@
 
         @FlaggedApi(Flags.FLAG_CONCERT_MODE)
         @Override
-        public void init(String cameraId, CharacteristicsMap map) {
+        public void initialize(String cameraId, CharacteristicsMap map) {
             mCameraCharacteristics = map.get(cameraId);
         }
 
@@ -125,6 +140,10 @@
             return formatResolutions;
         }
 
+        protected CameraCharacteristics getCameraCharacteristics() {
+            return mCameraCharacteristics;
+        }
+
         @FlaggedApi(Flags.FLAG_CONCERT_MODE)
         @Override
         public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
@@ -146,7 +165,12 @@
             final CaptureRequest.Key [] CAPTURE_REQUEST_SET = {CaptureRequest.CONTROL_ZOOM_RATIO,
                 CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_REGIONS,
                 CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.JPEG_QUALITY,
-                CaptureRequest.JPEG_ORIENTATION};
+                CaptureRequest.JPEG_ORIENTATION, ExtensionCaptureRequest.EFV_PADDING_ZOOM_FACTOR,
+                ExtensionCaptureRequest.EFV_AUTO_ZOOM,
+                ExtensionCaptureRequest.EFV_MAX_PADDING_ZOOM_FACTOR,
+                ExtensionCaptureRequest.EFV_STABILIZATION_MODE,
+                ExtensionCaptureRequest.EFV_TRANSLATE_VIEWPORT,
+                ExtensionCaptureRequest.EFV_ROTATE_VIEWPORT};
             return Arrays.asList(CAPTURE_REQUEST_SET);
         }
 
@@ -157,8 +181,192 @@
             final CaptureResult.Key [] CAPTURE_RESULT_SET = {CaptureResult.CONTROL_ZOOM_RATIO,
                 CaptureResult.CONTROL_AF_MODE, CaptureResult.CONTROL_AF_REGIONS,
                 CaptureResult.CONTROL_AF_TRIGGER, CaptureResult.CONTROL_AF_STATE,
-                CaptureResult.JPEG_QUALITY, CaptureResult.JPEG_ORIENTATION};
+                CaptureResult.JPEG_QUALITY, CaptureResult.JPEG_ORIENTATION,
+                ExtensionCaptureResult.EFV_PADDING_REGION,
+                ExtensionCaptureResult.EFV_AUTO_ZOOM,
+                ExtensionCaptureResult.EFV_MAX_PADDING_ZOOM_FACTOR,
+                ExtensionCaptureResult.EFV_AUTO_ZOOM_PADDING_REGION,
+                ExtensionCaptureResult.EFV_STABILIZATION_MODE,
+                ExtensionCaptureResult.EFV_TARGET_COORDINATES,
+                ExtensionCaptureResult.EFV_PADDING_ZOOM_FACTOR,
+                ExtensionCaptureResult.EFV_TRANSLATE_VIEWPORT,
+                ExtensionCaptureResult.EFV_ROTATE_VIEWPORT
+            };
             return Arrays.asList(CAPTURE_RESULT_SET);
         }
+
+        @FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
+        @Override
+        public List<Pair<CameraCharacteristics.Key, Object>>
+                getAvailableCharacteristicsKeyValues() {
+            Range<Float> zoomRange = mCameraCharacteristics
+                    .get(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE);
+            int[] caps = mCameraCharacteristics
+                    .get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+
+            Set<Integer> unsupportedCapabilities = new HashSet<>(Arrays.asList(
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
+                    CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR
+            ));
+
+            List<Integer> filtered = new ArrayList<>();
+            for (int c : caps) {
+                if (unsupportedCapabilities.contains(c)) {
+                    continue;
+                }
+                filtered.add(c);
+            }
+            int[] extensionsCaps = new int[filtered.size()];
+            for (int i = 0; i < filtered.size(); i++) {
+                 extensionsCaps[i] = filtered.get(i);
+            }
+
+            Set<Integer> supportedFormats = new HashSet<>( Arrays.asList(
+                    ImageFormat.YUV_420_888,
+                    ImageFormat.JPEG,
+                    ImageFormat.JPEG_R,
+                    ImageFormat.PRIVATE));
+
+            StreamConfiguration[] configurations = mCameraCharacteristics
+                    .get(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+            List<StreamConfiguration> tmpConfigs = new ArrayList<>();
+            for (StreamConfiguration sc : configurations) {
+                if (supportedFormats.contains(sc.getFormat())) {
+                    tmpConfigs.add(sc);
+                }
+            }
+            StreamConfiguration[] filteredConfigurations =
+                    new StreamConfiguration[tmpConfigs.size()];
+            filteredConfigurations = tmpConfigs.toArray(filteredConfigurations);
+
+            StreamConfigurationDuration[] minFrameDurations = mCameraCharacteristics
+                    .get(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+            List<StreamConfigurationDuration> tmpMinFrameDurations = new ArrayList<>();
+            for (StreamConfigurationDuration scd : minFrameDurations) {
+                if (supportedFormats.contains(scd.getFormat())) {
+                    tmpMinFrameDurations.add(scd);
+                }
+            }
+            StreamConfigurationDuration[] filteredMinFrameDurations =
+                    new StreamConfigurationDuration[tmpMinFrameDurations.size()];
+            filteredMinFrameDurations = tmpMinFrameDurations.toArray(filteredMinFrameDurations);
+
+            StreamConfigurationDuration[] stallDurations = mCameraCharacteristics
+                    .get(CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
+            List<StreamConfigurationDuration> tmpStallDurations = new ArrayList<>();
+            for (StreamConfigurationDuration scd : stallDurations) {
+                if (supportedFormats.contains(scd.getFormat())) {
+                    tmpStallDurations.add(scd);
+                }
+            }
+            StreamConfigurationDuration[] filteredStallDurations =
+                    new StreamConfigurationDuration[tmpStallDurations.size()];
+            filteredStallDurations = tmpStallDurations.toArray(filteredStallDurations);
+
+            return Arrays.asList(
+                    Pair.create(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                            filteredConfigurations),
+                    Pair.create(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+                            filteredMinFrameDurations),
+                    Pair.create(CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS,
+                            filteredStallDurations),
+                    Pair.create(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES,
+                            extensionsCaps),
+                    Pair.create(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE, zoomRange),
+                    Pair.create(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES,
+                            new int[]{
+                                    CameraMetadata.CONTROL_AF_MODE_OFF,
+                                    CameraMetadata.CONTROL_AF_MODE_AUTO
+                            }),
+                    Pair.create(
+                            CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+                            new int[]{ CameraCharacteristics
+                                    .CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION
+                            }),
+                    Pair.create(CameraExtensionCharacteristics.EFV_PADDING_ZOOM_FACTOR_RANGE,
+                            new Range<Float>(1.0f, 2.0f))
+            );
+        }
+    }
+
+    @FlaggedApi(Flags.FLAG_CONCERT_MODE)
+    public static class AdvancedExtenderImpl extends AdvancedExtender {
+
+        @FlaggedApi(Flags.FLAG_CONCERT_MODE)
+        public AdvancedExtenderImpl(@NonNull CameraManager cameraManager) {
+            super(cameraManager);
+        }
+
+        @FlaggedApi(Flags.FLAG_CONCERT_MODE)
+        @Override
+        public boolean isExtensionAvailable(String cameraId,
+                CharacteristicsMap charsMap) {
+            return false;
+        }
+
+        @FlaggedApi(Flags.FLAG_CONCERT_MODE)
+        @Override
+        public void initialize(String cameraId, CharacteristicsMap map) {
+            throw new RuntimeException("Extension not supported");
+        }
+
+        @FlaggedApi(Flags.FLAG_CONCERT_MODE)
+        @Override
+        public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+                String cameraId) {
+            throw new RuntimeException("Extension not supported");
+        }
+
+        protected Map<Integer, List<Size>> filterOutputResolutions(List<Integer> formats) {
+            throw new RuntimeException("Extension not supported");
+        }
+
+        protected CameraCharacteristics getCameraCharacteristics() {
+            throw new RuntimeException("Extension not supported");
+        }
+
+        @FlaggedApi(Flags.FLAG_CONCERT_MODE)
+        @Override
+        public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+                String cameraId) {
+            throw new RuntimeException("Extension not supported");
+        }
+
+        @FlaggedApi(Flags.FLAG_CONCERT_MODE)
+        @Override
+        public SessionProcessor getSessionProcessor() {
+            throw new RuntimeException("Extension not supported");
+        }
+
+        @FlaggedApi(Flags.FLAG_CONCERT_MODE)
+        @Override
+        public List<CaptureRequest.Key> getAvailableCaptureRequestKeys(
+                String cameraId) {
+            throw new RuntimeException("Extension not supported");
+
+        }
+
+        @FlaggedApi(Flags.FLAG_CONCERT_MODE)
+        @Override
+        public List<CaptureResult.Key> getAvailableCaptureResultKeys(
+                String cameraId) {
+            throw new RuntimeException("Extension not supported");
+        }
+
+        @FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
+        @Override
+        public List<Pair<CameraCharacteristics.Key, Object>>
+                getAvailableCharacteristicsKeyValues() {
+            throw new RuntimeException("Extension not supported");
+        }
     }
 }
diff --git a/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidSessionProcessor.java b/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidSessionProcessor.java
index f23f3a6..92f371f 100644
--- a/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidSessionProcessor.java
+++ b/camera2/extensions/eyesFreeVidSample/src/android/camera/extensions/impl/service/EyesFreeVidSessionProcessor.java
@@ -16,21 +16,28 @@
 
 package android.camera.extensions.impl.service;
 
-import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Queue;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.camera.extensions.impl.service.EyesFreeVidService.AdvancedExtenderEyesFreeImpl;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.ExtensionCaptureRequest;
+import android.hardware.camera2.ExtensionCaptureResult;
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.extension.CameraOutputSurface;
 import android.hardware.camera2.extension.CharacteristicsMap;
@@ -39,6 +46,7 @@
 import android.hardware.camera2.extension.RequestProcessor;
 import android.hardware.camera2.extension.SessionProcessor;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.SurfaceUtils;
 import android.media.Image;
 import android.media.ImageReader;
 import android.media.ImageWriter;
@@ -70,7 +78,7 @@
 
     protected final Object mParametersLock = new Object();
     @GuardedBy("mParametersLock")
-    protected List<Pair<CaptureRequest.Key, Object>> mParameters = new ArrayList<>();
+    protected HashMap<CaptureRequest.Key, Object> mParametersMap = new HashMap<>();
 
     protected AtomicInteger mNextCaptureSequenceId = new AtomicInteger(1);
 
@@ -83,6 +91,8 @@
     protected ImageReader mPreviewImageReader;
     protected String mCameraId;
 
+    protected AtomicBoolean mOnCaptureSessionEndStarted = new AtomicBoolean(false);
+
     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
     protected EyesFreeVidSessionProcessor(AdvancedExtenderEyesFreeImpl advancedExtender) {
         mAdvancedExtender = advancedExtender;
@@ -105,7 +115,7 @@
             List<CameraOutputSurface> captureList = new ArrayList<>(List.of(imageCaptureSurface));
 
             ExtensionOutputConfiguration captureConfig = new ExtensionOutputConfiguration(
-                    captureList, CAPTURE_OUTPUT_ID, null, 0);
+                    captureList, CAPTURE_OUTPUT_ID, null, -1);
             outputs.add(captureConfig);
         }
 
@@ -114,14 +124,14 @@
         if (previewSurface.getSurface() != null) {
             mPreviewImageReader = ImageReader.newInstance(previewSurface.getSize().getWidth(),
                     previewSurface.getSize().getHeight(), previewSurface.getImageFormat(),
-                    MAX_NUM_IMAGES);
+                    MAX_NUM_IMAGES, SurfaceUtils.getSurfaceUsage(previewSurface.getSurface()));
 
             List<CameraOutputSurface> previewList = new ArrayList<>(List.of(
                     new CameraOutputSurface(mPreviewImageReader.getSurface(),
                     previewSurface.getSize())));
 
             ExtensionOutputConfiguration previewConfig = new ExtensionOutputConfiguration(
-                    previewList, PREVIEW_OUTPUT_ID, null, 0);
+                    previewList, PREVIEW_OUTPUT_ID, null, -1);
             outputs.add(previewConfig);
         }
 
@@ -181,20 +191,25 @@
     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
     @Override
     public void onCaptureSessionEnd() {
+        mOnCaptureSessionEndStarted.set(true);
+
+        if (mRequestProcessor != null) {
+            mRequestProcessor.abortCaptures();
+        }
+
         mRequestProcessor = null;
     }
 
     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
     @Override
-    public int startRepeating(@Nullable Executor executor,
+    public int startRepeating(@NonNull Executor executor,
             @NonNull CaptureCallback captureCallback) {
         List<Integer> outputConfigIds = new ArrayList<>(List.of(PREVIEW_OUTPUT_ID));
 
         RequestProcessor.Request requestRes;
-        synchronized (mParametersLock) {
-            requestRes = new RequestProcessor.Request(outputConfigIds, mParameters,
-                    CameraDevice.TEMPLATE_PREVIEW);
-        }
+
+        requestRes = new RequestProcessor.Request(outputConfigIds, convertParameterMapToList(),
+                CameraDevice.TEMPLATE_PREVIEW);
 
         final int seqId = mNextCaptureSequenceId.getAndIncrement();
 
@@ -202,7 +217,9 @@
             @Override
             public void onCaptureStarted(RequestProcessor.Request request, long frameNumber,
                     long timestamp) {
-                captureCallback.onCaptureStarted(seqId, timestamp);
+                if (!mOnCaptureSessionEndStarted.get()) {
+                    captureCallback.onCaptureStarted(seqId, timestamp);
+                }
             }
 
             @Override
@@ -213,34 +230,48 @@
             @Override
             public void onCaptureCompleted(RequestProcessor.Request request,
                     TotalCaptureResult totalCaptureResult) {
-                addCaptureResultKeys(seqId, totalCaptureResult, captureCallback);
-                captureCallback.onCaptureProcessStarted(seqId);
+                if (!mOnCaptureSessionEndStarted.get()) {
+                    addCaptureResultKeys(seqId, totalCaptureResult, captureCallback, request);
+                    captureCallback.onCaptureProcessStarted(seqId);
+                }
             }
 
             @Override
             public void onCaptureFailed(RequestProcessor.Request request,
                     CaptureFailure captureFailure) {
-                captureCallback.onCaptureFailed(seqId);
+                if (!mOnCaptureSessionEndStarted.get()) {
+                    captureCallback.onCaptureFailed(seqId, captureFailure.getReason());
+                }
             }
 
             @Override
             public void onCaptureBufferLost(RequestProcessor.Request request,
                     long frameNumber, int outputStreamId) {
-                captureCallback.onCaptureFailed(seqId);
+                if (!mOnCaptureSessionEndStarted.get()) {
+                    captureCallback.onCaptureFailed(seqId, CaptureFailure.REASON_ERROR);
+                }
             }
 
             @Override
             public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
-                captureCallback.onCaptureSequenceCompleted(seqId);
+                if (!mOnCaptureSessionEndStarted.get()) {
+                    captureCallback.onCaptureSequenceCompleted(seqId);
+                }
             }
 
             @Override
             public void onCaptureSequenceAborted(int sequenceId) {
-                captureCallback.onCaptureSequenceAborted(seqId);
+                if (!mOnCaptureSessionEndStarted.get()) {
+                    captureCallback.onCaptureSequenceAborted(seqId);
+                }
             }
         };
 
-        mRequestProcessor.setRepeating(requestRes, executor, resCallback);
+        try {
+            mRequestProcessor.setRepeating(requestRes, executor, resCallback);
+        } catch(CameraAccessException e) {
+            return -1;
+        }
 
         return seqId;
     }
@@ -248,28 +279,102 @@
     protected void addCaptureResultKeys(
         @NonNull int seqId,
         @NonNull TotalCaptureResult result,
-        @NonNull CaptureCallback captureCallback) {
-
-        CameraMetadataNative cameraMetadataNative = new CameraMetadataNative();
-        long vendorId = mAdvancedExtender.getMetadataVendorId(mCameraId);
-        cameraMetadataNative.setVendorId(vendorId);
+        @NonNull CaptureCallback captureCallback,
+        @NonNull RequestProcessor.Request request) {
 
         Long shutterTimestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
         if (shutterTimestamp != null) {
 
             List<CaptureResult.Key> captureResultKeys =
                     mAdvancedExtender.getAvailableCaptureResultKeys(mCameraId);
+            HashMap<CaptureResult.Key, Object> captureResults = new HashMap<>();
             for (CaptureResult.Key key : captureResultKeys) {
                 if (result.get(key) != null) {
-                    cameraMetadataNative.set(key, result.get(key));
+                    captureResults.put(key, result.get(key));
                 }
             }
-            CaptureResult captureResult = new CaptureResult(cameraMetadataNative, seqId);
-            captureCallback.onCaptureCompleted(shutterTimestamp, seqId,
-                    captureResult);
+
+            synchronized (mParametersLock) {
+                List<Pair<CaptureRequest.Key, Object>> requestParameters = request.getParameters();
+                boolean autoZoomEnabled = false;
+                boolean stabilizationModeLocked = false;
+                for (Pair<CaptureRequest.Key, Object> parameter : requestParameters) {
+                    if (ExtensionCaptureRequest.EFV_AUTO_ZOOM.equals(parameter.first)) {
+                        captureResults.put(ExtensionCaptureResult.EFV_AUTO_ZOOM,
+                                (boolean) parameter.second);
+                        autoZoomEnabled = (boolean) parameter.second;
+                        if (autoZoomEnabled &&
+                                ExtensionCaptureRequest.EFV_MAX_PADDING_ZOOM_FACTOR.equals(
+                                parameter.first)) {
+                            captureResults.put(
+                                    ExtensionCaptureResult.EFV_MAX_PADDING_ZOOM_FACTOR,
+                                    (Float) parameter.second);
+                        }
+                    }
+                    if (ExtensionCaptureRequest.EFV_PADDING_ZOOM_FACTOR.equals(parameter.first)) {
+                        captureResults.put(ExtensionCaptureResult.EFV_PADDING_ZOOM_FACTOR,
+                                (Float) parameter.second);
+                    }
+                    if (ExtensionCaptureRequest.EFV_TRANSLATE_VIEWPORT.equals(parameter.first)) {
+                        captureResults.put(ExtensionCaptureResult.EFV_TRANSLATE_VIEWPORT,
+                                (Pair<Integer, Integer>) parameter.second);
+                    }
+                    if (ExtensionCaptureRequest.EFV_ROTATE_VIEWPORT.equals(parameter.first)) {
+                        captureResults.put(ExtensionCaptureResult.EFV_ROTATE_VIEWPORT,
+                                (Float) parameter.second);
+                    }
+                    if (ExtensionCaptureRequest.EFV_STABILIZATION_MODE.equals(parameter.first)) {
+                        if (ExtensionCaptureRequest.EFV_STABILIZATION_MODE_LOCKED ==
+                                (int) parameter.second) {
+                            stabilizationModeLocked = true;
+                            int[] samplePaddingRegion = {5, 5, 5, 5};
+                            captureResults.put(ExtensionCaptureResult.EFV_PADDING_REGION,
+                                    samplePaddingRegion);
+                            CameraCharacteristics cameraCharacteristics =
+                                    mAdvancedExtender.getCameraCharacteristics();
+                            Rect arraySize = cameraCharacteristics.get(
+                                    CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+                            int centerX = arraySize.width() / 2;
+                            int centerY = arraySize.height() / 2;
+                            int squareSize = 5;
+                            PointF[] sampleTargetCoordinates = new PointF[]{
+                                    new PointF(centerX - squareSize, centerY - squareSize),
+                                    new PointF(centerX + squareSize, centerY - squareSize),
+                                    new PointF(centerX + squareSize, centerY + squareSize),
+                                    new PointF(centerX - squareSize, centerY + squareSize)
+                            };
+                            captureResults.put(ExtensionCaptureResult.EFV_TARGET_COORDINATES,
+                                    sampleTargetCoordinates);
+                        }
+                    }
+                }
+
+                if (autoZoomEnabled && stabilizationModeLocked) {
+                    int[] sampleAutoZoomPaddingRegion = {3, 3, 3, 3};
+                    captureResults.put(ExtensionCaptureResult.EFV_AUTO_ZOOM_PADDING_REGION,
+                            sampleAutoZoomPaddingRegion);
+                }
+            }
+
+            captureCallback.onCaptureCompleted(shutterTimestamp, seqId, captureResults);
         }
     }
 
+    protected List<Pair<CaptureRequest.Key, Object>> convertParameterMapToList() {
+        List<Pair<CaptureRequest.Key, Object>> mParametersList = new ArrayList<>();
+
+        synchronized(mParametersLock) {
+            for (Map.Entry<CaptureRequest.Key, Object> entry : mParametersMap.entrySet()) {
+                CaptureRequest.Key key = entry.getKey();
+                Object value = entry.getValue();
+                Pair<CaptureRequest.Key, Object> pair = new Pair<>(key, value);
+                mParametersList.add(pair);
+            }
+        }
+
+        return mParametersList;
+    }
+
     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
     @Override
     public void stopRepeating() {
@@ -278,15 +383,13 @@
 
     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
     @Override
-    public int startCapture(@Nullable Executor executor,
+    public int startMultiFrameCapture(@NonNull Executor executor,
             @NonNull CaptureCallback captureCallback) {
         List<Integer> outputConfigIds = new ArrayList<>(List.of(CAPTURE_OUTPUT_ID));
 
         RequestProcessor.Request requestRes;
-        synchronized (mParametersLock) {
-            requestRes = new RequestProcessor.Request(outputConfigIds, mParameters,
+        requestRes = new RequestProcessor.Request(outputConfigIds, convertParameterMapToList(),
                     CameraDevice.TEMPLATE_PREVIEW);
-        }
 
         final int seqId = mNextCaptureSequenceId.getAndIncrement();
 
@@ -307,19 +410,19 @@
             @Override
             public void onCaptureCompleted(RequestProcessor.Request request,
                     TotalCaptureResult totalCaptureResult) {
-                addCaptureResultKeys(seqId, totalCaptureResult, captureCallback);
+                addCaptureResultKeys(seqId, totalCaptureResult, captureCallback, request);
             }
 
             @Override
             public void onCaptureFailed(RequestProcessor.Request request,
                     CaptureFailure captureFailure) {
-                captureCallback.onCaptureFailed(seqId);
+                captureCallback.onCaptureFailed(seqId, captureFailure.getReason());
             }
 
             @Override
             public void onCaptureBufferLost(RequestProcessor.Request request,
                     long frameNumber, int outputStreamId) {
-                captureCallback.onCaptureFailed(seqId);
+                captureCallback.onCaptureFailed(seqId, CaptureFailure.REASON_ERROR);
             }
 
             @Override
@@ -333,7 +436,11 @@
             }
         };
 
-        mRequestProcessor.submit(requestRes, executor, resCallback);
+        try {
+            mRequestProcessor.submit(requestRes, executor, resCallback);
+        } catch(CameraAccessException e) {
+            return -1;
+        }
 
         captureCallback.onCaptureProcessStarted(seqId);
         return seqId;
@@ -342,7 +449,7 @@
     @FlaggedApi(Flags.FLAG_CONCERT_MODE)
     @Override
     public int startTrigger(@NonNull CaptureRequest captureRequest,
-            @Nullable Executor executor, @NonNull CaptureCallback captureCallback) {
+            @NonNull Executor executor, @NonNull CaptureCallback captureCallback) {
         List<Integer> outputConfigIds = new ArrayList<>(List.of(PREVIEW_OUTPUT_ID));
 
         RequestProcessor.Request requestRes = new RequestProcessor.Request(outputConfigIds,
@@ -367,19 +474,19 @@
             @Override
             public void onCaptureCompleted(RequestProcessor.Request request,
                     TotalCaptureResult totalCaptureResult) {
-                addCaptureResultKeys(seqId, totalCaptureResult, captureCallback);
+                addCaptureResultKeys(seqId, totalCaptureResult, captureCallback, request);
             }
 
             @Override
             public void onCaptureFailed(RequestProcessor.Request request,
                     CaptureFailure captureFailure) {
-                captureCallback.onCaptureFailed(seqId);
+                captureCallback.onCaptureFailed(seqId, captureFailure.getReason());
             }
 
             @Override
             public void onCaptureBufferLost(RequestProcessor.Request request,
                     long frameNumber, int outputStreamId) {
-                captureCallback.onCaptureFailed(seqId);
+                captureCallback.onCaptureFailed(seqId, CaptureFailure.REASON_ERROR);
             }
 
             @Override
@@ -393,7 +500,11 @@
             }
         };
 
-        mRequestProcessor.submit(requestRes, executor, resCallback);
+        try {
+            mRequestProcessor.submit(requestRes, executor, resCallback);
+        } catch(CameraAccessException e) {
+            return -1;
+        }
 
         captureCallback.onCaptureProcessStarted(seqId);
         return seqId;
@@ -419,9 +530,16 @@
     @Override
     public void setParameters(@NonNull CaptureRequest captureRequest) {
         synchronized (mParametersLock) {
-            for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
-                Object value = captureRequest.get(key);
-                mParameters.add(new Pair<>(key, value));
+
+            List<CaptureRequest.Key> supportedCaptureRequestKeys =
+                    mAdvancedExtender.getAvailableCaptureRequestKeys(mCameraId);
+            List<CaptureRequest.Key<?>> requestedCaptureRequestKeys =
+                    captureRequest.getKeys();
+            for (CaptureRequest.Key<?> key : requestedCaptureRequestKeys) {
+                if (supportedCaptureRequestKeys.contains(key)) {
+                    Object value = captureRequest.get(key);
+                    mParametersMap.put(key, value);
+                }
             }
         }
     }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
index d13efc8..abf8d45 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
@@ -216,4 +217,23 @@
      * @since 1.4
      */
     boolean isPostviewAvailable();
+
+    /**
+     * Returns a list of {@link CameraCharacteristics} key/value pairs for apps to use when
+     * querying {@link CameraExtensionCharacteristics#get} and
+     * {@link CameraExtensionCharacteristics#getKeys}. The key/value pairs define the limitations
+     * on the controls returned from {@link #getAvailableCaptureRequestKeys}. If a key is not
+     * present in the returned list, then the capability is either undefined or unsupported.
+     *
+     * <p>For example, an extension may limit the zoom ratio range. In this case, an OEM returns
+     * a new zoom ratio range for the key {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE}.
+     *
+     * <p>Similarly, an extension may support preview stabilization. In this case, the OEM returns
+     * the array containing the elements
+     * {@link CameraCharacteristics#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION} and
+     * {@link CameraCharacteristics#CONTROL_VIDEO_STABILIZATION_MODE_OFF} for the key
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES}.
+     * @since 1.5
+     */
+    List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues();
 }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
index 8c3ac11..45e4fcc 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
@@ -104,4 +105,9 @@
     public boolean isPostviewAvailable() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
+
+    @Override
+    public List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
 }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
index 135306c..8bb17f7 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
@@ -104,4 +105,9 @@
     public boolean isPostviewAvailable() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
+
+    @Override
+    public List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
 }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
index fa4ad0d..71b38d6 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
@@ -104,4 +105,9 @@
     public boolean isPostviewAvailable() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
+
+    @Override
+    public List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
 }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
index a66d3ce..365abc3 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
@@ -49,9 +49,9 @@
      * with the given parameters.
      */
     public static Camera2OutputConfigImplBuilder newImageReaderConfig(
-            Size size, int imageFormat, int maxImages) {
+            Size size, int imageFormat, int maxImages, long usage) {
         return new Camera2OutputConfigImplBuilder(
-                new ImageReaderOutputConfigImplImpl(size, imageFormat, maxImages));
+                new ImageReaderOutputConfigImplImpl(size, imageFormat, maxImages, usage));
     }
 
     /**
@@ -181,11 +181,14 @@
         private Size mSize;
         private int mImageFormat;
         private int mMaxImages;
+        private long mUsage;
 
-        ImageReaderOutputConfigImplImpl(Size size, int imageFormat, int maxImages) {
+        ImageReaderOutputConfigImplImpl(Size size, int imageFormat, int maxImages,
+                long usage) {
             mSize = size;
             mImageFormat = imageFormat;
             mMaxImages = maxImages;
+            mUsage = usage;
         }
 
         @Override
@@ -202,6 +205,11 @@
         public int getMaxImages() {
             return mMaxImages;
         }
+
+        @Override
+        public long getUsage() {
+            return mUsage;
+        }
     }
 
     private static class MultiResolutionImageReaderOutputConfigImplImpl extends OutputConfigImplImpl
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/EyesFreeVideographyAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/EyesFreeVideographyAdvancedExtenderImpl.java
index 01b65be..f2eb399 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/EyesFreeVideographyAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/EyesFreeVideographyAdvancedExtenderImpl.java
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
@@ -105,4 +106,10 @@
     public boolean isPostviewAvailable() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
+
+    @Override
+    public List<Pair<CameraCharacteristics.Key, Object>>
+            getAvailableCharacteristicsKeyValues() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
 }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
index dc5b2b6..7d87cc6 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
@@ -105,4 +106,9 @@
     public boolean isPostviewAvailable() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
+
+    @Override
+    public List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
 }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
index ca4dcaf..7c3b48e 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
@@ -38,4 +38,9 @@
      * Gets the capacity for TYPE_IMAGEREADER.
      */
     int getMaxImages();
+
+    /**
+     * Gets the surface usage bits.
+     */
+    long getUsage();
 }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
index 5b0ed8e..961d669 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
@@ -104,4 +105,9 @@
     public boolean isPostviewAvailable() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
+
+    @Override
+    public List<Pair<CameraCharacteristics.Key, Object>> getAvailableCharacteristicsKeyValues() {
+        throw new RuntimeException("Stub, replace with implementation.");
+    }
 }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
index f692029..7bf8df2 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
@@ -39,4 +39,14 @@
      * Gets the image format.
      */
     int getImageFormat();
+
+    /**
+     * Gets the dataspace.
+     */
+    int getDataspace();
+
+    /**
+    * Gets the surface usage bits.
+    */
+    long getUsage();
 }
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
index 2e5603b..57fffd0 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
@@ -19,6 +19,7 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.util.Pair;
@@ -390,5 +391,20 @@
          * @since 1.4
          */
         void onCaptureProcessProgressed(int progress);
+
+        /**
+         * This method is called instead of
+         * {@link #onCaptureProcessStarted} when the camera device failed
+         * to produce the required input for the device-specific extension. The
+         * cause could be a failed camera capture request, a failed
+         * capture result or dropped camera frame.
+         * The callback allows clients to be notified
+         * about failure reason.
+         *
+         * @param captureSequenceId id of the current capture sequence
+         * @param reason            The capture failure reason @see CaptureFailure#FailureReason
+         * @since 1.5
+         */
+        void onCaptureFailed(int captureSequenceId, int reason);
     }
 }
diff --git a/common/tests/Android.bp b/common/tests/Android.bp
index 5b68d05..8738a5d 100644
--- a/common/tests/Android.bp
+++ b/common/tests/Android.bp
@@ -21,9 +21,12 @@
     name: "AndroidCommonTests",
     certificate: "platform",
     libs: ["android.test.runner.stubs"],
-    sdk_version: "8",
+    sdk_version: "19",
     srcs: ["src/**/*.java"],
-    static_libs: ["android-common"],
+    static_libs: [
+        "android-common",
+        "androidx.test.rules",
+    ],
     optimize: {
         enabled: false,
     },
diff --git a/common/tests/src/com/android/common/OperationSchedulerTest.java b/common/tests/src/com/android/common/OperationSchedulerTest.java
index a25544a..899da49 100644
--- a/common/tests/src/com/android/common/OperationSchedulerTest.java
+++ b/common/tests/src/com/android/common/OperationSchedulerTest.java
@@ -18,8 +18,9 @@
 
 import android.content.SharedPreferences;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
 
 public class OperationSchedulerTest extends AndroidTestCase {
     /**
diff --git a/common/tests/src/com/android/common/Rfc822ValidatorTest.java b/common/tests/src/com/android/common/Rfc822ValidatorTest.java
index 61b8f25..f9bc808 100644
--- a/common/tests/src/com/android/common/Rfc822ValidatorTest.java
+++ b/common/tests/src/com/android/common/Rfc822ValidatorTest.java
@@ -16,7 +16,7 @@
 
 package com.android.common;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/common/tests/src/com/android/common/widget/CompositeCursorAdapterTest.java b/common/tests/src/com/android/common/widget/CompositeCursorAdapterTest.java
index 53d5840..17ba182 100644
--- a/common/tests/src/com/android/common/widget/CompositeCursorAdapterTest.java
+++ b/common/tests/src/com/android/common/widget/CompositeCursorAdapterTest.java
@@ -19,10 +19,11 @@
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests for {@link CompositeCursorAdapter}.
  *
diff --git a/framesequence/jni/Android.bp b/framesequence/jni/Android.bp
index 13ae47a..db71b51 100644
--- a/framesequence/jni/Android.bp
+++ b/framesequence/jni/Android.bp
@@ -20,41 +20,10 @@
 
 cc_library_shared {
     name: "libframesequence",
-
-    // Main library
-    // NOTE: the following code when dropped during the Android.mk->Android.bp
-    // conversion because FRAMESEQUENCE_INCLUDE_WEBP is never set:
-    //  ifeq ($(FRAMESEQUENCE_INCLUDE_WEBP),true)
-    //    LOCAL_C_INCLUDES += external/webp/include
-    //    LOCAL_SRC_FILES += FrameSequence_webp.cpp
-    //    LOCAL_STATIC_LIBRARIES += libwebp-decode
-    //  endif
-
-    static_libs: ["libgif"],
     header_libs: ["jni_headers"],
-    include_dirs: ["external/giflib"],
     srcs: [
         "BitmapDecoderJNI.cpp",
-        "FrameSequence.cpp",
-        "FrameSequenceJNI.cpp",
-        "FrameSequence_gif.cpp",
-        "JNIHelpers.cpp",
-        "Registry.cpp",
-        "Stream.cpp",
-    ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-        "-Wno-unused-variable",
-        "-Wno-overloaded-virtual",
-        "-fvisibility=hidden",
     ],
     sdk_version: "8",
-    shared_libs: [
-        "libjnigraphics",
-        "liblog",
-    ],
-
     product_specific: true,
 }
diff --git a/framesequence/jni/BitmapDecoderJNI.cpp b/framesequence/jni/BitmapDecoderJNI.cpp
index 5fe04b4..6f7e246 100644
--- a/framesequence/jni/BitmapDecoderJNI.cpp
+++ b/framesequence/jni/BitmapDecoderJNI.cpp
@@ -14,34 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "FancyDecoding"
+#include <jni.h>
 
-#include <android/bitmap.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "FrameSequenceJNI.h"
-#include "JNIHelpers.h"
-#include "Stream.h"
-#include "utils/log.h"
-
-void throwException(JNIEnv* env, const char* error) {
-    jclass clazz = env->FindClass("java/lang/RuntimeException");
-    env->ThrowNew(clazz, error);
-}
-
-jint JNI_OnLoad(JavaVM* vm, void* reserved) {
-    JNIEnv* env;
-    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        return -1;
-    }
-    if (FrameSequence_OnLoad(env)) {
-        ALOGE("Failed to load FrameSequence");
-        return -1;
-    }
-    if (JavaStream_OnLoad(env)) {
-        ALOGE("Failed to load JavaStream");
-        return -1;
-    }
-
+jint JNI_OnLoad(JavaVM*, void*) {
     return JNI_VERSION_1_6;
 }
diff --git a/framesequence/jni/Color.h b/framesequence/jni/Color.h
deleted file mode 100644
index e49c64a..0000000
--- a/framesequence/jni/Color.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RASTERMILL_COLOR_H
-#define RASTERMILL_COLOR_H
-
-#include <sys/types.h>
-
-typedef uint32_t Color8888;
-
-static const Color8888 COLOR_8888_ALPHA_MASK = 0xff000000; // TODO: handle endianness
-static const Color8888 TRANSPARENT = 0x0;
-
-// TODO: handle endianness
-#define ARGB_TO_COLOR8888(a, r, g, b) \
-    ((a) << 24 | (b) << 16 | (g) << 8 | (r))
-
-#endif // RASTERMILL_COLOR_H
diff --git a/framesequence/jni/FrameSequence.cpp b/framesequence/jni/FrameSequence.cpp
deleted file mode 100644
index efcfefa..0000000
--- a/framesequence/jni/FrameSequence.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "FrameSequence.h"
-
-#include "Registry.h"
-
-FrameSequence* FrameSequence::create(Stream* stream) {
-    const RegistryEntry* entry = Registry::Find(stream);
-
-    if (!entry) return NULL;
-
-    FrameSequence* frameSequence = entry->createFrameSequence(stream);
-    if (!frameSequence->getFrameCount() ||
-            !frameSequence->getWidth() || !frameSequence->getHeight()) {
-        // invalid contents, abort
-        delete frameSequence;
-        return NULL;
-    }
-
-    return frameSequence;
-}
diff --git a/framesequence/jni/FrameSequence.h b/framesequence/jni/FrameSequence.h
deleted file mode 100644
index 134c81a..0000000
--- a/framesequence/jni/FrameSequence.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RASTERMILL_FRAME_SEQUENCE_H
-#define RASTERMILL_FRAME_SEQUENCE_H
-
-#include "Stream.h"
-#include "Color.h"
-
-class FrameSequenceState {
-public:
-    /**
-     * Produces a frame of animation in the output buffer, drawing (at minimum) the delta since
-     * previousFrameNr (the current contents of the buffer), or from scratch if previousFrameNr is
-     * negative
-     *
-     * Returns frame's delay time in milliseconds.
-     */
-    virtual long drawFrame(int frameNr,
-            Color8888* outputPtr, int outputPixelStride, int previousFrameNr) = 0;
-    virtual ~FrameSequenceState() {}
-};
-
-class FrameSequence {
-public:
-    /**
-     * Creates a FrameSequence using data from the data stream
-     *
-     * Type determined by header information in the stream
-     */
-    static FrameSequence* create(Stream* stream);
-
-    virtual ~FrameSequence() {}
-    virtual int getWidth() const = 0;
-    virtual int getHeight() const = 0;
-    virtual bool isOpaque() const = 0;
-    virtual int getFrameCount() const = 0;
-    virtual int getDefaultLoopCount() const = 0;
-    virtual jobject getRawByteBuffer() const = 0;
-
-    virtual FrameSequenceState* createState() const = 0;
-};
-
-#endif //RASTERMILL_FRAME_SEQUENCE_H
diff --git a/framesequence/jni/FrameSequenceJNI.cpp b/framesequence/jni/FrameSequenceJNI.cpp
deleted file mode 100644
index c701f03..0000000
--- a/framesequence/jni/FrameSequenceJNI.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/bitmap.h>
-#include "JNIHelpers.h"
-#include "utils/log.h"
-#include "FrameSequence.h"
-
-#include "FrameSequenceJNI.h"
-
-#define JNI_PACKAGE "android/support/rastermill"
-
-static struct {
-    jclass clazz;
-    jmethodID ctor;
-} gFrameSequenceClassInfo;
-
-////////////////////////////////////////////////////////////////////////////////
-// Frame sequence
-////////////////////////////////////////////////////////////////////////////////
-
-static jobject createJavaFrameSequence(JNIEnv* env, FrameSequence* frameSequence) {
-    if (!frameSequence) {
-        return NULL;
-    }
-    return env->NewObject(gFrameSequenceClassInfo.clazz, gFrameSequenceClassInfo.ctor,
-            reinterpret_cast<jlong>(frameSequence),
-            frameSequence->getWidth(),
-            frameSequence->getHeight(),
-            frameSequence->isOpaque(),
-            frameSequence->getFrameCount(),
-            frameSequence->getDefaultLoopCount());
-}
-
-static jobject nativeDecodeByteArray(JNIEnv* env, jobject clazz,
-        jbyteArray byteArray, jint offset, jint length) {
-    jbyte* bytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(byteArray, NULL));
-    if (bytes == NULL) {
-        jniThrowException(env, ILLEGAL_STATE_EXEPTION,
-                "couldn't read array bytes");
-        return NULL;
-    }
-    MemoryStream stream(bytes + offset, length, NULL);
-    FrameSequence* frameSequence = FrameSequence::create(&stream);
-    env->ReleasePrimitiveArrayCritical(byteArray, bytes, 0);
-    return createJavaFrameSequence(env, frameSequence);
-}
-
-static jobject nativeDecodeByteBuffer(JNIEnv* env, jobject clazz,
-        jobject buf, jint offset, jint limit) {
-    jobject globalBuf = env->NewGlobalRef(buf);
-    JavaVM* vm;
-    env->GetJavaVM(&vm);
-    MemoryStream stream(
-        (reinterpret_cast<uint8_t*>(
-            env->GetDirectBufferAddress(globalBuf))) + offset,
-        limit,
-        globalBuf);
-    FrameSequence* frameSequence = FrameSequence::create(&stream);
-    jobject finalSequence = createJavaFrameSequence(env, frameSequence);
-    return finalSequence;
-}
-
-static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
-        jobject istream, jbyteArray byteArray) {
-    JavaInputStream stream(env, istream, byteArray);
-    FrameSequence* frameSequence = FrameSequence::create(&stream);
-    return createJavaFrameSequence(env, frameSequence);
-}
-
-static void nativeDestroyFrameSequence(JNIEnv* env, jobject clazz,
-        jlong frameSequenceLong) {
-    FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceLong);
-    jobject buf = frameSequence->getRawByteBuffer();
-    if (buf != NULL) {
-        env->DeleteGlobalRef(buf);
-    }
-    delete frameSequence;
-}
-
-static jlong nativeCreateState(JNIEnv* env, jobject clazz, jlong frameSequenceLong) {
-    FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceLong);
-    FrameSequenceState* state = frameSequence->createState();
-    return reinterpret_cast<jlong>(state);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Frame sequence state
-////////////////////////////////////////////////////////////////////////////////
-
-static void nativeDestroyState(
-        JNIEnv* env, jobject clazz, jlong frameSequenceStateLong) {
-    FrameSequenceState* frameSequenceState =
-            reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
-    delete frameSequenceState;
-}
-
-void throwIae(JNIEnv* env, const char* message, int errorCode) {
-    char buf[256];
-    snprintf(buf, sizeof(buf), "%s, error %d", message, errorCode);
-    jniThrowException(env, ILLEGAL_STATE_EXEPTION, buf);
-}
-
-static jlong JNICALL nativeGetFrame(
-        JNIEnv* env, jobject clazz, jlong frameSequenceStateLong, jint frameNr,
-        jobject bitmap, jint previousFrameNr) {
-    FrameSequenceState* frameSequenceState =
-            reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
-    int ret;
-    AndroidBitmapInfo info;
-    void* pixels;
-
-    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
-        throwIae(env, "Couldn't get info from Bitmap", ret);
-        return 0;
-    }
-
-    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
-        throwIae(env, "Bitmap pixels couldn't be locked", ret);
-        return 0;
-    }
-
-    int pixelStride = info.stride >> 2;
-    jlong delayMs = frameSequenceState->drawFrame(frameNr,
-            (Color8888*) pixels, pixelStride, previousFrameNr);
-
-    AndroidBitmap_unlockPixels(env, bitmap);
-    return delayMs;
-}
-
-static JNINativeMethod gMethods[] = {
-    {   "nativeDecodeByteArray",
-        "([BII)L" JNI_PACKAGE "/FrameSequence;",
-        (void*) nativeDecodeByteArray
-    },
-    {   "nativeDecodeByteBuffer",
-        "(Ljava/nio/ByteBuffer;II)L" JNI_PACKAGE "/FrameSequence;",
-        (void*) nativeDecodeByteBuffer
-    },
-    {   "nativeDecodeStream",
-        "(Ljava/io/InputStream;[B)L" JNI_PACKAGE "/FrameSequence;",
-        (void*) nativeDecodeStream
-    },
-    {   "nativeDestroyFrameSequence",
-        "(J)V",
-        (void*) nativeDestroyFrameSequence
-    },
-    {   "nativeCreateState",
-        "(J)J",
-        (void*) nativeCreateState
-    },
-    {   "nativeGetFrame",
-        "(JILandroid/graphics/Bitmap;I)J",
-        (void*) nativeGetFrame
-    },
-    {   "nativeDestroyState",
-        "(J)V",
-        (void*) nativeDestroyState
-    },
-};
-
-jint FrameSequence_OnLoad(JNIEnv* env) {
-    // Get jclass with env->FindClass.
-    // Register methods with env->RegisterNatives.
-    gFrameSequenceClassInfo.clazz = env->FindClass(JNI_PACKAGE "/FrameSequence");
-    if (!gFrameSequenceClassInfo.clazz) {
-        ALOGW("Failed to find " JNI_PACKAGE "/FrameSequence");
-        return -1;
-    }
-    gFrameSequenceClassInfo.clazz = (jclass)env->NewGlobalRef(gFrameSequenceClassInfo.clazz);
-
-    gFrameSequenceClassInfo.ctor = env->GetMethodID(gFrameSequenceClassInfo.clazz, "<init>", "(JIIZII)V");
-    if (!gFrameSequenceClassInfo.ctor) {
-        ALOGW("Failed to find constructor for FrameSequence - was it stripped?");
-        return -1;
-    }
-
-    return env->RegisterNatives(gFrameSequenceClassInfo.clazz, gMethods, METHOD_COUNT(gMethods));
-}
diff --git a/framesequence/jni/FrameSequenceJNI.h b/framesequence/jni/FrameSequenceJNI.h
deleted file mode 100644
index a52df8a..0000000
--- a/framesequence/jni/FrameSequenceJNI.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RASTERMILL_FRAMESEQUENCE_JNI
-#define RASTERMILL_FRAMESEQUENCE_JNI
-
-#include <jni.h>
-
-jint FrameSequence_OnLoad(JNIEnv* env);
-
-#endif // RASTERMILL_FRAMESEQUENCE_JNI
diff --git a/framesequence/jni/FrameSequence_gif.cpp b/framesequence/jni/FrameSequence_gif.cpp
deleted file mode 100644
index ed47834..0000000
--- a/framesequence/jni/FrameSequence_gif.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string.h>
-#include "JNIHelpers.h"
-#include "utils/log.h"
-#include "utils/math.h"
-
-#include "FrameSequence_gif.h"
-
-#define GIF_DEBUG 0
-
-static int streamReader(GifFileType* fileType, GifByteType* out, int size) {
-    Stream* stream = (Stream*) fileType->UserData;
-    return (int) stream->read(out, size);
-}
-
-static Color8888 gifColorToColor8888(const GifColorType& color) {
-    return ARGB_TO_COLOR8888(0xff, color.Red, color.Green, color.Blue);
-}
-
-static long getDelayMs(GraphicsControlBlock& gcb) {
-    return gcb.DelayTime * 10;
-}
-
-static bool willBeCleared(const GraphicsControlBlock& gcb) {
-    return gcb.DisposalMode == DISPOSE_BACKGROUND || gcb.DisposalMode == DISPOSE_PREVIOUS;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Frame sequence
-////////////////////////////////////////////////////////////////////////////////
-
-FrameSequence_gif::FrameSequence_gif(Stream* stream) :
-        mLoopCount(1), mBgColor(TRANSPARENT), mPreservedFrames(NULL), mRestoringFrames(NULL) {
-    mGif = DGifOpen(stream, streamReader, NULL);
-    if (!mGif) {
-        ALOGW("Gif load failed");
-        return;
-    }
-
-    if (DGifSlurp(mGif) != GIF_OK) {
-        ALOGW("Gif slurp failed");
-        DGifCloseFile(mGif, NULL);
-        mGif = NULL;
-        return;
-    }
-
-    long durationMs = 0;
-    int lastUnclearedFrame = -1;
-    mPreservedFrames = new bool[mGif->ImageCount];
-    mRestoringFrames = new int[mGif->ImageCount];
-
-    GraphicsControlBlock gcb;
-    for (int i = 0; i < mGif->ImageCount; i++) {
-        const SavedImage& image = mGif->SavedImages[i];
-
-        // find the loop extension pair
-        for (int j = 0; (j + 1) < image.ExtensionBlockCount; j++) {
-            ExtensionBlock* eb1 = image.ExtensionBlocks + j;
-            ExtensionBlock* eb2 = image.ExtensionBlocks + j + 1;
-            if (eb1->Function == APPLICATION_EXT_FUNC_CODE
-                    // look for "NETSCAPE2.0" app extension
-                    && eb1->ByteCount == 11
-                    && !memcmp((const char*)(eb1->Bytes), "NETSCAPE2.0", 11)
-                    // verify extension contents and get loop count
-                    && eb2->Function == CONTINUE_EXT_FUNC_CODE
-                    && eb2->ByteCount == 3
-                    && eb2->Bytes[0] == 1) {
-                mLoopCount = (int)(eb2->Bytes[2] << 8) + (int)(eb2->Bytes[1]);
-            }
-        }
-
-        DGifSavedExtensionToGCB(mGif, i, &gcb);
-
-        // timing
-        durationMs += getDelayMs(gcb);
-
-        // preserve logic
-        mPreservedFrames[i] = false;
-        mRestoringFrames[i] = -1;
-        if (gcb.DisposalMode == DISPOSE_PREVIOUS && lastUnclearedFrame >= 0) {
-            mPreservedFrames[lastUnclearedFrame] = true;
-            mRestoringFrames[i] = lastUnclearedFrame;
-        }
-        if (!willBeCleared(gcb)) {
-            lastUnclearedFrame = i;
-        }
-    }
-
-#if GIF_DEBUG
-    ALOGD("FrameSequence_gif created with size %d %d, frames %d dur %ld",
-            mGif->SWidth, mGif->SHeight, mGif->ImageCount, durationMs);
-    for (int i = 0; i < mGif->ImageCount; i++) {
-        DGifSavedExtensionToGCB(mGif, i, &gcb);
-        ALOGD("    Frame %d - must preserve %d, restore point %d, trans color %d",
-                i, mPreservedFrames[i], mRestoringFrames[i], gcb.TransparentColor);
-    }
-#endif
-
-    const ColorMapObject* cmap = mGif->SColorMap;
-    if (cmap) {
-        // calculate bg color
-        GraphicsControlBlock gcb;
-        DGifSavedExtensionToGCB(mGif, 0, &gcb);
-        if (gcb.TransparentColor == NO_TRANSPARENT_COLOR
-                && mGif->SBackGroundColor < cmap->ColorCount) {
-            mBgColor = gifColorToColor8888(cmap->Colors[mGif->SBackGroundColor]);
-        }
-    }
-}
-
-FrameSequence_gif::~FrameSequence_gif() {
-    if (mGif) {
-        DGifCloseFile(mGif, NULL);
-    }
-    delete[] mPreservedFrames;
-    delete[] mRestoringFrames;
-}
-
-FrameSequenceState* FrameSequence_gif::createState() const {
-    return new FrameSequenceState_gif(*this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// draw helpers
-////////////////////////////////////////////////////////////////////////////////
-
-// return true if area of 'target' is completely covers area of 'covered'
-static bool checkIfCover(const GifImageDesc& target, const GifImageDesc& covered) {
-    return target.Left <= covered.Left
-            && covered.Left + covered.Width <= target.Left + target.Width
-            && target.Top <= covered.Top
-            && covered.Top + covered.Height <= target.Top + target.Height;
-}
-
-static void copyLine(Color8888* dst, const unsigned char* src, const ColorMapObject* cmap,
-                     int transparent, int width) {
-    for (; width > 0; width--, src++, dst++) {
-        if (*src != transparent && *src < cmap->ColorCount) {
-            *dst = gifColorToColor8888(cmap->Colors[*src]);
-        }
-    }
-}
-
-static void setLineColor(Color8888* dst, Color8888 color, int width) {
-    for (; width > 0; width--, dst++) {
-        *dst = color;
-    }
-}
-
-static void getCopySize(const GifImageDesc& imageDesc, int maxWidth, int maxHeight,
-        GifWord& copyWidth, GifWord& copyHeight) {
-    copyWidth = imageDesc.Width;
-    if (imageDesc.Left + copyWidth > maxWidth) {
-        copyWidth = maxWidth - imageDesc.Left;
-    }
-    copyHeight = imageDesc.Height;
-    if (imageDesc.Top + copyHeight > maxHeight) {
-        copyHeight = maxHeight - imageDesc.Top;
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Frame sequence state
-////////////////////////////////////////////////////////////////////////////////
-
-FrameSequenceState_gif::FrameSequenceState_gif(const FrameSequence_gif& frameSequence) :
-    mFrameSequence(frameSequence), mPreserveBuffer(NULL), mPreserveBufferFrame(-1) {
-}
-
-FrameSequenceState_gif::~FrameSequenceState_gif() {
-       delete[] mPreserveBuffer;
-}
-
-void FrameSequenceState_gif::savePreserveBuffer(Color8888* outputPtr, int outputPixelStride, int frameNr) {
-    if (frameNr == mPreserveBufferFrame) return;
-
-    mPreserveBufferFrame = frameNr;
-    const int width = mFrameSequence.getWidth();
-    const int height = mFrameSequence.getHeight();
-    if (!mPreserveBuffer) {
-        mPreserveBuffer = new Color8888[width * height];
-    }
-    for (int y = 0; y < height; y++) {
-        memcpy(mPreserveBuffer + width * y,
-                outputPtr + outputPixelStride * y,
-                width * 4);
-    }
-}
-
-void FrameSequenceState_gif::restorePreserveBuffer(Color8888* outputPtr, int outputPixelStride) {
-    const int width = mFrameSequence.getWidth();
-    const int height = mFrameSequence.getHeight();
-    if (!mPreserveBuffer) {
-        ALOGD("preserve buffer not allocated! ah!");
-        return;
-    }
-    for (int y = 0; y < height; y++) {
-        memcpy(outputPtr + outputPixelStride * y,
-                mPreserveBuffer + width * y,
-                width * 4);
-    }
-}
-
-long FrameSequenceState_gif::drawFrame(int frameNr,
-        Color8888* outputPtr, int outputPixelStride, int previousFrameNr) {
-
-    GifFileType* gif = mFrameSequence.getGif();
-    if (!gif) {
-        ALOGD("Cannot drawFrame, mGif is NULL");
-        return -1;
-    }
-
-#if GIF_DEBUG
-    ALOGD("      drawFrame on %p nr %d on addr %p, previous frame nr %d",
-            this, frameNr, outputPtr, previousFrameNr);
-#endif
-
-    const int height = mFrameSequence.getHeight();
-    const int width = mFrameSequence.getWidth();
-
-    GraphicsControlBlock gcb;
-
-    int start = max(previousFrameNr + 1, 0);
-
-    for (int i = max(start - 1, 0); i < frameNr; i++) {
-        int neededPreservedFrame = mFrameSequence.getRestoringFrame(i);
-        if (neededPreservedFrame >= 0 && (mPreserveBufferFrame != neededPreservedFrame)) {
-#if GIF_DEBUG
-            ALOGD("frame %d needs frame %d preserved, but %d is currently, so drawing from scratch",
-                    i, neededPreservedFrame, mPreserveBufferFrame);
-#endif
-            start = 0;
-        }
-    }
-
-    for (int i = start; i <= frameNr; i++) {
-        DGifSavedExtensionToGCB(gif, i, &gcb);
-        const SavedImage& frame = gif->SavedImages[i];
-
-#if GIF_DEBUG
-        bool frameOpaque = gcb.TransparentColor == NO_TRANSPARENT_COLOR;
-        ALOGD("producing frame %d, drawing frame %d (opaque %d, disp %d, del %d)",
-                frameNr, i, frameOpaque, gcb.DisposalMode, gcb.DelayTime);
-#endif
-        if (i == 0) {
-            //clear bitmap
-            Color8888 bgColor = mFrameSequence.getBackgroundColor();
-            for (int y = 0; y < height; y++) {
-                for (int x = 0; x < width; x++) {
-                    outputPtr[y * outputPixelStride + x] = bgColor;
-                }
-            }
-        } else {
-            GraphicsControlBlock prevGcb;
-            DGifSavedExtensionToGCB(gif, i - 1, &prevGcb);
-            const SavedImage& prevFrame = gif->SavedImages[i - 1];
-            bool prevFrameDisposed = willBeCleared(prevGcb);
-
-            bool newFrameOpaque = gcb.TransparentColor == NO_TRANSPARENT_COLOR;
-            bool prevFrameCompletelyCovered = newFrameOpaque
-                    && checkIfCover(frame.ImageDesc, prevFrame.ImageDesc);
-
-            if (prevFrameDisposed && !prevFrameCompletelyCovered) {
-                switch (prevGcb.DisposalMode) {
-                case DISPOSE_BACKGROUND: {
-                    Color8888* dst = outputPtr + prevFrame.ImageDesc.Left +
-                            prevFrame.ImageDesc.Top * outputPixelStride;
-
-                    GifWord copyWidth, copyHeight;
-                    getCopySize(prevFrame.ImageDesc, width, height, copyWidth, copyHeight);
-                    for (; copyHeight > 0; copyHeight--) {
-                        setLineColor(dst, TRANSPARENT, copyWidth);
-                        dst += outputPixelStride;
-                    }
-                } break;
-                case DISPOSE_PREVIOUS: {
-                    restorePreserveBuffer(outputPtr, outputPixelStride);
-                } break;
-                }
-            }
-
-            if (mFrameSequence.getPreservedFrame(i - 1)) {
-                // currently drawn frame will be restored by a following DISPOSE_PREVIOUS draw, so
-                // we preserve it
-                savePreserveBuffer(outputPtr, outputPixelStride, i - 1);
-            }
-        }
-
-        bool willBeCleared = gcb.DisposalMode == DISPOSE_BACKGROUND
-                || gcb.DisposalMode == DISPOSE_PREVIOUS;
-        if (i == frameNr || !willBeCleared) {
-            const ColorMapObject* cmap = gif->SColorMap;
-            if (frame.ImageDesc.ColorMap) {
-                cmap = frame.ImageDesc.ColorMap;
-            }
-
-            // If a cmap is missing, the frame can't be decoded, so we skip it.
-            if (cmap) {
-                const unsigned char* src = (unsigned char*)frame.RasterBits;
-                Color8888* dst = outputPtr + frame.ImageDesc.Left +
-                        frame.ImageDesc.Top * outputPixelStride;
-                GifWord copyWidth, copyHeight;
-                getCopySize(frame.ImageDesc, width, height, copyWidth, copyHeight);
-                for (; copyHeight > 0; copyHeight--) {
-                    copyLine(dst, src, cmap, gcb.TransparentColor, copyWidth);
-                    src += frame.ImageDesc.Width;
-                    dst += outputPixelStride;
-                }
-            }
-        }
-    }
-
-    // return last frame's delay
-    const int maxFrame = gif->ImageCount;
-    const int lastFrame = (frameNr + maxFrame - 1) % maxFrame;
-    DGifSavedExtensionToGCB(gif, lastFrame, &gcb);
-    return getDelayMs(gcb);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Registry
-////////////////////////////////////////////////////////////////////////////////
-
-#include "Registry.h"
-
-static bool isGif(void* header, int header_size) {
-    return !memcmp(GIF_STAMP, header, GIF_STAMP_LEN)
-            || !memcmp(GIF87_STAMP, header, GIF_STAMP_LEN)
-            || !memcmp(GIF89_STAMP, header, GIF_STAMP_LEN);
-}
-
-static bool acceptsBuffers() {
-    return false;
-}
-
-static FrameSequence* createFramesequence(Stream* stream) {
-    return new FrameSequence_gif(stream);
-}
-
-static RegistryEntry gEntry = {
-        GIF_STAMP_LEN,
-        isGif,
-        createFramesequence,
-        NULL,
-        acceptsBuffers,
-};
-static Registry gRegister(gEntry);
diff --git a/framesequence/jni/FrameSequence_gif.h b/framesequence/jni/FrameSequence_gif.h
deleted file mode 100644
index 563f5b8..0000000
--- a/framesequence/jni/FrameSequence_gif.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RASTERMILL_FRAMESQUENCE_GIF_H
-#define RASTERMILL_FRAMESQUENCE_GIF_H
-
-#include "config.h"
-#include "gif_lib.h"
-
-#include "Stream.h"
-#include "Color.h"
-#include "FrameSequence.h"
-
-class FrameSequence_gif : public FrameSequence {
-public:
-    FrameSequence_gif(Stream* stream);
-    virtual ~FrameSequence_gif();
-
-    virtual int getWidth() const {
-        return mGif ? mGif->SWidth : 0;
-    }
-
-    virtual int getHeight() const {
-        return mGif ? mGif->SHeight : 0;
-    }
-
-    virtual bool isOpaque() const {
-        return (mBgColor & COLOR_8888_ALPHA_MASK) == COLOR_8888_ALPHA_MASK;
-    }
-
-    virtual int getFrameCount() const {
-        return mGif ? mGif->ImageCount : 0;
-    }
-
-    virtual int getDefaultLoopCount() const {
-        return mLoopCount;
-    }
-
-    virtual jobject getRawByteBuffer() const {
-        return NULL;
-    }
-
-    virtual FrameSequenceState* createState() const;
-
-    GifFileType* getGif() const { return mGif; }
-    Color8888 getBackgroundColor() const { return mBgColor; }
-    bool getPreservedFrame(int frameIndex) const { return mPreservedFrames[frameIndex]; }
-    int getRestoringFrame(int frameIndex) const { return mRestoringFrames[frameIndex]; }
-
-private:
-    GifFileType* mGif;
-    int mLoopCount;
-    Color8888 mBgColor;
-
-    // array of bool per frame - if true, frame data is used by a later DISPOSE_PREVIOUS frame
-    bool* mPreservedFrames;
-
-    // array of ints per frame - if >= 0, points to the index of the preserve that frame needs
-    int* mRestoringFrames;
-};
-
-class FrameSequenceState_gif : public FrameSequenceState {
-public:
-    FrameSequenceState_gif(const FrameSequence_gif& frameSequence);
-    virtual ~FrameSequenceState_gif();
-
-    // returns frame's delay time in ms
-    virtual long drawFrame(int frameNr,
-            Color8888* outputPtr, int outputPixelStride, int previousFrameNr);
-
-private:
-    void savePreserveBuffer(Color8888* outputPtr, int outputPixelStride, int frameNr);
-    void restorePreserveBuffer(Color8888* outputPtr, int outputPixelStride);
-
-    const FrameSequence_gif& mFrameSequence;
-    Color8888* mPreserveBuffer;
-    int mPreserveBufferFrame;
-};
-
-#endif //RASTERMILL_FRAMESQUENCE_GIF_H
diff --git a/framesequence/jni/FrameSequence_webp.cpp b/framesequence/jni/FrameSequence_webp.cpp
deleted file mode 100644
index f1bae82..0000000
--- a/framesequence/jni/FrameSequence_webp.cpp
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string.h>
-#include "JNIHelpers.h"
-#include "utils/log.h"
-#include "utils/math.h"
-#include "webp/format_constants.h"
-
-#include "FrameSequence_webp.h"
-
-#define WEBP_DEBUG 0
-
-////////////////////////////////////////////////////////////////////////////////
-// Frame sequence
-////////////////////////////////////////////////////////////////////////////////
-
-static uint32_t GetLE32(const uint8_t* const data) {
-    return MKFOURCC(data[0], data[1], data[2], data[3]);
-}
-
-// Returns true if the frame covers full canvas.
-static bool isFullFrame(const WebPIterator& frame, int canvasWidth, int canvasHeight) {
-    return (frame.width == canvasWidth && frame.height == canvasHeight);
-}
-
-// Returns true if the rectangle defined by 'frame' contains pixel (x, y).
-static bool FrameContainsPixel(const WebPIterator& frame, int x, int y) {
-    const int left = frame.x_offset;
-    const int right = left + frame.width;
-    const int top = frame.y_offset;
-    const int bottom = top + frame.height;
-    return x >= left && x < right && y >= top && y < bottom;
-}
-
-// Construct mIsKeyFrame array.
-void FrameSequence_webp::constructDependencyChain() {
-    const size_t frameCount = getFrameCount();
-    mIsKeyFrame = new bool[frameCount];
-    const int canvasWidth = getWidth();
-    const int canvasHeight = getHeight();
-
-    WebPIterator prev;
-    WebPIterator curr;
-
-    // Note: WebPDemuxGetFrame() uses base-1 counting.
-    int ok = WebPDemuxGetFrame(mDemux, 1, &curr);
-    ALOG_ASSERT(ok, "Could not retrieve frame# 0");
-    mIsKeyFrame[0] = true;  // 0th frame is always a key frame.
-    for (size_t i = 1; i < frameCount; i++) {
-        prev = curr;
-        ok = WebPDemuxGetFrame(mDemux, i + 1, &curr);  // Get ith frame.
-        ALOG_ASSERT(ok, "Could not retrieve frame# %d", i);
-
-        if ((!curr.has_alpha || curr.blend_method == WEBP_MUX_NO_BLEND) &&
-                isFullFrame(curr, canvasWidth, canvasHeight)) {
-            mIsKeyFrame[i] = true;
-        } else {
-            mIsKeyFrame[i] = (prev.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) &&
-                    (isFullFrame(prev, canvasWidth, canvasHeight) || mIsKeyFrame[i - 1]);
-        }
-    }
-    WebPDemuxReleaseIterator(&prev);
-    WebPDemuxReleaseIterator(&curr);
-
-#if WEBP_DEBUG
-    ALOGD("Dependency chain:");
-    for (size_t i = 0; i < frameCount; i++) {
-        ALOGD("Frame# %zu: %s", i, mIsKeyFrame[i] ? "Key frame" : "NOT a key frame");
-    }
-#endif
-}
-
-FrameSequence_webp::FrameSequence_webp(Stream* stream)
-        : mDemux(NULL)
-        , mIsKeyFrame(NULL)
-        , mRawByteBuffer(NULL) {
-    if (stream->getRawBuffer() != NULL) {
-        mData.size = stream->getRawBufferSize();
-        mData.bytes = stream->getRawBufferAddr();
-        mRawByteBuffer = stream->getRawBuffer();
-    } else {
-        // Read RIFF header to get file size.
-        uint8_t riff_header[RIFF_HEADER_SIZE];
-        if (stream->read(riff_header, RIFF_HEADER_SIZE) != RIFF_HEADER_SIZE) {
-            ALOGE("WebP header load failed");
-            return;
-        }
-        uint32_t readSize = GetLE32(riff_header + TAG_SIZE);
-        if (readSize > MAX_CHUNK_PAYLOAD) {
-            ALOGE("WebP got header size too large");
-            return;
-        }
-        mData.size = CHUNK_HEADER_SIZE + readSize;
-        if(mData.size < RIFF_HEADER_SIZE) {
-            ALOGE("WebP file malformed");
-            return;
-        }
-        mData.bytes = new uint8_t[mData.size];
-        memcpy((void*)mData.bytes, riff_header, RIFF_HEADER_SIZE);
-
-        // Read rest of the bytes.
-        void* remaining_bytes = (void*)(mData.bytes + RIFF_HEADER_SIZE);
-        size_t remaining_size = mData.size - RIFF_HEADER_SIZE;
-        if (stream->read(remaining_bytes, remaining_size) != remaining_size) {
-            ALOGE("WebP full load failed");
-            return;
-        }
-    }
-
-    // Construct demux.
-    mDemux = WebPDemux(&mData);
-    if (!mDemux) {
-        ALOGE("Parsing of WebP container file failed");
-        return;
-    }
-    mLoopCount = WebPDemuxGetI(mDemux, WEBP_FF_LOOP_COUNT);
-    mFormatFlags = WebPDemuxGetI(mDemux, WEBP_FF_FORMAT_FLAGS);
-#if WEBP_DEBUG
-    ALOGD("FrameSequence_webp created with size = %d x %d, number of frames = %d, flags = 0x%X",
-          getWidth(), getHeight(), getFrameCount(), mFormatFlags);
-#endif
-    constructDependencyChain();
-}
-
-FrameSequence_webp::~FrameSequence_webp() {
-    WebPDemuxDelete(mDemux);
-    delete[] mIsKeyFrame;
-    if (mRawByteBuffer == NULL) {
-        delete[] mData.bytes;
-    }
-}
-
-FrameSequenceState* FrameSequence_webp::createState() const {
-    return new FrameSequenceState_webp(*this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// draw helpers
-////////////////////////////////////////////////////////////////////////////////
-
-static bool willBeCleared(const WebPIterator& iter) {
-    return iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND;
-}
-
-// return true if area of 'target' completely covers area of 'covered'
-static bool checkIfCover(const WebPIterator& target, const WebPIterator& covered) {
-    const int covered_x_max = covered.x_offset + covered.width;
-    const int target_x_max = target.x_offset + target.width;
-    const int covered_y_max = covered.y_offset + covered.height;
-    const int target_y_max = target.y_offset + target.height;
-    return target.x_offset <= covered.x_offset
-           && covered_x_max <= target_x_max
-           && target.y_offset <= covered.y_offset
-           && covered_y_max <= target_y_max;
-}
-
-// Clear all pixels in a line to transparent.
-static void clearLine(Color8888* dst, int width) {
-    memset(dst, 0, width * sizeof(*dst));  // Note: Assumes TRANSPARENT == 0x0.
-}
-
-// Copy all pixels from 'src' to 'dst'.
-static void copyFrame(const Color8888* src, int srcStride, Color8888* dst, int dstStride,
-        int width, int height) {
-    for (int y = 0; y < height; y++) {
-        memcpy(dst, src, width * sizeof(*dst));
-        src += srcStride;
-        dst += dstStride;
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Frame sequence state
-////////////////////////////////////////////////////////////////////////////////
-
-FrameSequenceState_webp::FrameSequenceState_webp(const FrameSequence_webp& frameSequence) :
-        mFrameSequence(frameSequence) {
-    WebPInitDecoderConfig(&mDecoderConfig);
-    mDecoderConfig.output.is_external_memory = 1;
-    mDecoderConfig.output.colorspace = MODE_rgbA;  // Pre-multiplied alpha mode.
-    const int canvasWidth = mFrameSequence.getWidth();
-    const int canvasHeight = mFrameSequence.getHeight();
-    mPreservedBuffer = new Color8888[canvasWidth * canvasHeight];
-}
-
-FrameSequenceState_webp::~FrameSequenceState_webp() {
-    delete[] mPreservedBuffer;
-}
-
-void FrameSequenceState_webp::initializeFrame(const WebPIterator& currIter, Color8888* currBuffer,
-        int currStride, const WebPIterator& prevIter, const Color8888* prevBuffer, int prevStride) {
-    const int canvasWidth = mFrameSequence.getWidth();
-    const int canvasHeight = mFrameSequence.getHeight();
-    const bool currFrameIsKeyFrame = mFrameSequence.isKeyFrame(currIter.frame_num - 1);
-
-    if (currFrameIsKeyFrame) {  // Clear canvas.
-        for (int y = 0; y < canvasHeight; y++) {
-            Color8888* dst = currBuffer + y * currStride;
-            clearLine(dst, canvasWidth);
-        }
-    } else {
-        // Preserve previous frame as starting state of current frame.
-        copyFrame(prevBuffer, prevStride, currBuffer, currStride, canvasWidth, canvasHeight);
-
-        // Dispose previous frame rectangle to Background if needed.
-        bool prevFrameCompletelyCovered =
-                (!currIter.has_alpha || currIter.blend_method == WEBP_MUX_NO_BLEND) &&
-                checkIfCover(currIter, prevIter);
-        if ((prevIter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) &&
-                !prevFrameCompletelyCovered) {
-            Color8888* dst = currBuffer + prevIter.x_offset + prevIter.y_offset * currStride;
-            for (int j = 0; j < prevIter.height; j++) {
-                clearLine(dst, prevIter.width);
-                dst += currStride;
-            }
-        }
-    }
-}
-
-bool FrameSequenceState_webp::decodeFrame(const WebPIterator& currIter, Color8888* currBuffer,
-        int currStride, const WebPIterator& prevIter, const Color8888* prevBuffer, int prevStride) {
-    Color8888* dst = currBuffer + currIter.x_offset + currIter.y_offset * currStride;
-    mDecoderConfig.output.u.RGBA.rgba = (uint8_t*)dst;
-    mDecoderConfig.output.u.RGBA.stride = currStride * 4;
-    mDecoderConfig.output.u.RGBA.size = mDecoderConfig.output.u.RGBA.stride * currIter.height;
-
-    const WebPData& currFrame = currIter.fragment;
-    if (WebPDecode(currFrame.bytes, currFrame.size, &mDecoderConfig) != VP8_STATUS_OK) {
-        return false;
-    }
-
-    const int canvasWidth = mFrameSequence.getWidth();
-    const int canvasHeight = mFrameSequence.getHeight();
-    const bool currFrameIsKeyFrame = mFrameSequence.isKeyFrame(currIter.frame_num - 1);
-    // During the decoding of current frame, we may have set some pixels to be transparent
-    // (i.e. alpha < 255). However, the value of each of these pixels should have been determined
-    // by blending it against the value of that pixel in the previous frame if WEBP_MUX_BLEND was
-    // specified. So, we correct these pixels based on disposal method of the previous frame and
-    // the previous frame buffer.
-    if (currIter.blend_method == WEBP_MUX_BLEND && !currFrameIsKeyFrame) {
-        if (prevIter.dispose_method == WEBP_MUX_DISPOSE_NONE) {
-            for (int y = 0; y < currIter.height; y++) {
-                const int canvasY = currIter.y_offset + y;
-                for (int x = 0; x < currIter.width; x++) {
-                    const int canvasX = currIter.x_offset + x;
-                    Color8888& currPixel = currBuffer[canvasY * currStride + canvasX];
-                    // FIXME: Use alpha-blending when alpha is between 0 and 255.
-                    if (!(currPixel & COLOR_8888_ALPHA_MASK)) {
-                        const Color8888 prevPixel = prevBuffer[canvasY * prevStride + canvasX];
-                        currPixel = prevPixel;
-                    }
-                }
-            }
-        } else {  // prevIter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND
-            // Need to restore transparent pixels to as they were just after frame initialization.
-            // That is:
-            //   * Transparent if it belongs to previous frame rectangle <-- This is a no-op.
-            //   * Pixel in the previous canvas otherwise <-- Need to restore.
-            for (int y = 0; y < currIter.height; y++) {
-                const int canvasY = currIter.y_offset + y;
-                for (int x = 0; x < currIter.width; x++) {
-                    const int canvasX = currIter.x_offset + x;
-                    Color8888& currPixel = currBuffer[canvasY * currStride + canvasX];
-                    // FIXME: Use alpha-blending when alpha is between 0 and 255.
-                    if (!(currPixel & COLOR_8888_ALPHA_MASK)
-                            && !FrameContainsPixel(prevIter, canvasX, canvasY)) {
-                        const Color8888 prevPixel = prevBuffer[canvasY * prevStride + canvasX];
-                        currPixel = prevPixel;
-                    }
-                }
-            }
-        }
-    }
-    return true;
-}
-
-long FrameSequenceState_webp::drawFrame(int frameNr,
-        Color8888* outputPtr, int outputPixelStride, int previousFrameNr) {
-    WebPDemuxer* demux = mFrameSequence.getDemuxer();
-    ALOG_ASSERT(demux, "Cannot drawFrame, mDemux is NULL");
-
-#if WEBP_DEBUG
-    ALOGD("  drawFrame called for frame# %d, previous frame# %d", frameNr, previousFrameNr);
-#endif
-
-    const int canvasWidth = mFrameSequence.getWidth();
-    const int canvasHeight = mFrameSequence.getHeight();
-
-    // Find the first frame to be decoded.
-    int start = max(previousFrameNr + 1, 0);
-    int earliestRequired = frameNr;
-    while (earliestRequired > start) {
-        if (mFrameSequence.isKeyFrame(earliestRequired)) {
-            start = earliestRequired;
-            break;
-        }
-        earliestRequired--;
-    }
-
-    WebPIterator currIter;
-    WebPIterator prevIter;
-    int ok = WebPDemuxGetFrame(demux, start, &currIter);  // Get frame number 'start - 1'.
-    ALOG_ASSERT(ok, "Could not retrieve frame# %d", start - 1);
-
-    // Use preserve buffer only if needed.
-    Color8888* prevBuffer = (frameNr == 0) ? outputPtr : mPreservedBuffer;
-    int prevStride = (frameNr == 0) ? outputPixelStride : canvasWidth;
-    Color8888* currBuffer = outputPtr;
-    int currStride = outputPixelStride;
-
-    for (int i = start; i <= frameNr; i++) {
-        prevIter = currIter;
-        ok = WebPDemuxGetFrame(demux, i + 1, &currIter);  // Get ith frame.
-        ALOG_ASSERT(ok, "Could not retrieve frame# %d", i);
-#if WEBP_DEBUG
-        ALOGD("      producing frame %d (has_alpha = %d, dispose = %s, blend = %s, duration = %d)",
-              i, currIter.has_alpha,
-              (currIter.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none" : "background",
-              (currIter.blend_method == WEBP_MUX_BLEND) ? "yes" : "no", currIter.duration);
-#endif
-        // We swap the prev/curr buffers as we go.
-        Color8888* tmpBuffer = prevBuffer;
-        prevBuffer = currBuffer;
-        currBuffer = tmpBuffer;
-
-        int tmpStride = prevStride;
-        prevStride = currStride;
-        currStride = tmpStride;
-
-#if WEBP_DEBUG
-        ALOGD("            prev = %p, curr = %p, out = %p, tmp = %p",
-              prevBuffer, currBuffer, outputPtr, mPreservedBuffer);
-#endif
-        // Process this frame.
-        initializeFrame(currIter, currBuffer, currStride, prevIter, prevBuffer, prevStride);
-
-        if (i == frameNr || !willBeCleared(currIter)) {
-            if (!decodeFrame(currIter, currBuffer, currStride, prevIter, prevBuffer, prevStride)) {
-                ALOGE("Error decoding frame# %d", i);
-                return -1;
-            }
-        }
-    }
-
-    if (outputPtr != currBuffer) {
-        copyFrame(currBuffer, currStride, outputPtr, outputPixelStride, canvasWidth, canvasHeight);
-    }
-
-    // Return last frame's delay.
-    const int frameCount = mFrameSequence.getFrameCount();
-    const int lastFrame = (frameNr + frameCount - 1) % frameCount;
-    ok = WebPDemuxGetFrame(demux, lastFrame + 1, &currIter);
-    ALOG_ASSERT(ok, "Could not retrieve frame# %d", lastFrame);
-    const int lastFrameDelay = currIter.duration;
-
-    WebPDemuxReleaseIterator(&currIter);
-    WebPDemuxReleaseIterator(&prevIter);
-
-    return lastFrameDelay;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Registry
-////////////////////////////////////////////////////////////////////////////////
-
-#include "Registry.h"
-
-static bool isWebP(void* header, int header_size) {
-    const uint8_t* const header_str = (const uint8_t*)header;
-    return (header_size >= RIFF_HEADER_SIZE) &&
-            !memcmp("RIFF", header_str, 4) &&
-            !memcmp("WEBP", header_str + 8, 4);
-}
-
-static bool acceptsWebPBuffer() {
-    return true;
-}
-
-static FrameSequence* createFramesequence(Stream* stream) {
-    return new FrameSequence_webp(stream);
-}
-
-static RegistryEntry gEntry = {
-        RIFF_HEADER_SIZE,
-        isWebP,
-        createFramesequence,
-        NULL,
-        acceptsWebPBuffer,
-};
-static Registry gRegister(gEntry);
-
diff --git a/framesequence/jni/FrameSequence_webp.h b/framesequence/jni/FrameSequence_webp.h
deleted file mode 100644
index 148146f..0000000
--- a/framesequence/jni/FrameSequence_webp.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RASTERMILL_FRAMESQUENCE_WEBP_H
-#define RASTERMILL_FRAMESQUENCE_WEBP_H
-
-#include "config.h"
-#include "webp/decode.h"
-#include "webp/demux.h"
-
-#include "Stream.h"
-#include "Color.h"
-#include "FrameSequence.h"
-
-// Parser for a possibly-animated WebP bitstream.
-class FrameSequence_webp : public FrameSequence {
-public:
-    FrameSequence_webp(Stream* stream);
-    virtual ~FrameSequence_webp();
-
-    virtual int getWidth() const {
-        if (!mDemux) {
-            return 0;
-        }
-        return WebPDemuxGetI(mDemux, WEBP_FF_CANVAS_WIDTH);
-    }
-
-    virtual int getHeight() const {
-        if (!mDemux) {
-            return 0;
-        }
-        return WebPDemuxGetI(mDemux, WEBP_FF_CANVAS_HEIGHT);
-    }
-
-    virtual bool isOpaque() const {
-        return !(mFormatFlags & ALPHA_FLAG);
-    }
-
-    virtual int getFrameCount() const {
-        if (!mDemux) {
-            return 0;
-        }
-        return WebPDemuxGetI(mDemux, WEBP_FF_FRAME_COUNT);
-    }
-
-    virtual int getDefaultLoopCount() const {
-        return mLoopCount;
-    }
-
-    virtual jobject getRawByteBuffer() const {
-        return mRawByteBuffer;
-    }
-
-    virtual FrameSequenceState* createState() const;
-
-    WebPDemuxer* getDemuxer() const { return mDemux; }
-
-    bool isKeyFrame(size_t frameNr) const { return mIsKeyFrame[frameNr]; }
-
-private:
-    void constructDependencyChain();
-
-    WebPData mData;
-    WebPDemuxer* mDemux;
-    int mLoopCount;
-    uint32_t mFormatFlags;
-    // mIsKeyFrame[i] is true if ith canvas can be constructed without decoding any prior frames.
-    bool* mIsKeyFrame;
-    jobject mRawByteBuffer = nullptr;
-};
-
-// Produces frames of a possibly-animated WebP file for display.
-class FrameSequenceState_webp : public FrameSequenceState {
-public:
-    FrameSequenceState_webp(const FrameSequence_webp& frameSequence);
-    virtual ~FrameSequenceState_webp();
-
-    // Returns frame's delay time in milliseconds.
-    virtual long drawFrame(int frameNr,
-            Color8888* outputPtr, int outputPixelStride, int previousFrameNr);
-
-private:
-    void initializeFrame(const WebPIterator& currIter, Color8888* currBuffer, int currStride,
-            const WebPIterator& prevIter, const Color8888* prevBuffer, int prevStride);
-    bool decodeFrame(const WebPIterator& iter, Color8888* currBuffer, int currStride,
-            const WebPIterator& prevIter, const Color8888* prevBuffer, int prevStride);
-
-    const FrameSequence_webp& mFrameSequence;
-    WebPDecoderConfig mDecoderConfig;
-    Color8888* mPreservedBuffer;
-};
-
-#endif //RASTERMILL_FRAMESQUENCE_WEBP_H
diff --git a/framesequence/jni/JNIHelpers.cpp b/framesequence/jni/JNIHelpers.cpp
deleted file mode 100644
index dd0c818..0000000
--- a/framesequence/jni/JNIHelpers.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "JNIHelpers.h"
-#include "utils/log.h"
-
-void jniThrowException(JNIEnv* env, const char* className, const char* msg) {
-    jclass clazz = env->FindClass(className);
-    if (!clazz) {
-        ALOGE("Unable to find exception class %s", className);
-        /* ClassNotFoundException now pending */
-        return;
-    }
-
-    if (env->ThrowNew(clazz, msg) != JNI_OK) {
-        ALOGE("Failed throwing '%s' '%s'", className, msg);
-        /* an exception, most likely OOM, will now be pending */
-    }
-    env->DeleteLocalRef(clazz);
-}
diff --git a/framesequence/jni/JNIHelpers.h b/framesequence/jni/JNIHelpers.h
deleted file mode 100644
index 3718b38..0000000
--- a/framesequence/jni/JNIHelpers.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RASTERMILL_JNIHELPERS_H
-#define RASTERMILL_JNIHELPERS_H
-
-#include <jni.h>
-
-#define METHOD_COUNT(methodArray) (sizeof(methodArray) / sizeof((methodArray)[0]))
-
-#define ILLEGAL_STATE_EXEPTION "java/lang/IllegalStateException"
-
-void jniThrowException(JNIEnv* env, const char* className, const char* msg);
-
-
-#endif //RASTERMILL_JNIHELPERS_H
diff --git a/framesequence/jni/Registry.cpp b/framesequence/jni/Registry.cpp
deleted file mode 100644
index e632bb2..0000000
--- a/framesequence/jni/Registry.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Registry.h"
-
-#include "Stream.h"
-
-static Registry* gHead = 0;
-static int gHeaderBytesRequired = 0;
-
-Registry::Registry(const RegistryEntry& entry) {
-    mImpl = entry;
-
-    mNext = gHead;
-    gHead = this;
-
-    if (gHeaderBytesRequired < entry.requiredHeaderBytes) {
-        gHeaderBytesRequired = entry.requiredHeaderBytes;
-    }
-}
-
-const RegistryEntry* Registry::Find(Stream* stream) {
-    Registry* registry = gHead;
-
-    if (stream->getRawBuffer() != NULL) {
-        while (registry) {
-            if (registry->mImpl.acceptsBuffer()) {
-                return &(registry->mImpl);
-            }
-            registry = registry->mNext;
-        }
-    } else {
-        int headerSize = gHeaderBytesRequired;
-        char header[headerSize];
-        headerSize = stream->peek(header, headerSize);
-        while (registry) {
-            if (headerSize >= registry->mImpl.requiredHeaderBytes
-                    && registry->mImpl.checkHeader(header, headerSize)) {
-                return &(registry->mImpl);
-            }
-            registry = registry->mNext;
-        }
-    }
-    return 0;
-}
-
diff --git a/framesequence/jni/Registry.h b/framesequence/jni/Registry.h
deleted file mode 100644
index 8db43cf..0000000
--- a/framesequence/jni/Registry.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RASTERMILL_REGISTRY_H
-#define RASTERMILL_REGISTRY_H
-
-#include "jni.h"
-#include <stdint.h>
-
-class FrameSequence;
-class Decoder;
-class Stream;
-
-struct RegistryEntry {
-    int requiredHeaderBytes;
-    bool (*checkHeader)(void* header, int header_size);
-    FrameSequence* (*createFrameSequence)(Stream* stream);
-    Decoder* (*createDecoder)(Stream* stream);
-    bool (*acceptsBuffer)();
-};
-
-/**
- * Template class for registering subclasses that can produce instances of themselves given a
- * DataStream pointer.
- *
- * The super class / root constructable type only needs to define a single static construction
- * meathod that creates an instance by iterating through all factory methods.
- */
-class Registry {
-public:
-    Registry(const RegistryEntry& entry);
-
-    static const RegistryEntry* Find(Stream* stream);
-
-private:
-    RegistryEntry mImpl;
-    Registry* mNext;
-};
-
-#endif // RASTERMILL_REGISTRY_H
diff --git a/framesequence/jni/Stream.cpp b/framesequence/jni/Stream.cpp
deleted file mode 100644
index 10dc805..0000000
--- a/framesequence/jni/Stream.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Stream"
-
-#include "Stream.h"
-
-#include <string.h>
-
-#include "JNIHelpers.h"
-#include "utils/log.h"
-#include "utils/math.h"
-
-static struct {
-    jmethodID read;
-    jmethodID reset;
-} gInputStreamClassInfo;
-
-Stream::Stream()
-    : mPeekBuffer(0)
-    , mPeekSize(0)
-    , mPeekOffset(0) {
-}
-
-Stream::~Stream() {
-    delete[] mPeekBuffer;
-}
-
-size_t Stream::peek(void* buffer, size_t size) {
-    size_t peek_remaining = mPeekSize - mPeekOffset;
-    if (size > peek_remaining) {
-        char* old_peek = mPeekBuffer;
-        mPeekBuffer = new char[size];
-        if (old_peek) {
-            memcpy(mPeekBuffer, old_peek + mPeekOffset, peek_remaining);
-            delete[] old_peek;
-        }
-        size_t read = doRead(mPeekBuffer + mPeekOffset, size - peek_remaining);
-        mPeekOffset = 0;
-        mPeekSize = peek_remaining + read;
-    }
-    size = min(size, mPeekSize - mPeekOffset);
-    memcpy(buffer, mPeekBuffer + mPeekOffset, size);
-    return size;
-}
-
-size_t Stream::read(void* buffer, size_t size) {
-    size_t bytes_read = 0;
-    size_t peek_remaining = mPeekSize - mPeekOffset;
-    if (peek_remaining) {
-        bytes_read = min(size, peek_remaining);
-        memcpy(buffer, mPeekBuffer + mPeekOffset, bytes_read);
-        mPeekOffset += bytes_read;
-        if (mPeekOffset == mPeekSize) {
-            delete[] mPeekBuffer;
-            mPeekBuffer = 0;
-            mPeekOffset = 0;
-            mPeekSize = 0;
-        }
-        size -= bytes_read;
-        buffer = ((char*) buffer) + bytes_read;
-    }
-    if (size) {
-        bytes_read += doRead(buffer, size);
-    }
-    return bytes_read;
-}
-
-uint8_t* Stream::getRawBufferAddr() {
-    return NULL;
-}
-
-jobject Stream::getRawBuffer() {
-    return NULL;
-}
-
-int Stream::getRawBufferSize() {
-    return 0;
-}
-
-uint8_t* MemoryStream::getRawBufferAddr() {
-    return mBuffer;
-}
-
-jobject MemoryStream::getRawBuffer() {
-    return mRawBuffer;
-}
-
-int MemoryStream::getRawBufferSize() {
-    if (mRawBuffer != NULL) {
-        return mRemaining;
-    } else {
-        return 0;
-    }
-}
-
-size_t MemoryStream::doRead(void* buffer, size_t size) {
-    size = min(size, mRemaining);
-    memcpy(buffer, mBuffer, size);
-    mBuffer += size;
-    mRemaining -= size;
-    return size;
-}
-
-size_t FileStream::doRead(void* buffer, size_t size) {
-    return fread(buffer, 1, size, mFd);
-}
-
-size_t JavaInputStream::doRead(void* dstBuffer, size_t size) {
-    size_t totalBytesRead = 0;
-
-    do {
-        size_t requested = min(size, mByteArrayLength);
-
-        jint bytesRead = mEnv->CallIntMethod(mInputStream,
-                gInputStreamClassInfo.read, mByteArray, 0, requested);
-        if (mEnv->ExceptionCheck() || bytesRead < 0) {
-            return 0;
-        }
-
-        mEnv->GetByteArrayRegion(mByteArray, 0, bytesRead, (jbyte*)dstBuffer);
-        dstBuffer = (char*)dstBuffer + bytesRead;
-        totalBytesRead += bytesRead;
-        size -= bytesRead;
-    } while (size > 0);
-
-    return totalBytesRead;
-}
-
-jint JavaStream_OnLoad(JNIEnv* env) {
-    // Skip the verbose logging on error for these, as they won't be subject
-    // to obfuscators or similar and are thus unlikely to ever fail
-    jclass inputStreamClazz = env->FindClass("java/io/InputStream");
-    if (!inputStreamClazz) {
-        return -1;
-    }
-    gInputStreamClassInfo.read = env->GetMethodID(inputStreamClazz, "read", "([BII)I");
-    gInputStreamClassInfo.reset = env->GetMethodID(inputStreamClazz, "reset", "()V");
-    if (!gInputStreamClassInfo.read || !gInputStreamClassInfo.reset) {
-        return -1;
-    }
-    return 0;
-}
diff --git a/framesequence/jni/Stream.h b/framesequence/jni/Stream.h
deleted file mode 100644
index f0f3895..0000000
--- a/framesequence/jni/Stream.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RASTERMILL_STREAM_H
-#define RASTERMILL_STREAM_H
-
-#include <jni.h>
-#include <stdio.h>
-#include <sys/types.h>
-
-class Stream {
-public:
-    Stream();
-    virtual ~Stream();
-
-    size_t peek(void* buffer, size_t size);
-    size_t read(void* buffer, size_t size);
-    virtual uint8_t* getRawBufferAddr();
-    virtual jobject getRawBuffer();
-    virtual int getRawBufferSize();
-
-protected:
-    virtual size_t doRead(void* buffer, size_t size) = 0;
-
-private:
-    char* mPeekBuffer;
-    size_t mPeekSize;
-    size_t mPeekOffset;
-};
-
-class MemoryStream : public Stream {
-public:
-    MemoryStream(void* buffer, size_t size, jobject buf) :
-            mBuffer((uint8_t*)buffer),
-            mRemaining(size),
-            mRawBuffer(buf) {}
-    virtual uint8_t* getRawBufferAddr();
-    virtual jobject getRawBuffer();
-    virtual int getRawBufferSize();
-
-protected:
-    virtual size_t doRead(void* buffer, size_t size);
-
-private:
-    uint8_t* mBuffer;
-    size_t mRemaining;
-    jobject mRawBuffer;
-};
-
-class FileStream : public Stream {
-public:
-    FileStream(FILE* fd) : mFd(fd) {}
-
-protected:
-    virtual size_t doRead(void* buffer, size_t size);
-
-private:
-    FILE* mFd;
-};
-
-class JavaInputStream : public Stream {
-public:
-    JavaInputStream(JNIEnv* env, jobject inputStream, jbyteArray byteArray) :
-            mEnv(env),
-            mInputStream(inputStream),
-            mByteArray(byteArray),
-            mByteArrayLength(env->GetArrayLength(byteArray)) {}
-
-protected:
-    virtual size_t doRead(void* buffer, size_t size);
-
-private:
-    JNIEnv* mEnv;
-    const jobject mInputStream;
-    const jbyteArray mByteArray;
-    const size_t mByteArrayLength;
-};
-
-jint JavaStream_OnLoad(JNIEnv* env);
-
-#endif //RASTERMILL_STREAM_H
diff --git a/framesequence/jni/utils/log.h b/framesequence/jni/utils/log.h
deleted file mode 100644
index d8441dc..0000000
--- a/framesequence/jni/utils/log.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LOG_H_
-#define LOG_H_
-
-#include <android/log.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Normally we strip ALOGV (VERBOSE messages) from release builds.
- * You can modify this (for example with "#define LOG_NDEBUG 0"
- * at the top of your source file) to change that behavior.
- */
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-/*
- * This is the local tag used for the following simplified
- * logging macros.  You can change this preprocessor definition
- * before using the other macros to change the tag.
- */
-#ifndef LOG_TAG
-#define LOG_TAG "RasterMill"
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose log message using the current LOG_TAG.
- */
-#ifndef ALOGV
-#if LOG_NDEBUG
-#define ALOGV(...)   ((void)0)
-#else
-#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#endif
-#endif
-
-#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
-
-#ifndef ALOGV_IF
-#if LOG_NDEBUG
-#define ALOGV_IF(cond, ...)   ((void)0)
-#else
-#define ALOGV_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug log message using the current LOG_TAG.
- */
-#ifndef ALOGD
-#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGD_IF
-#define ALOGD_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info log message using the current LOG_TAG.
- */
-#ifndef ALOGI
-#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGI_IF
-#define ALOGI_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning log message using the current LOG_TAG.
- */
-#ifndef ALOGW
-#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGW_IF
-#define ALOGW_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error log message using the current LOG_TAG.
- */
-#ifndef ALOGE
-#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGE_IF
-#define ALOGE_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * verbose priority.
- */
-#ifndef IF_ALOGV
-#if LOG_NDEBUG
-#define IF_ALOGV() if (false)
-#else
-#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
-#endif
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * debug priority.
- */
-#ifndef IF_ALOGD
-#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * info priority.
- */
-#ifndef IF_ALOGI
-#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * warn priority.
- */
-#ifndef IF_ALOGW
-#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * error priority.
- */
-#ifndef IF_ALOGE
-#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Log a fatal error.  If the given condition fails, this stops program
- * execution like a normal assertion, but also generating the given message.
- * It is NOT stripped from release builds.  Note that the condition test
- * is -inverted- from the normal assert() semantics.
- */
-#ifndef LOG_ALWAYS_FATAL_IF
-#define LOG_ALWAYS_FATAL_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-#ifndef LOG_ALWAYS_FATAL
-#define LOG_ALWAYS_FATAL(...) \
-    ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
-#endif
-
-/*
- * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
- * are stripped out of release builds.
- */
-#if LOG_NDEBUG
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) ((void)0)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) ((void)0)
-#endif
-
-#else
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
-#endif
-
-#endif
-
-/*
- * Assertion that generates a log message when the assertion fails.
- * Stripped out of release builds.  Uses the current LOG_TAG.
- */
-#ifndef ALOG_ASSERT
-#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
-//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Basic log message macro.
- *
- * Example:
- *  ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
- *
- * The second argument may be NULL or "" to indicate the "global" tag.
- */
-#ifndef ALOG
-#define ALOG(priority, tag, ...) \
-    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to specify a number for the priority.
- */
-#ifndef LOG_PRI
-#define LOG_PRI(priority, tag, ...) \
-    __android_log_print(priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to pass in a varargs ("args" is a va_list).
- */
-#ifndef LOG_PRI_VA
-#define LOG_PRI_VA(priority, tag, fmt, args) \
-    __android_log_vprint(priority, NULL, tag, fmt, args)
-#endif
-
-/*
- * Conditional given a desired logging priority and tag.
- */
-#ifndef IF_ALOG
-#define IF_ALOG(priority, tag) \
-    if (__android_log_assert(ANDROID_##priority, tag))
-#endif
-
-/* Returns 2nd arg.  Used to substitute default value if caller's vararg list
- * is empty.
- */
-#define __android_second(dummy, second, ...)     second
-
-/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
- * returns nothing.
- */
-#define __android_rest(first, ...)               , ## __VA_ARGS__
-
-#define android_printAssert(cond, tag, fmt...) \
-    __android_log_assert(cond, tag, \
-        __android_second(0, ## fmt, NULL) __android_rest(fmt))
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LOG_H_ */
diff --git a/framesequence/jni/utils/math.h b/framesequence/jni/utils/math.h
deleted file mode 100644
index 87f100b..0000000
--- a/framesequence/jni/utils/math.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MATH_H_
-#define MATH_H_
-
-#define max(a,b) \
-   ({ __typeof__ (a) _a = (a); \
-       __typeof__ (b) _b = (b); \
-     _a > _b ? _a : _b; })
-
-#define min(a,b) \
-   ({ __typeof__ (a) _a = (a); \
-       __typeof__ (b) _b = (b); \
-     _a < _b ? _a : _b; })
-
-#endif /* MATH_H_ */
diff --git a/framesequence/samples/FrameSequenceSamples/Android.bp b/framesequence/samples/FrameSequenceSamples/Android.bp
deleted file mode 100644
index f6bd93f..0000000
--- a/framesequence/samples/FrameSequenceSamples/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_app {
-
-    name: "FrameSequenceSample",
-    // java dependency
-    static_libs: ["android-common-framesequence"],
-    jni_libs: ["libframesequence"],
-    // proguard for framesequence library code
-    optimize: {
-        proguard_flags_files: ["proguard.flags"],
-    },
-    sdk_version: "19",
-    srcs: ["src/**/*.java"],
-    resource_dirs: ["res"],
-    aaptflags: [
-        "--auto-add-overlay",
-        "--extra-packages",
-        "com.android.framesequence.samples",
-    ],
-
-    product_specific: true,
-}
diff --git a/framesequence/samples/FrameSequenceSamples/AndroidManifest.xml b/framesequence/samples/FrameSequenceSamples/AndroidManifest.xml
deleted file mode 100644
index d614631..0000000
--- a/framesequence/samples/FrameSequenceSamples/AndroidManifest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.framesequence.samples"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-    <uses-sdk
-        android:minSdkVersion="15"
-        android:targetSdkVersion="18" />
-
-    <application
-        android:allowBackup="true"
-        android:icon="@drawable/ic_launcher"
-        android:label="@string/app_name" >
-        <activity
-            android:name=".SamplesList"
-            android:label="@string/app_name" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity android:name=".FrameSequenceTest" />
-    </application>
-
-</manifest>
diff --git a/framesequence/samples/FrameSequenceSamples/build.xml b/framesequence/samples/FrameSequenceSamples/build.xml
deleted file mode 100644
index 5e55b4e..0000000
--- a/framesequence/samples/FrameSequenceSamples/build.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="RastermillSamples" default="help">
-
-    <!-- The local.properties file is created and updated by the 'android' tool.
-         It contains the path to the SDK. It should *NOT* be checked into
-         Version Control Systems. -->
-    <property file="local.properties" />
-
-    <!-- The ant.properties file can be created by you. It is only edited by the
-         'android' tool to add properties to it.
-         This is the place to change some Ant specific build properties.
-         Here are some properties you may want to change/update:
-
-         source.dir
-             The name of the source directory. Default is 'src'.
-         out.dir
-             The name of the output directory. Default is 'bin'.
-
-         For other overridable properties, look at the beginning of the rules
-         files in the SDK, at tools/ant/build.xml
-
-         Properties related to the SDK location or the project target should
-         be updated using the 'android' tool with the 'update' action.
-
-         This file is an integral part of the build system for your
-         application and should be checked into Version Control Systems.
-
-         -->
-    <property file="ant.properties" />
-
-    <!-- if sdk.dir was not set from one of the property file, then
-         get it from the ANDROID_HOME env var.
-         This must be done before we load project.properties since
-         the proguard config can use sdk.dir -->
-    <property environment="env" />
-    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
-        <isset property="env.ANDROID_HOME" />
-    </condition>
-
-    <!-- The project.properties file is created and updated by the 'android'
-         tool, as well as ADT.
-
-         This contains project specific properties such as project target, and library
-         dependencies. Lower level build properties are stored in ant.properties
-         (or in .classpath for Eclipse projects).
-
-         This file is an integral part of the build system for your
-         application and should be checked into Version Control Systems. -->
-    <loadproperties srcFile="project.properties" />
-
-    <!-- quick check on sdk.dir -->
-    <fail
-            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
-            unless="sdk.dir"
-    />
-
-    <target name="-pre-build">
-        <ant dir="../../" target="release" inheritAll="false" />
-        <copy todir="libs">
-            <fileset dir="../../exported_libs" />
-        </copy>
-    </target>
-
-    <!--
-        Import per project custom build rules if present at the root of the project.
-        This is the place to put custom intermediary targets such as:
-            -pre-build
-            -pre-compile
-            -post-compile (This is typically used for code obfuscation.
-                           Compiled code location: ${out.classes.absolute.dir}
-                           If this is not done in place, override ${out.dex.input.absolute.dir})
-            -post-package
-            -post-build
-            -pre-clean
-    -->
-    <import file="custom_rules.xml" optional="true" />
-
-    <!-- Import the actual build file.
-
-         To customize existing targets, there are two options:
-         - Customize only one target:
-             - copy/paste the target into this file, *before* the
-               <import> task.
-             - customize it to your needs.
-         - Customize the whole content of build.xml
-             - copy/paste the content of the rules files (minus the top node)
-               into this file, replacing the <import> task.
-             - customize to your needs.
-
-         ***********************
-         ****** IMPORTANT ******
-         ***********************
-         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
-         in order to avoid having your file be overridden by tools such as "android update project"
-    -->
-    <!-- version-tag: 1 -->
-    <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>
diff --git a/framesequence/samples/FrameSequenceSamples/proguard.flags b/framesequence/samples/FrameSequenceSamples/proguard.flags
deleted file mode 100644
index 4acde2d..0000000
--- a/framesequence/samples/FrameSequenceSamples/proguard.flags
+++ /dev/null
@@ -1,3 +0,0 @@
--keep class android.support.rastermill.** {
-  *;
-}
diff --git a/framesequence/samples/FrameSequenceSamples/project.properties b/framesequence/samples/FrameSequenceSamples/project.properties
deleted file mode 100644
index ce39f2d..0000000
--- a/framesequence/samples/FrameSequenceSamples/project.properties
+++ /dev/null
@@ -1,14 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-18
diff --git a/framesequence/samples/FrameSequenceSamples/res/drawable-hdpi/ic_launcher.png b/framesequence/samples/FrameSequenceSamples/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 96a442e..0000000
--- a/framesequence/samples/FrameSequenceSamples/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/framesequence/samples/FrameSequenceSamples/res/drawable-mdpi/ic_launcher.png b/framesequence/samples/FrameSequenceSamples/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 359047d..0000000
--- a/framesequence/samples/FrameSequenceSamples/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/framesequence/samples/FrameSequenceSamples/res/drawable-xhdpi/ic_launcher.png b/framesequence/samples/FrameSequenceSamples/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 71c6d76..0000000
--- a/framesequence/samples/FrameSequenceSamples/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/framesequence/samples/FrameSequenceSamples/res/layout/basic_test_activity.xml b/framesequence/samples/FrameSequenceSamples/res/layout/basic_test_activity.xml
deleted file mode 100644
index ebe7229..0000000
--- a/framesequence/samples/FrameSequenceSamples/res/layout/basic_test_activity.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<LinearLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    <View
-            android:id="@+id/drawableview"
-            android:layout_width="match_parent"
-            android:layout_height="300dp" />
-    <LinearLayout
-            android:orientation="horizontal"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content">
-        <Button
-                android:id="@+id/start"
-                android:text="@string/start"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
-        <Button
-                android:id="@+id/stop"
-                android:text="@string/stop"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
-        <Button
-                android:id="@+id/vis"
-                android:text="@string/vis"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
-        <Button
-                android:id="@+id/invis"
-                android:text="@string/invis"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
-    </LinearLayout>
-    <Button
-            android:id="@+id/circle_mask"
-            android:text="@string/circle_mask"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"/>
-</LinearLayout>
diff --git a/framesequence/samples/FrameSequenceSamples/res/raw/animated_gif.gif b/framesequence/samples/FrameSequenceSamples/res/raw/animated_gif.gif
deleted file mode 100644
index 51baf15..0000000
--- a/framesequence/samples/FrameSequenceSamples/res/raw/animated_gif.gif
+++ /dev/null
Binary files differ
diff --git a/framesequence/samples/FrameSequenceSamples/res/raw/animated_webp.webp b/framesequence/samples/FrameSequenceSamples/res/raw/animated_webp.webp
deleted file mode 100644
index 25c6a4d..0000000
--- a/framesequence/samples/FrameSequenceSamples/res/raw/animated_webp.webp
+++ /dev/null
Binary files differ
diff --git a/framesequence/samples/FrameSequenceSamples/res/values/strings.xml b/framesequence/samples/FrameSequenceSamples/res/values/strings.xml
deleted file mode 100644
index b9ace00..0000000
--- a/framesequence/samples/FrameSequenceSamples/res/values/strings.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <!-- NOTE: all strings should be marked as translatable=false,
-         since this sample app is for testing, and won't be shipped -->
-
-    <string name="app_name" translatable="false">FrameSequence Samples</string>
-    <string name="action_settings" translatable="false">Settings</string>
-
-    <string name="start" translatable="false">start</string>
-    <string name="stop" translatable="false">stop</string>
-    <string name="vis" translatable="false">vis</string>
-    <string name="invis" translatable="false">invis</string>
-
-    <string name="circle_mask" translatable="false">Toggle Circle Mask</string>
-
-</resources>
diff --git a/framesequence/samples/FrameSequenceSamples/res/values/styles.xml b/framesequence/samples/FrameSequenceSamples/res/values/styles.xml
deleted file mode 100644
index 737bdc3..0000000
--- a/framesequence/samples/FrameSequenceSamples/res/values/styles.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<resources>
-
-    <!-- Application theme. -->
-    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
-    </style>
-
-</resources>
diff --git a/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/FrameSequenceTest.java b/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/FrameSequenceTest.java
deleted file mode 100644
index 7f66ce1..0000000
--- a/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/FrameSequenceTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.framesequence.samples;
-
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.support.rastermill.FrameSequence;
-import android.support.rastermill.FrameSequenceDrawable;
-import android.view.View;
-import android.widget.Toast;
-
-import java.io.InputStream;
-import java.util.HashSet;
-
-public class FrameSequenceTest extends Activity {
-    FrameSequenceDrawable mDrawable;
-    int mResourceId;
-
-    // This provider is entirely unnecessary, just here to validate the acquire/release process
-    private class CheckingProvider implements FrameSequenceDrawable.BitmapProvider {
-        HashSet<Bitmap> mBitmaps = new HashSet<Bitmap>();
-        @Override
-        public Bitmap acquireBitmap(int minWidth, int minHeight) {
-            Bitmap bitmap =
-                    Bitmap.createBitmap(minWidth + 1, minHeight + 4, Bitmap.Config.ARGB_8888);
-            mBitmaps.add(bitmap);
-            return bitmap;
-        }
-
-        @Override
-        public void releaseBitmap(Bitmap bitmap) {
-            if (!mBitmaps.contains(bitmap)) throw new IllegalStateException();
-            mBitmaps.remove(bitmap);
-            bitmap.recycle();
-        }
-
-        public boolean isEmpty() {
-            return mBitmaps.isEmpty();
-        }
-    }
-
-    final CheckingProvider mProvider = new CheckingProvider();
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mResourceId = getIntent().getIntExtra("resourceId", R.raw.animated_gif);
-
-        setContentView(R.layout.basic_test_activity);
-        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mDrawable.start();
-            }
-        });
-        findViewById(R.id.stop).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mDrawable.stop();
-            }
-        });
-        findViewById(R.id.vis).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mDrawable.setVisible(true, true);
-            }
-        });
-        findViewById(R.id.invis).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mDrawable.setVisible(false, true);
-            }
-        });
-        findViewById(R.id.circle_mask).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mDrawable.setCircleMaskEnabled(!mDrawable.getCircleMaskEnabled());
-            }
-        });
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-
-        View drawableView = findViewById(R.id.drawableview);
-        InputStream is = getResources().openRawResource(mResourceId);
-
-        FrameSequence fs = FrameSequence.decodeStream(is);
-        mDrawable = new FrameSequenceDrawable(fs, mProvider);
-        mDrawable.setOnFinishedListener(new FrameSequenceDrawable.OnFinishedListener() {
-            @Override
-            public void onFinished(FrameSequenceDrawable drawable) {
-                Toast.makeText(getApplicationContext(),
-                        "The animation has finished", Toast.LENGTH_SHORT).show();
-            }
-        });
-        drawableView.setBackgroundDrawable(mDrawable);
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        View drawableView = findViewById(R.id.drawableview);
-
-        mDrawable.destroy();
-        if (!mProvider.isEmpty()) throw new IllegalStateException("All bitmaps not recycled");
-
-        mDrawable = null;
-        drawableView.setBackgroundDrawable(null);
-    }
-}
diff --git a/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/SamplesList.java b/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/SamplesList.java
deleted file mode 100644
index 36cc784..0000000
--- a/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/SamplesList.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.framesequence.samples;
-
-import android.app.ListActivity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.SimpleAdapter;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-
-public class SamplesList extends ListActivity {
-
-    static final String KEY_NAME = "name";
-    static final String KEY_CLASS = "clazz";
-    static final String KEY_RESOURCE = "res";
-
-    static Map<String,?> makeSample(String name, Class<?> activity, int resourceId) {
-        Map<String,Object> ret = new HashMap<String,Object>();
-        ret.put(KEY_NAME, name);
-        ret.put(KEY_CLASS, activity);
-        ret.put(KEY_RESOURCE, resourceId);
-        return ret;
-    }
-
-    static final ArrayList<Map<String,?>> SAMPLES = new ArrayList<>();
-    static {
-        SAMPLES.add(makeSample("GIF animation", FrameSequenceTest.class, R.raw.animated_gif));
-        SAMPLES.add(makeSample("WEBP animation", FrameSequenceTest.class, R.raw.animated_webp));
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setListAdapter(new SimpleAdapter(this, SAMPLES,
-                android.R.layout.simple_list_item_1, new String[] { KEY_NAME },
-                new int[] { android.R.id.text1 }));
-    }
-
-    @Override
-    protected void onListItemClick(ListView l, View v, int position, long id) {
-        Class<?> clazz = (Class<?>) SAMPLES.get(position).get(KEY_CLASS);
-        int resourceId = ((Integer) SAMPLES.get(position).get(KEY_RESOURCE)).intValue();
-
-        Intent intent = new Intent(this, clazz);
-        intent.putExtra("resourceId", resourceId);
-        startActivity(intent);
-    }
-
-}
diff --git a/framesequence/src/android/support/rastermill/FrameSequence.java b/framesequence/src/android/support/rastermill/FrameSequence.java
index 8ff241f..1af64d2 100644
--- a/framesequence/src/android/support/rastermill/FrameSequence.java
+++ b/framesequence/src/android/support/rastermill/FrameSequence.java
@@ -16,136 +16,42 @@
 
 package android.support.rastermill;
 
-import android.graphics.Bitmap;
 import java.nio.ByteBuffer;
 
 import java.io.InputStream;
 
+/**
+ * Entire class is a no-op, does nothing
+ */
+@Deprecated
 public class FrameSequence {
     static {
         System.loadLibrary("framesequence");
     }
 
-    private final long mNativeFrameSequence;
-    private final int mWidth;
-    private final int mHeight;
-    private final boolean mOpaque;
-    private final int mFrameCount;
-    private final int mDefaultLoopCount;
+    public int getWidth() { return 0; }
+    public int getHeight() { return 0; }
+    public boolean isOpaque() { return true; }
+    public int getFrameCount() { return 0; }
+    public int getDefaultLoopCount() { return 0; }
 
-    public int getWidth() { return mWidth; }
-    public int getHeight() { return mHeight; }
-    public boolean isOpaque() { return mOpaque; }
-    public int getFrameCount() { return mFrameCount; }
-    public int getDefaultLoopCount() { return mDefaultLoopCount; }
-
-    private static native FrameSequence nativeDecodeByteArray(byte[] data, int offset, int length);
-    private static native FrameSequence nativeDecodeStream(InputStream is, byte[] tempStorage);
-    private static native FrameSequence nativeDecodeByteBuffer(ByteBuffer buffer, int offset, int capacity);
-    private static native void nativeDestroyFrameSequence(long nativeFrameSequence);
-    private static native long nativeCreateState(long nativeFrameSequence);
-    private static native void nativeDestroyState(long nativeState);
-    private static native long nativeGetFrame(long nativeState, int frameNr,
-            Bitmap output, int previousFrameNr);
-
-    @SuppressWarnings("unused") // called by native
-    private FrameSequence(long nativeFrameSequence, int width, int height,
-                          boolean opaque, int frameCount, int defaultLoopCount) {
-        mNativeFrameSequence = nativeFrameSequence;
-        mWidth = width;
-        mHeight = height;
-        mOpaque = opaque;
-        mFrameCount = frameCount;
-        mDefaultLoopCount = defaultLoopCount;
+    @SuppressWarnings("unused")
+    private FrameSequence() {
     }
 
     public static FrameSequence decodeByteArray(byte[] data) {
-        return decodeByteArray(data, 0, data.length);
+        return null;
     }
 
     public static FrameSequence decodeByteArray(byte[] data, int offset, int length) {
-        if (data == null) throw new IllegalArgumentException();
-        if (offset < 0 || length < 0 || (offset + length > data.length)) {
-            throw new IllegalArgumentException("invalid offset/length parameters");
-        }
-        return nativeDecodeByteArray(data, offset, length);
+        return null;
     }
 
     public static FrameSequence decodeByteBuffer(ByteBuffer buffer) {
-        if (buffer == null) throw new IllegalArgumentException();
-        if (!buffer.isDirect()) {
-            if (buffer.hasArray()) {
-                byte[] byteArray = buffer.array();
-                return decodeByteArray(byteArray, buffer.position(), buffer.remaining());
-            } else {
-                throw new IllegalArgumentException("Cannot have non-direct ByteBuffer with no byte array");
-            }
-        }
-        return nativeDecodeByteBuffer(buffer, buffer.position(), buffer.remaining());
+        return null;
     }
 
     public static FrameSequence decodeStream(InputStream stream) {
-        if (stream == null) throw new IllegalArgumentException();
-        byte[] tempStorage = new byte[16 * 1024]; // TODO: use buffer pool
-        return nativeDecodeStream(stream, tempStorage);
-    }
-
-    State createState() {
-        if (mNativeFrameSequence == 0) {
-            throw new IllegalStateException("attempted to use incorrectly built FrameSequence");
-        }
-
-        long nativeState = nativeCreateState(mNativeFrameSequence);
-        if (nativeState == 0) {
-            return null;
-        }
-        return new State(nativeState);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            if (mNativeFrameSequence != 0) nativeDestroyFrameSequence(mNativeFrameSequence);
-        } finally {
-            super.finalize();
-        }
-    }
-
-    /**
-     * Playback state used when moving frames forward in a frame sequence.
-     *
-     * Note that this doesn't require contiguous frames to be rendered, it just stores
-     * information (in the case of gif, a recall buffer) that will be used to construct
-     * frames based upon data recorded before previousFrameNr.
-     *
-     * Note: {@link #destroy()} *must* be called before the object is GC'd to free native resources
-     *
-     * Note: State holds a native ref to its FrameSequence instance, so its FrameSequence should
-     * remain ref'd while it is in use
-     */
-    static class State {
-        private long mNativeState;
-
-        public State(long nativeState) {
-            mNativeState = nativeState;
-        }
-
-        public void destroy() {
-            if (mNativeState != 0) {
-                nativeDestroyState(mNativeState);
-                mNativeState = 0;
-            }
-        }
-
-        // TODO: consider adding alternate API for drawing into a SurfaceTexture
-        public long getFrame(int frameNr, Bitmap output, int previousFrameNr) {
-            if (output == null || output.getConfig() != Bitmap.Config.ARGB_8888) {
-                throw new IllegalArgumentException("Bitmap passed must be non-null and ARGB_8888");
-            }
-            if (mNativeState == 0) {
-                throw new IllegalStateException("attempted to draw destroyed FrameSequenceState");
-            }
-            return nativeGetFrame(mNativeState, frameNr, output, previousFrameNr);
-        }
+        return null;
     }
 }
diff --git a/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java b/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java
index d86df62..30e3a0c 100644
--- a/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java
+++ b/framesequence/src/android/support/rastermill/FrameSequenceDrawable.java
@@ -17,524 +17,116 @@
 package android.support.rastermill;
 
 import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
-import android.graphics.Paint;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Shader;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Process;
-import android.os.SystemClock;
-import android.util.Log;
 
+/**
+ * Entire class is a no-op, does nothing
+ */
+@Deprecated
 public class FrameSequenceDrawable extends Drawable implements Animatable, Runnable {
-    private static final String TAG = "FrameSequence";
-    /**
-     * These constants are chosen to imitate common browser behavior for WebP/GIF.
-     * If other decoders are added, this behavior should be moved into the WebP/GIF decoders.
-     *
-     * Note that 0 delay is undefined behavior in the GIF standard.
-     */
-    private static final long MIN_DELAY_MS = 20;
-    private static final long DEFAULT_DELAY_MS = 100;
-
-    private static final Object sLock = new Object();
-    private static HandlerThread sDecodingThread;
-    private static Handler sDecodingThreadHandler;
-    private static void initializeDecodingThread() {
-        synchronized (sLock) {
-            if (sDecodingThread != null) return;
-
-            sDecodingThread = new HandlerThread("FrameSequence decoding thread",
-                    Process.THREAD_PRIORITY_BACKGROUND);
-            sDecodingThread.start();
-            sDecodingThreadHandler = new Handler(sDecodingThread.getLooper());
-        }
-    }
 
     public static interface OnFinishedListener {
-        /**
-         * Called when a FrameSequenceDrawable has finished looping.
-         *
-         * Note that this is will not be called if the drawable is explicitly
-         * stopped, or marked invisible.
-         */
         public abstract void onFinished(FrameSequenceDrawable drawable);
     }
 
     public static interface BitmapProvider {
-        /**
-         * Called by FrameSequenceDrawable to aquire an 8888 Bitmap with minimum dimensions.
-         */
         public abstract Bitmap acquireBitmap(int minWidth, int minHeight);
 
-        /**
-         * Called by FrameSequenceDrawable to release a Bitmap it no longer needs. The Bitmap
-         * will no longer be used at all by the drawable, so it is safe to reuse elsewhere.
-         *
-         * This method may be called by FrameSequenceDrawable on any thread.
-         */
         public abstract void releaseBitmap(Bitmap bitmap);
     }
 
-    private static BitmapProvider sAllocatingBitmapProvider = new BitmapProvider() {
-        @Override
-        public Bitmap acquireBitmap(int minWidth, int minHeight) {
-            return Bitmap.createBitmap(minWidth, minHeight, Bitmap.Config.ARGB_8888);
-        }
-
-        @Override
-        public void releaseBitmap(Bitmap bitmap) {}
-    };
-
-    /**
-     * Register a callback to be invoked when a FrameSequenceDrawable finishes looping.
-     *
-     * @see #setLoopBehavior(int)
-     */
     public void setOnFinishedListener(OnFinishedListener onFinishedListener) {
-        mOnFinishedListener = onFinishedListener;
     }
 
-    /**
-     * Loop a finite number of times, which can be set using setLoopCount. Default to loop once.
-     */
     public static final int LOOP_FINITE = 1;
 
-    /**
-     * Loop continuously. The OnFinishedListener will never be called.
-     */
     public static final int LOOP_INF = 2;
 
-    /**
-     * Use loop count stored in source data, or LOOP_ONCE if not present.
-     */
     public static final int LOOP_DEFAULT = 3;
 
-    /**
-     * Loop only once.
-     *
-     * @deprecated Use LOOP_FINITE instead.
-     */
     @Deprecated
     public static final int LOOP_ONCE = LOOP_FINITE;
 
-    /**
-     * Define looping behavior of frame sequence.
-     *
-     * Must be one of LOOP_ONCE, LOOP_INF, LOOP_DEFAULT, or LOOP_FINITE.
-     */
     public void setLoopBehavior(int loopBehavior) {
-        mLoopBehavior = loopBehavior;
+
     }
 
-    /**
-     * Set the number of loops in LOOP_FINITE mode. The number must be a postive integer.
-     */
     public void setLoopCount(int loopCount) {
-        mLoopCount = loopCount;
-    }
 
-    private final FrameSequence mFrameSequence;
-    private final FrameSequence.State mFrameSequenceState;
-
-    private final Paint mPaint;
-    private BitmapShader mFrontBitmapShader;
-    private BitmapShader mBackBitmapShader;
-    private final Rect mSrcRect;
-    private boolean mCircleMaskEnabled;
-
-    //Protects the fields below
-    private final Object mLock = new Object();
-
-    private final BitmapProvider mBitmapProvider;
-    private boolean mDestroyed = false;
-    private Bitmap mFrontBitmap;
-    private Bitmap mBackBitmap;
-
-    private static final int STATE_SCHEDULED = 1;
-    private static final int STATE_DECODING = 2;
-    private static final int STATE_WAITING_TO_SWAP = 3;
-    private static final int STATE_READY_TO_SWAP = 4;
-
-    private int mState;
-    private int mCurrentLoop;
-    private int mLoopBehavior = LOOP_DEFAULT;
-    private int mLoopCount = 1;
-
-    private long mLastSwap;
-    private long mNextSwap;
-    private int mNextFrameToDecode;
-    private OnFinishedListener mOnFinishedListener;
-
-    private RectF mTempRectF = new RectF();
-
-    /**
-     * Runs on decoding thread, only modifies mBackBitmap's pixels
-     */
-    private Runnable mDecodeRunnable = new Runnable() {
-        @Override
-        public void run() {
-            int nextFrame;
-            Bitmap bitmap;
-            synchronized (mLock) {
-                if (mDestroyed) return;
-
-                nextFrame = mNextFrameToDecode;
-                if (nextFrame < 0) {
-                    return;
-                }
-                bitmap = mBackBitmap;
-                mState = STATE_DECODING;
-            }
-            int lastFrame = nextFrame - 2;
-            boolean exceptionDuringDecode = false;
-            long invalidateTimeMs = 0;
-            try {
-                invalidateTimeMs = mFrameSequenceState.getFrame(nextFrame, bitmap, lastFrame);
-            } catch(Exception e) {
-                // Exception during decode: continue, but delay next frame indefinitely.
-                Log.e(TAG, "exception during decode: " + e);
-                exceptionDuringDecode = true;
-            }
-
-            if (invalidateTimeMs < MIN_DELAY_MS) {
-                invalidateTimeMs = DEFAULT_DELAY_MS;
-            }
-
-            boolean schedule = false;
-            Bitmap bitmapToRelease = null;
-            synchronized (mLock) {
-                if (mDestroyed) {
-                    bitmapToRelease = mBackBitmap;
-                    mBackBitmap = null;
-                } else if (mNextFrameToDecode >= 0 && mState == STATE_DECODING) {
-                    schedule = true;
-                    mNextSwap = exceptionDuringDecode ? Long.MAX_VALUE : invalidateTimeMs + mLastSwap;
-                    mState = STATE_WAITING_TO_SWAP;
-                }
-            }
-            if (schedule) {
-                scheduleSelf(FrameSequenceDrawable.this, mNextSwap);
-            }
-            if (bitmapToRelease != null) {
-                // destroy the bitmap here, since there's no safe way to get back to
-                // drawable thread - drawable is likely detached, so schedule is noop.
-                mBitmapProvider.releaseBitmap(bitmapToRelease);
-            }
-        }
-    };
-
-    private Runnable mFinishedCallbackRunnable = new Runnable() {
-        @Override
-        public void run() {
-            synchronized (mLock) {
-                mNextFrameToDecode = -1;
-                mState = 0;
-            }
-            if (mOnFinishedListener != null) {
-                mOnFinishedListener.onFinished(FrameSequenceDrawable.this);
-            }
-        }
-    };
-
-    private static Bitmap acquireAndValidateBitmap(BitmapProvider bitmapProvider,
-            int minWidth, int minHeight) {
-        Bitmap bitmap = bitmapProvider.acquireBitmap(minWidth, minHeight);
-
-        if (bitmap.getWidth() < minWidth
-                || bitmap.getHeight() < minHeight
-                || bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
-            throw new IllegalArgumentException("Invalid bitmap provided");
-        }
-
-        return bitmap;
     }
 
     public FrameSequenceDrawable(FrameSequence frameSequence) {
-        this(frameSequence, sAllocatingBitmapProvider);
     }
 
     public FrameSequenceDrawable(FrameSequence frameSequence, BitmapProvider bitmapProvider) {
-        if (frameSequence == null || bitmapProvider == null) throw new IllegalArgumentException();
-
-        mFrameSequence = frameSequence;
-        mFrameSequenceState = frameSequence.createState();
-        final int width = frameSequence.getWidth();
-        final int height = frameSequence.getHeight();
-
-        mBitmapProvider = bitmapProvider;
-        mFrontBitmap = acquireAndValidateBitmap(bitmapProvider, width, height);
-        mBackBitmap = acquireAndValidateBitmap(bitmapProvider, width, height);
-        mSrcRect = new Rect(0, 0, width, height);
-        mPaint = new Paint();
-        mPaint.setFilterBitmap(true);
-
-        mFrontBitmapShader
-            = new BitmapShader(mFrontBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
-        mBackBitmapShader
-            = new BitmapShader(mBackBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
-
-        mLastSwap = 0;
-
-        mNextFrameToDecode = -1;
-        mFrameSequenceState.getFrame(0, mFrontBitmap, -1);
-        initializeDecodingThread();
     }
 
-    /**
-     * Pass true to mask the shape of the animated drawing content to a circle.
-     *
-     * <p> The masking circle will be the largest circle contained in the Drawable's bounds.
-     * Masking is done with BitmapShader, incurring minimal additional draw cost.
-     */
     public final void setCircleMaskEnabled(boolean circleMaskEnabled) {
-        if (mCircleMaskEnabled != circleMaskEnabled) {
-            mCircleMaskEnabled = circleMaskEnabled;
-            // Anti alias only necessary when using circular mask
-            mPaint.setAntiAlias(circleMaskEnabled);
-            invalidateSelf();
-        }
     }
 
     public final boolean getCircleMaskEnabled() {
-        return mCircleMaskEnabled;
-    }
-
-    private void checkDestroyedLocked() {
-        if (mDestroyed) {
-            throw new IllegalStateException("Cannot perform operation on recycled drawable");
-        }
+        return false;
     }
 
     public boolean isDestroyed() {
-        synchronized (mLock) {
-            return mDestroyed;
-        }
+        return true;
     }
 
-    /**
-     * Marks the drawable as permanently recycled (and thus unusable), and releases any owned
-     * Bitmaps drawable to its BitmapProvider, if attached.
-     *
-     * If no BitmapProvider is attached to the drawable, recycle() is called on the Bitmaps.
-     */
     public void destroy() {
-        if (mBitmapProvider == null) {
-            throw new IllegalStateException("BitmapProvider must be non-null");
-        }
-
-        Bitmap bitmapToReleaseA;
-        Bitmap bitmapToReleaseB = null;
-        synchronized (mLock) {
-            checkDestroyedLocked();
-
-            bitmapToReleaseA = mFrontBitmap;
-            mFrontBitmap = null;
-
-            if (mState != STATE_DECODING) {
-                bitmapToReleaseB = mBackBitmap;
-                mBackBitmap = null;
-            }
-
-            mDestroyed = true;
-        }
-
-        // For simplicity and safety, we don't destroy the state object here
-        mBitmapProvider.releaseBitmap(bitmapToReleaseA);
-        if (bitmapToReleaseB != null) {
-            mBitmapProvider.releaseBitmap(bitmapToReleaseB);
-        }
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            mFrameSequenceState.destroy();
-        } finally {
-            super.finalize();
-        }
     }
 
     @Override
     public void draw(Canvas canvas) {
-        synchronized (mLock) {
-            checkDestroyedLocked();
-            if (mState == STATE_WAITING_TO_SWAP) {
-                // may have failed to schedule mark ready runnable,
-                // so go ahead and swap if swapping is due
-                if (mNextSwap - SystemClock.uptimeMillis() <= 0) {
-                    mState = STATE_READY_TO_SWAP;
-                }
-            }
-
-            if (isRunning() && mState == STATE_READY_TO_SWAP) {
-                // Because draw has occurred, the view system is guaranteed to no longer hold a
-                // reference to the old mFrontBitmap, so we now use it to produce the next frame
-                Bitmap tmp = mBackBitmap;
-                mBackBitmap = mFrontBitmap;
-                mFrontBitmap = tmp;
-
-                BitmapShader tmpShader = mBackBitmapShader;
-                mBackBitmapShader = mFrontBitmapShader;
-                mFrontBitmapShader = tmpShader;
-
-                mLastSwap = SystemClock.uptimeMillis();
-
-                boolean continueLooping = true;
-                if (mNextFrameToDecode == mFrameSequence.getFrameCount() - 1) {
-                    mCurrentLoop++;
-                    if ((mLoopBehavior == LOOP_FINITE && mCurrentLoop == mLoopCount) ||
-                            (mLoopBehavior == LOOP_DEFAULT && mCurrentLoop == mFrameSequence.getDefaultLoopCount())) {
-                        continueLooping = false;
-                    }
-                }
-
-                if (continueLooping) {
-                    scheduleDecodeLocked();
-                } else {
-                    scheduleSelf(mFinishedCallbackRunnable, 0);
-                }
-            }
-        }
-
-        if (mCircleMaskEnabled) {
-            final Rect bounds = getBounds();
-            final int bitmapWidth = getIntrinsicWidth();
-            final int bitmapHeight = getIntrinsicHeight();
-            final float scaleX = 1.0f * bounds.width() / bitmapWidth;
-            final float scaleY = 1.0f * bounds.height() / bitmapHeight;
-
-            canvas.save();
-            // scale and translate to account for bounds, so we can operate in intrinsic
-            // width/height (so it's valid to use an unscaled bitmap shader)
-            canvas.translate(bounds.left, bounds.top);
-            canvas.scale(scaleX, scaleY);
-
-            final float unscaledCircleDiameter = Math.min(bounds.width(), bounds.height());
-            final float scaledDiameterX = unscaledCircleDiameter / scaleX;
-            final float scaledDiameterY = unscaledCircleDiameter / scaleY;
-
-            // Want to draw a circle, but we have to compensate for canvas scale
-            mTempRectF.set(
-                    (bitmapWidth - scaledDiameterX) / 2.0f,
-                    (bitmapHeight - scaledDiameterY) / 2.0f,
-                    (bitmapWidth + scaledDiameterX) / 2.0f,
-                    (bitmapHeight + scaledDiameterY) / 2.0f);
-            mPaint.setShader(mFrontBitmapShader);
-            canvas.drawOval(mTempRectF, mPaint);
-            canvas.restore();
-        } else {
-            mPaint.setShader(null);
-            canvas.drawBitmap(mFrontBitmap, mSrcRect, getBounds(), mPaint);
-        }
-    }
-
-    private void scheduleDecodeLocked() {
-        mState = STATE_SCHEDULED;
-        mNextFrameToDecode = (mNextFrameToDecode + 1) % mFrameSequence.getFrameCount();
-        sDecodingThreadHandler.post(mDecodeRunnable);
+        canvas.drawColor(Color.MAGENTA);
     }
 
     @Override
     public void run() {
-        // set ready to swap as necessary
-        boolean invalidate = false;
-        synchronized (mLock) {
-            if (mNextFrameToDecode >= 0 && mState == STATE_WAITING_TO_SWAP) {
-                mState = STATE_READY_TO_SWAP;
-                invalidate = true;
-            }
-        }
-        if (invalidate) {
-            invalidateSelf();
-        }
     }
 
     @Override
     public void start() {
-        if (!isRunning()) {
-            synchronized (mLock) {
-                checkDestroyedLocked();
-                if (mState == STATE_SCHEDULED) return; // already scheduled
-                mCurrentLoop = 0;
-                scheduleDecodeLocked();
-            }
-        }
     }
 
     @Override
     public void stop() {
-        if (isRunning()) {
-            unscheduleSelf(this);
-        }
     }
 
     @Override
     public boolean isRunning() {
-        synchronized (mLock) {
-            return mNextFrameToDecode > -1 && !mDestroyed;
-        }
+        return false;
     }
 
     @Override
-    public void unscheduleSelf(Runnable what) {
-        synchronized (mLock) {
-            mNextFrameToDecode = -1;
-            mState = 0;
-        }
-        super.unscheduleSelf(what);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        boolean changed = super.setVisible(visible, restart);
-
-        if (!visible) {
-            stop();
-        } else if (restart || changed) {
-            stop();
-            start();
-        }
-
-        return changed;
-    }
-
-    // drawing properties
-
-    @Override
     public void setFilterBitmap(boolean filter) {
-        mPaint.setFilterBitmap(filter);
     }
 
     @Override
     public void setAlpha(int alpha) {
-        mPaint.setAlpha(alpha);
     }
 
     @Override
     public void setColorFilter(ColorFilter colorFilter) {
-        mPaint.setColorFilter(colorFilter);
+
     }
 
     @Override
     public int getIntrinsicWidth() {
-        return mFrameSequence.getWidth();
+        return 0;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mFrameSequence.getHeight();
+        return 0;
     }
 
     @Override
     public int getOpacity() {
-        return mFrameSequence.isOpaque() ? PixelFormat.OPAQUE : PixelFormat.TRANSPARENT;
+        return PixelFormat.OPAQUE;
     }
 }