1 /* 2 * Copyright (C) 2006 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 17 package android.widget; 18 19 import android.annotation.IntRange; 20 import android.compat.annotation.UnsupportedAppUsage; 21 import android.content.Context; 22 import android.content.res.TypedArray; 23 import android.os.Build; 24 import android.os.Message; 25 import android.util.AttributeSet; 26 import android.util.Log; 27 import android.view.inspector.InspectableProperty; 28 import android.widget.RemoteViews.RemoteView; 29 30 /** 31 * Simple {@link ViewAnimator} that will animate between two or more views 32 * that have been added to it. Only one child is shown at a time. If 33 * requested, can automatically flip between each child at a regular interval. 34 * 35 * @attr ref android.R.styleable#ViewFlipper_flipInterval 36 * @attr ref android.R.styleable#ViewFlipper_autoStart 37 */ 38 @RemoteView 39 public class ViewFlipper extends ViewAnimator { 40 private static final String TAG = "ViewFlipper"; 41 private static final boolean LOGD = false; 42 43 private static final int DEFAULT_INTERVAL = 3000; 44 45 private int mFlipInterval = DEFAULT_INTERVAL; 46 private boolean mAutoStart = false; 47 48 private boolean mRunning = false; 49 private boolean mStarted = false; 50 private boolean mVisible = false; 51 ViewFlipper(Context context)52 public ViewFlipper(Context context) { 53 super(context); 54 } 55 ViewFlipper(Context context, AttributeSet attrs)56 public ViewFlipper(Context context, AttributeSet attrs) { 57 super(context, attrs); 58 59 TypedArray a = context.obtainStyledAttributes(attrs, 60 com.android.internal.R.styleable.ViewFlipper); 61 mFlipInterval = a.getInt( 62 com.android.internal.R.styleable.ViewFlipper_flipInterval, DEFAULT_INTERVAL); 63 mAutoStart = a.getBoolean( 64 com.android.internal.R.styleable.ViewFlipper_autoStart, false); 65 a.recycle(); 66 } 67 68 @Override onAttachedToWindow()69 protected void onAttachedToWindow() { 70 super.onAttachedToWindow(); 71 72 if (mAutoStart) { 73 // Automatically start when requested 74 startFlipping(); 75 } 76 } 77 78 @Override onDetachedFromWindow()79 protected void onDetachedFromWindow() { 80 super.onDetachedFromWindow(); 81 mVisible = false; 82 updateRunning(); 83 } 84 85 @Override onWindowVisibilityChanged(int visibility)86 protected void onWindowVisibilityChanged(int visibility) { 87 super.onWindowVisibilityChanged(visibility); 88 mVisible = visibility == VISIBLE; 89 updateRunning(false); 90 } 91 92 /** 93 * How long to wait before flipping to the next view 94 * 95 * @param milliseconds 96 * time in milliseconds 97 */ 98 @android.view.RemotableViewMethod setFlipInterval(@ntRangefrom = 0) int milliseconds)99 public void setFlipInterval(@IntRange(from = 0) int milliseconds) { 100 mFlipInterval = milliseconds; 101 } 102 103 /** 104 * Get the delay before flipping to the next view. 105 * 106 * @return delay time in milliseconds 107 */ 108 @InspectableProperty 109 @IntRange(from = 0) getFlipInterval()110 public int getFlipInterval() { 111 return mFlipInterval; 112 } 113 114 /** 115 * Start a timer to cycle through child views 116 */ startFlipping()117 public void startFlipping() { 118 mStarted = true; 119 updateRunning(); 120 } 121 122 /** 123 * No more flips 124 */ stopFlipping()125 public void stopFlipping() { 126 mStarted = false; 127 updateRunning(); 128 } 129 130 @Override getAccessibilityClassName()131 public CharSequence getAccessibilityClassName() { 132 return ViewFlipper.class.getName(); 133 } 134 135 /** 136 * Internal method to start or stop dispatching flip {@link Message} based 137 * on {@link #mRunning} and {@link #mVisible} state. 138 */ updateRunning()139 private void updateRunning() { 140 updateRunning(true); 141 } 142 143 /** 144 * Internal method to start or stop dispatching flip {@link Message} based 145 * on {@link #mRunning} and {@link #mVisible} state. 146 * 147 * @param flipNow Determines whether or not to execute the animation now, in 148 * addition to queuing future flips. If omitted, defaults to 149 * true. 150 */ 151 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) updateRunning(boolean flipNow)152 private void updateRunning(boolean flipNow) { 153 boolean running = mVisible && mStarted; 154 if (running != mRunning) { 155 if (running) { 156 showOnly(mWhichChild, flipNow); 157 postDelayed(mFlipRunnable, mFlipInterval); 158 } else { 159 removeCallbacks(mFlipRunnable); 160 } 161 mRunning = running; 162 } 163 if (LOGD) { 164 Log.d(TAG, "updateRunning() mVisible=" + mVisible + ", mStarted=" + mStarted 165 + ", mRunning=" + mRunning); 166 } 167 } 168 169 /** 170 * Returns true if the child views are flipping. 171 */ 172 @InspectableProperty(hasAttributeId = false) isFlipping()173 public boolean isFlipping() { 174 return mStarted; 175 } 176 177 /** 178 * Set if this view automatically calls {@link #startFlipping()} when it 179 * becomes attached to a window. 180 */ setAutoStart(boolean autoStart)181 public void setAutoStart(boolean autoStart) { 182 mAutoStart = autoStart; 183 } 184 185 /** 186 * Returns true if this view automatically calls {@link #startFlipping()} 187 * when it becomes attached to a window. 188 */ 189 @InspectableProperty isAutoStart()190 public boolean isAutoStart() { 191 return mAutoStart; 192 } 193 194 private final Runnable mFlipRunnable = new Runnable() { 195 @Override 196 public void run() { 197 if (mRunning) { 198 showNext(); 199 postDelayed(mFlipRunnable, mFlipInterval); 200 } 201 } 202 }; 203 } 204