Add an new internal DrawableContainer to handle animation scale == 0 case.

This will help ProgressBar to show something meaningful when animation scale is 0.
b/30877925

Change-Id: Ieb2e78712999d2e3f3a2a234bc605b4821ae41c0
diff --git a/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
new file mode 100644
index 0000000..1133899
--- /dev/null
+++ b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2016 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.internal.graphics.drawable;
+
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * An internal DrawableContainer class, used to draw different things depending on animation scale.
+ * i.e: animation scale can be 0 in battery saver mode.
+ * This class contains 2 drawable, one is animatable, the other is static. When animation scale is
+ * not 0, the animatable drawable will the drawn. Otherwise, the static drawable will be drawn.
+ * <p>This class implements Animatable since ProgressBar can pick this up similarly as an
+ * AnimatedVectorDrawable.
+ * <p>It can be defined in an XML file with the {@code <AnimationScaleListDrawable>}
+ * element.
+ */
+public class AnimationScaleListDrawable extends DrawableContainer implements Animatable {
+    private static final String TAG = "AnimationScaleListDrawable";
+    private AnimatedScaleListState mAnimatedScaleListState;
+    private boolean mMutated;
+
+    public AnimationScaleListDrawable() {
+        this(null, null);
+    }
+
+    private AnimationScaleListDrawable(@Nullable AnimatedScaleListState state,
+            @Nullable Resources res) {
+        // Every scale list drawable has its own constant state.
+        final AnimatedScaleListState newState = new AnimatedScaleListState(state, this, res);
+        setConstantState(newState);
+        onStateChange(getState());
+    }
+
+    /**
+     * Set the current drawable according to the animation scale. If scale is 0, then pick the
+     * static drawable, otherwise, pick the animatable drawable.
+     */
+    @Override
+    protected boolean onStateChange(int[] stateSet) {
+        final boolean changed = super.onStateChange(stateSet);
+        int idx = mAnimatedScaleListState.getCurrentDrawableIndexBasedOnScale();
+        return selectDrawable(idx) || changed;
+    }
+
+
+    @Override
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final TypedArray a = obtainAttributes(r, theme, attrs,
+                R.styleable.AnimationScaleListDrawable);
+        updateDensity(r);
+        a.recycle();
+
+        inflateChildElements(r, parser, attrs, theme);
+
+        onStateChange(getState());
+    }
+
+    /**
+     * Inflates child elements from XML.
+     */
+    private void inflateChildElements(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final AnimatedScaleListState state = mAnimatedScaleListState;
+        final int innerDepth = parser.getDepth() + 1;
+        int type;
+        int depth;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth
+                || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (depth > innerDepth || !parser.getName().equals("item")) {
+                continue;
+            }
+
+            // Either pick up the android:drawable attribute.
+            final TypedArray a = obtainAttributes(r, theme, attrs,
+                    R.styleable.AnimationScaleListDrawableItem);
+            Drawable dr = a.getDrawable(R.styleable.AnimationScaleListDrawableItem_drawable);
+            a.recycle();
+
+            // Or parse the child element under <item>.
+            if (dr == null) {
+                while ((type = parser.next()) == XmlPullParser.TEXT) {
+                }
+                if (type != XmlPullParser.START_TAG) {
+                    throw new XmlPullParserException(
+                            parser.getPositionDescription()
+                                    + ": <item> tag requires a 'drawable' attribute or "
+                                    + "child tag defining a drawable");
+                }
+                dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
+            }
+
+            state.addDrawable(dr);
+        }
+    }
+
+    @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mAnimatedScaleListState.mutate();
+            mMutated = true;
+        }
+        return this;
+    }
+
+    @Override
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
+    @Override
+    public void start() {
+        Drawable dr = getCurrent();
+        if (dr != null && dr instanceof Animatable) {
+            ((Animatable) dr).start();
+        }
+    }
+
+    @Override
+    public void stop() {
+        Drawable dr = getCurrent();
+        if (dr != null && dr instanceof Animatable) {
+            ((Animatable) dr).stop();
+        }
+    }
+
+    @Override
+    public boolean isRunning() {
+        boolean result = false;
+        Drawable dr = getCurrent();
+        if (dr != null && dr instanceof Animatable) {
+            result = ((Animatable) dr).isRunning();
+        }
+        return result;
+    }
+
+    static class AnimatedScaleListState extends DrawableContainerState {
+        int[] mThemeAttrs = null;
+        // The index of the last static drawable.
+        int mStaticDrawableIndex = -1;
+        // The index of the last animatable drawable.
+        int mAnimatableDrawableIndex = -1;
+
+        AnimatedScaleListState(AnimatedScaleListState orig, AnimationScaleListDrawable owner,
+                Resources res) {
+            super(orig, owner, res);
+
+            if (orig != null) {
+                // Perform a shallow copy and rely on mutate() to deep-copy.
+                mThemeAttrs = orig.mThemeAttrs;
+
+                mStaticDrawableIndex = orig.mStaticDrawableIndex;
+                mAnimatableDrawableIndex = orig.mAnimatableDrawableIndex;
+            }
+
+        }
+
+        void mutate() {
+            mThemeAttrs = mThemeAttrs != null ? mThemeAttrs.clone() : null;
+        }
+
+        /**
+         * Add the drawable into the container.
+         * This class only keep track one animatable drawable, and one static. If there are multiple
+         * defined in the XML, then pick the last one.
+         */
+        int addDrawable(Drawable drawable) {
+            final int pos = addChild(drawable);
+            if (drawable instanceof Animatable) {
+                mAnimatableDrawableIndex = pos;
+            } else {
+                mStaticDrawableIndex = pos;
+            }
+            return pos;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return new AnimationScaleListDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimationScaleListDrawable(this, res);
+        }
+
+        @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || super.canApplyTheme();
+        }
+
+        public int getCurrentDrawableIndexBasedOnScale() {
+            if (ValueAnimator.getDurationScale() == 0) {
+                return mStaticDrawableIndex;
+            }
+            return mAnimatableDrawableIndex;
+        }
+    }
+
+    @Override
+    public void applyTheme(@NonNull Theme theme) {
+        super.applyTheme(theme);
+
+        onStateChange(getState());
+    }
+
+    @Override
+    protected void setConstantState(@NonNull DrawableContainerState state) {
+        super.setConstantState(state);
+
+        if (state instanceof AnimatedScaleListState) {
+            mAnimatedScaleListState = (AnimatedScaleListState) state;
+        }
+    }
+}
+
diff --git a/core/res/res/drawable/ic_refresh.xml b/core/res/res/drawable/ic_refresh.xml
index 1f67168..1297407 100644
--- a/core/res/res/drawable/ic_refresh.xml
+++ b/core/res/res/drawable/ic_refresh.xml
@@ -21,7 +21,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
-    <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/progress_indeterminate_anim_large_material.xml b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
new file mode 100644
index 0000000..560ec5af
--- /dev/null
+++ b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 android:drawable="@drawable/vector_drawable_progress_bar_large" >
+    <target
+            android:name="progressBar"
+            android:animation="@anim/progress_indeterminate_material" />
+
+    <target
+            android:name="root"
+            android:animation="@anim/progress_indeterminate_rotation_material" />
+</animated-vector>
+
diff --git a/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
new file mode 100644
index 0000000..fbea22f
--- /dev/null
+++ b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
+
+    <target
+        android:name="progressBar"
+        android:animation="@anim/progress_indeterminate_material" />
+
+    <target
+        android:name="root"
+        android:animation="@anim/progress_indeterminate_rotation_material" />
+
+</animated-vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/progress_large_material.xml b/core/res/res/drawable/progress_large_material.xml
index 526f914..ee82e35 100644
--- a/core/res/res/drawable/progress_large_material.xml
+++ b/core/res/res/drawable/progress_large_material.xml
@@ -13,16 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_bar_large" >
-
-    <target
-        android:name="progressBar"
-        android:animation="@anim/progress_indeterminate_material" />
-
-    <target
-        android:name="root"
-        android:animation="@anim/progress_indeterminate_rotation_material" />
-
-</animated-vector>
+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/progress_static_material" />
+    <item android:drawable="@drawable/progress_indeterminate_anim_large_material" />
+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
diff --git a/core/res/res/drawable/progress_medium_material.xml b/core/res/res/drawable/progress_medium_material.xml
index cc35816..5c92600 100644
--- a/core/res/res/drawable/progress_medium_material.xml
+++ b/core/res/res/drawable/progress_medium_material.xml
@@ -13,15 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
-
-    <target
-        android:name="progressBar"
-        android:animation="@anim/progress_indeterminate_material" />
-
-    <target
-        android:name="root"
-        android:animation="@anim/progress_indeterminate_rotation_material" />
-
-</animated-vector>
\ No newline at end of file
+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/progress_static_material" />
+    <item android:drawable="@drawable/progress_indeterminate_anim_medium_material" />
+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
diff --git a/core/res/res/drawable/progress_small_material.xml b/core/res/res/drawable/progress_small_material.xml
index c6e4380..cec9d95 100644
--- a/core/res/res/drawable/progress_small_material.xml
+++ b/core/res/res/drawable/progress_small_material.xml
@@ -13,16 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_bar_small" >
-
-    <target
-        android:name="progressBar"
-        android:animation="@anim/progress_indeterminate_material" />
-
-    <target
-        android:name="root"
-        android:animation="@anim/progress_indeterminate_rotation_material" />
-
-</animated-vector>
+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/progress_static_material" />
+    <item>
+        <animated-vector android:drawable="@drawable/vector_drawable_progress_bar_small" >
+            <target
+                    android:name="progressBar"
+                    android:animation="@anim/progress_indeterminate_material" />
+            <target
+                    android:name="root"
+                    android:animation="@anim/progress_indeterminate_rotation_material" />
+        </animated-vector>
+    </item>
+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
diff --git a/core/res/res/drawable/progress_static_material.xml b/core/res/res/drawable/progress_static_material.xml
new file mode 100644
index 0000000..b078fa9
--- /dev/null
+++ b/core/res/res/drawable/progress_static_material.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        >
+    <path
+        android:fillColor="?attr/colorControlActivated"
+        android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
+</vector>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0c08564..f273d27 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5312,6 +5312,21 @@
         <attr name="alpha" />
     </declare-styleable>
 
