• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.res.TypedArray;
24 import android.os.Handler;
25 import android.os.Message;
26 import android.util.AttributeSet;
27 import android.util.Log;
28 import android.view.accessibility.AccessibilityEvent;
29 import android.view.accessibility.AccessibilityNodeInfo;
30 import android.widget.RemoteViews.RemoteView;
31 
32 /**
33  * Simple {@link ViewAnimator} that will animate between two or more views
34  * that have been added to it.  Only one child is shown at a time.  If
35  * requested, can automatically flip between each child at a regular interval.
36  *
37  * @attr ref android.R.styleable#ViewFlipper_flipInterval
38  * @attr ref android.R.styleable#ViewFlipper_autoStart
39  */
40 @RemoteView
41 public class ViewFlipper extends ViewAnimator {
42     private static final String TAG = "ViewFlipper";
43     private static final boolean LOGD = false;
44 
45     private static final int DEFAULT_INTERVAL = 3000;
46 
47     private int mFlipInterval = DEFAULT_INTERVAL;
48     private boolean mAutoStart = false;
49 
50     private boolean mRunning = false;
51     private boolean mStarted = false;
52     private boolean mVisible = false;
53     private boolean mUserPresent = true;
54 
ViewFlipper(Context context)55     public ViewFlipper(Context context) {
56         super(context);
57     }
58 
ViewFlipper(Context context, AttributeSet attrs)59     public ViewFlipper(Context context, AttributeSet attrs) {
60         super(context, attrs);
61 
62         TypedArray a = context.obtainStyledAttributes(attrs,
63                 com.android.internal.R.styleable.ViewFlipper);
64         mFlipInterval = a.getInt(
65                 com.android.internal.R.styleable.ViewFlipper_flipInterval, DEFAULT_INTERVAL);
66         mAutoStart = a.getBoolean(
67                 com.android.internal.R.styleable.ViewFlipper_autoStart, false);
68         a.recycle();
69     }
70 
71     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
72         @Override
73         public void onReceive(Context context, Intent intent) {
74             final String action = intent.getAction();
75             if (Intent.ACTION_SCREEN_OFF.equals(action)) {
76                 mUserPresent = false;
77                 updateRunning();
78             } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
79                 mUserPresent = true;
80                 updateRunning(false);
81             }
82         }
83     };
84 
85     @Override
onAttachedToWindow()86     protected void onAttachedToWindow() {
87         super.onAttachedToWindow();
88 
89         // Listen for broadcasts related to user-presence
90         final IntentFilter filter = new IntentFilter();
91         filter.addAction(Intent.ACTION_SCREEN_OFF);
92         filter.addAction(Intent.ACTION_USER_PRESENT);
93         getContext().registerReceiver(mReceiver, filter);
94 
95         if (mAutoStart) {
96             // Automatically start when requested
97             startFlipping();
98         }
99     }
100 
101     @Override
onDetachedFromWindow()102     protected void onDetachedFromWindow() {
103         super.onDetachedFromWindow();
104         mVisible = false;
105 
106         getContext().unregisterReceiver(mReceiver);
107         updateRunning();
108     }
109 
110     @Override
onWindowVisibilityChanged(int visibility)111     protected void onWindowVisibilityChanged(int visibility) {
112         super.onWindowVisibilityChanged(visibility);
113         mVisible = visibility == VISIBLE;
114         updateRunning(false);
115     }
116 
117     /**
118      * How long to wait before flipping to the next view
119      *
120      * @param milliseconds
121      *            time in milliseconds
122      */
123     @android.view.RemotableViewMethod
setFlipInterval(int milliseconds)124     public void setFlipInterval(int milliseconds) {
125         mFlipInterval = milliseconds;
126     }
127 
128     /**
129      * Start a timer to cycle through child views
130      */
startFlipping()131     public void startFlipping() {
132         mStarted = true;
133         updateRunning();
134     }
135 
136     /**
137      * No more flips
138      */
stopFlipping()139     public void stopFlipping() {
140         mStarted = false;
141         updateRunning();
142     }
143 
144     @Override
onInitializeAccessibilityEvent(AccessibilityEvent event)145     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
146         super.onInitializeAccessibilityEvent(event);
147         event.setClassName(ViewFlipper.class.getName());
148     }
149 
150     @Override
onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info)151     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
152         super.onInitializeAccessibilityNodeInfo(info);
153         info.setClassName(ViewFlipper.class.getName());
154     }
155 
156     /**
157      * Internal method to start or stop dispatching flip {@link Message} based
158      * on {@link #mRunning} and {@link #mVisible} state.
159      */
updateRunning()160     private void updateRunning() {
161         updateRunning(true);
162     }
163 
164     /**
165      * Internal method to start or stop dispatching flip {@link Message} based
166      * on {@link #mRunning} and {@link #mVisible} state.
167      *
168      * @param flipNow Determines whether or not to execute the animation now, in
169      *            addition to queuing future flips. If omitted, defaults to
170      *            true.
171      */
updateRunning(boolean flipNow)172     private void updateRunning(boolean flipNow) {
173         boolean running = mVisible && mStarted && mUserPresent;
174         if (running != mRunning) {
175             if (running) {
176                 showOnly(mWhichChild, flipNow);
177                 Message msg = mHandler.obtainMessage(FLIP_MSG);
178                 mHandler.sendMessageDelayed(msg, mFlipInterval);
179             } else {
180                 mHandler.removeMessages(FLIP_MSG);
181             }
182             mRunning = running;
183         }
184         if (LOGD) {
185             Log.d(TAG, "updateRunning() mVisible=" + mVisible + ", mStarted=" + mStarted
186                     + ", mUserPresent=" + mUserPresent + ", mRunning=" + mRunning);
187         }
188     }
189 
190     /**
191      * Returns true if the child views are flipping.
192      */
isFlipping()193     public boolean isFlipping() {
194         return mStarted;
195     }
196 
197     /**
198      * Set if this view automatically calls {@link #startFlipping()} when it
199      * becomes attached to a window.
200      */
setAutoStart(boolean autoStart)201     public void setAutoStart(boolean autoStart) {
202         mAutoStart = autoStart;
203     }
204 
205     /**
206      * Returns true if this view automatically calls {@link #startFlipping()}
207      * when it becomes attached to a window.
208      */
isAutoStart()209     public boolean isAutoStart() {
210         return mAutoStart;
211     }
212 
213     private final int FLIP_MSG = 1;
214 
215     private final Handler mHandler = new Handler() {
216         @Override
217         public void handleMessage(Message msg) {
218             if (msg.what == FLIP_MSG) {
219                 if (mRunning) {
220                     showNext();
221                     msg = obtainMessage(FLIP_MSG);
222                     sendMessageDelayed(msg, mFlipInterval);
223                 }
224             }
225         }
226     };
227 }
228