/graphics/java/android/graphics/drawable/TransitionDrawable.java

https://github.com/integralnd/android_frameworks_base · Java · 246 lines · 133 code · 29 blank · 84 comment · 10 complexity · 8b586c3ebe4dfe450c18ffcae4dcdb2a MD5 · raw file

  1. /*
  2. * Copyright (C) 2008 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package android.graphics.drawable;
  17. import android.graphics.Canvas;
  18. import android.os.SystemClock;
  19. /**
  20. * An extension of LayerDrawables that is intended to cross-fade between
  21. * the first and second layer. To start the transition, call {@link #startTransition(int)}. To
  22. * display just the first layer, call {@link #resetTransition()}.
  23. * <p>
  24. * It can be defined in an XML file with the <code>&lt;transition></code> element.
  25. * Each Drawable in the transition is defined in a nested <code>&lt;item></code>.
  26. * </p>
  27. * @attr ref android.R.styleable#LayerDrawableItem_left
  28. * @attr ref android.R.styleable#LayerDrawableItem_top
  29. * @attr ref android.R.styleable#LayerDrawableItem_right
  30. * @attr ref android.R.styleable#LayerDrawableItem_bottom
  31. * @attr ref android.R.styleable#LayerDrawableItem_drawable
  32. * @attr ref android.R.styleable#LayerDrawableItem_id
  33. *
  34. */
  35. public class TransitionDrawable extends LayerDrawable implements Drawable.Callback {
  36. /**
  37. * A transition is about to start.
  38. */
  39. private static final int TRANSITION_STARTING = 0;
  40. /**
  41. * The transition has started and the animation is in progress
  42. */
  43. private static final int TRANSITION_RUNNING = 1;
  44. /**
  45. * No transition will be applied
  46. */
  47. private static final int TRANSITION_NONE = 2;
  48. /**
  49. * The current state of the transition. One of {@link #TRANSITION_STARTING},
  50. * {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE}
  51. */
  52. private int mTransitionState = TRANSITION_NONE;
  53. private boolean mReverse;
  54. private long mStartTimeMillis;
  55. private int mFrom;
  56. private int mTo;
  57. private int mDuration;
  58. private int mOriginalDuration;
  59. private int mAlpha = 0;
  60. private boolean mCrossFade;
  61. /**
  62. * Create a new transition drawable with the specified list of layers. At least
  63. * 2 layers are required for this drawable to work properly.
  64. */
  65. public TransitionDrawable(Drawable[] layers) {
  66. this(new TransitionState(null, null), layers);
  67. }
  68. /**
  69. * Create a new transition drawable with no layer. To work correctly, at least 2
  70. * layers must be added to this drawable.
  71. *
  72. * @see #TransitionDrawable(Drawable[])
  73. */
  74. TransitionDrawable() {
  75. this(new TransitionState(null, null));
  76. }
  77. private TransitionDrawable(TransitionState state) {
  78. super(state);
  79. }
  80. private TransitionDrawable(TransitionState state, Drawable[] layers) {
  81. super(layers, state);
  82. }
  83. @Override
  84. LayerState createConstantState(LayerState state) {
  85. return new TransitionState((TransitionState) state, this);
  86. }
  87. /**
  88. * Begin the second layer on top of the first layer.
  89. *
  90. * @param durationMillis The length of the transition in milliseconds
  91. */
  92. public void startTransition(int durationMillis) {
  93. mFrom = 0;
  94. mTo = 255;
  95. mAlpha = 0;
  96. mDuration = mOriginalDuration = durationMillis;
  97. mReverse = false;
  98. mTransitionState = TRANSITION_STARTING;
  99. invalidateSelf();
  100. }
  101. /**
  102. * Show only the first layer.
  103. */
  104. public void resetTransition() {
  105. mAlpha = 0;
  106. mTransitionState = TRANSITION_NONE;
  107. invalidateSelf();
  108. }
  109. /**
  110. * Reverses the transition, picking up where the transition currently is.
  111. * If the transition is not currently running, this will start the transition
  112. * with the specified duration. If the transition is already running, the last
  113. * known duration will be used.
  114. *
  115. * @param duration The duration to use if no transition is running.
  116. */
  117. public void reverseTransition(int duration) {
  118. final long time = SystemClock.uptimeMillis();
  119. // Animation is over
  120. if (time - mStartTimeMillis > mDuration) {
  121. if (mAlpha == 0) {
  122. mFrom = 0;
  123. mTo = 255;
  124. mAlpha = 0;
  125. mReverse = false;
  126. } else {
  127. mFrom = 255;
  128. mTo = 0;
  129. mAlpha = 255;
  130. mReverse = true;
  131. }
  132. mDuration = mOriginalDuration = duration;
  133. mTransitionState = TRANSITION_STARTING;
  134. invalidateSelf();
  135. return;
  136. }
  137. mReverse = !mReverse;
  138. mFrom = mAlpha;
  139. mTo = mReverse ? 0 : 255;
  140. mDuration = (int) (mReverse ? time - mStartTimeMillis :
  141. mOriginalDuration - (time - mStartTimeMillis));
  142. mTransitionState = TRANSITION_STARTING;
  143. }
  144. @Override
  145. public void draw(Canvas canvas) {
  146. boolean done = true;
  147. switch (mTransitionState) {
  148. case TRANSITION_STARTING:
  149. mStartTimeMillis = SystemClock.uptimeMillis();
  150. done = false;
  151. mTransitionState = TRANSITION_RUNNING;
  152. break;
  153. case TRANSITION_RUNNING:
  154. if (mStartTimeMillis >= 0) {
  155. float normalized = (float)
  156. (SystemClock.uptimeMillis() - mStartTimeMillis) / mDuration;
  157. done = normalized >= 1.0f;
  158. normalized = Math.min(normalized, 1.0f);
  159. mAlpha = (int) (mFrom + (mTo - mFrom) * normalized);
  160. }
  161. break;
  162. }
  163. final int alpha = mAlpha;
  164. final boolean crossFade = mCrossFade;
  165. final ChildDrawable[] array = mLayerState.mChildren;
  166. Drawable d;
  167. d = array[0].mDrawable;
  168. if (crossFade) {
  169. d.setAlpha(255 - alpha);
  170. }
  171. d.draw(canvas);
  172. if (crossFade) {
  173. d.setAlpha(0xFF);
  174. }
  175. if (alpha > 0) {
  176. d = array[1].mDrawable;
  177. d.setAlpha(alpha);
  178. d.draw(canvas);
  179. d.setAlpha(0xFF);
  180. }
  181. if (!done) {
  182. invalidateSelf();
  183. }
  184. }
  185. /**
  186. * Enables or disables the cross fade of the drawables. When cross fade
  187. * is disabled, the first drawable is always drawn opaque. With cross
  188. * fade enabled, the first drawable is drawn with the opposite alpha of
  189. * the second drawable.
  190. *
  191. * @param enabled True to enable cross fading, false otherwise.
  192. */
  193. public void setCrossFadeEnabled(boolean enabled) {
  194. mCrossFade = enabled;
  195. }
  196. /**
  197. * Indicates whether the cross fade is enabled for this transition.
  198. *
  199. * @return True if cross fading is enabled, false otherwise.
  200. */
  201. public boolean isCrossFadeEnabled() {
  202. return mCrossFade;
  203. }
  204. static class TransitionState extends LayerState {
  205. TransitionState(TransitionState orig, TransitionDrawable owner) {
  206. super(orig, owner);
  207. }
  208. @Override
  209. public Drawable newDrawable() {
  210. return new TransitionDrawable(this);
  211. }
  212. @Override
  213. public int getChangingConfigurations() {
  214. return mChangingConfigurations;
  215. }
  216. }
  217. }