+    <!-- Drawable used to render according to the animation scale. Esp. when it is 0 due to battery
+         saver mode. It should contain one animatable drawable and one static drawable.
+         @hide -->
+    <declare-styleable name="AnimationScaleListDrawable">
+    </declare-styleable>
+
+    <!-- Attributes that can be assigned to a AnimationScaleListDrawable item.
+         @hide -->
+    <declare-styleable name="AnimationScaleListDrawableItem">
+        <!-- Reference to a drawable resource to use for the state. If not
+             given, the drawable must be defined by the first child tag. -->
+        <attr name="drawable" />
+    </declare-styleable>
+
+
     <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
     <declare-styleable name="GradientDrawable">
         <!-- Indicates whether the drawable should intially be visible. -->
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 7f3a437..3aca867 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1422,9 +1422,10 @@
     /**
      * Obtains styled attributes from the theme, if available, or unstyled
      * resources if the theme is null.
+     * @hide
      */
-    static @NonNull TypedArray obtainAttributes(@NonNull Resources res, @Nullable Theme theme,
-            @NonNull AttributeSet set, @NonNull int[] attrs) {
+    protected static @NonNull TypedArray obtainAttributes(@NonNull Resources res,
+            @Nullable Theme theme, @NonNull AttributeSet set, @NonNull int[] attrs) {
         if (theme == null) {
             return res.obtainAttributes(set, attrs);
         }
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index cc7f5c7..c7a3c75 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -27,8 +27,8 @@
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
@@ -601,8 +601,9 @@
      * during inflation.
      *
      * @param res the resources used to inflate density-dependent values
+     * @hide
      */
-    final void updateDensity(Resources res) {
+    protected final void updateDensity(Resources res) {
         mDrawableContainerState.updateDensity(res);
     }
 
@@ -711,7 +712,10 @@
         boolean mHasTintList;
         boolean mHasTintMode;
 
-        DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
+        /**
+         * @hide
+         */
+        protected DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
             mSourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null);