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);