blob: cf1f5542f493c726eb9d1e13d25b3e5781ceea4e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.widget;
18
Jeff Sharkey1162fd72009-11-04 17:58:08 -080019import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.Context;
Jeff Sharkey1162fd72009-11-04 17:58:08 -080021import android.content.Intent;
22import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.res.TypedArray;
Svetoslav976e8bd2014-07-16 15:12:03 -070024import android.os.*;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.util.AttributeSet;
Jeff Sharkey1162fd72009-11-04 17:58:08 -080026import android.util.Log;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -080027import android.view.accessibility.AccessibilityEvent;
28import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.widget.RemoteViews.RemoteView;
30
31/**
32 * Simple {@link ViewAnimator} that will animate between two or more views
33 * that have been added to it. Only one child is shown at a time. If
34 * requested, can automatically flip between each child at a regular interval.
35 *
36 * @attr ref android.R.styleable#ViewFlipper_flipInterval
Jeff Sharkey1162fd72009-11-04 17:58:08 -080037 * @attr ref android.R.styleable#ViewFlipper_autoStart
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038 */
Jeff Sharkey1162fd72009-11-04 17:58:08 -080039@RemoteView
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040public class ViewFlipper extends ViewAnimator {
Jeff Sharkey1162fd72009-11-04 17:58:08 -080041 private static final String TAG = "ViewFlipper";
Jeff Sharkey2b95c242010-02-08 17:40:30 -080042 private static final boolean LOGD = false;
Jeff Sharkey1162fd72009-11-04 17:58:08 -080043
44 private static final int DEFAULT_INTERVAL = 3000;
45
46 private int mFlipInterval = DEFAULT_INTERVAL;
47 private boolean mAutoStart = false;
48
49 private boolean mRunning = false;
50 private boolean mStarted = false;
51 private boolean mVisible = false;
52 private boolean mUserPresent = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54 public ViewFlipper(Context context) {
55 super(context);
56 }
57
58 public ViewFlipper(Context context, AttributeSet attrs) {
59 super(context, attrs);
60
61 TypedArray a = context.obtainStyledAttributes(attrs,
62 com.android.internal.R.styleable.ViewFlipper);
Jeff Sharkey1162fd72009-11-04 17:58:08 -080063 mFlipInterval = a.getInt(
64 com.android.internal.R.styleable.ViewFlipper_flipInterval, DEFAULT_INTERVAL);
65 mAutoStart = a.getBoolean(
66 com.android.internal.R.styleable.ViewFlipper_autoStart, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 a.recycle();
68 }
69
Jeff Sharkey1162fd72009-11-04 17:58:08 -080070 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
71 @Override
72 public void onReceive(Context context, Intent intent) {
73 final String action = intent.getAction();
74 if (Intent.ACTION_SCREEN_OFF.equals(action)) {
75 mUserPresent = false;
76 updateRunning();
77 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
78 mUserPresent = true;
Mason Tangf70036b2010-06-14 17:47:24 -070079 updateRunning(false);
Jeff Sharkey1162fd72009-11-04 17:58:08 -080080 }
81 }
82 };
83
84 @Override
85 protected void onAttachedToWindow() {
86 super.onAttachedToWindow();
87
88 // Listen for broadcasts related to user-presence
89 final IntentFilter filter = new IntentFilter();
90 filter.addAction(Intent.ACTION_SCREEN_OFF);
91 filter.addAction(Intent.ACTION_USER_PRESENT);
Svetoslav976e8bd2014-07-16 15:12:03 -070092
93 // OK, this is gross but needed. This class is supported by the
94 // remote views machanism and as a part of that the remote views
95 // can be inflated by a context for another user without the app
96 // having interact users permission - just for loading resources.
97 // For exmaple, when adding widgets from a user profile to the
98 // home screen. Therefore, we register the receiver as the current
99 // user not the one the context is for.
100 getContext().registerReceiverAsUser(mReceiver, android.os.Process.myUserHandle(),
101 filter, null, mHandler);
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800102
103 if (mAutoStart) {
104 // Automatically start when requested
105 startFlipping();
106 }
107 }
108
109 @Override
110 protected void onDetachedFromWindow() {
111 super.onDetachedFromWindow();
112 mVisible = false;
113
114 getContext().unregisterReceiver(mReceiver);
115 updateRunning();
116 }
117
118 @Override
119 protected void onWindowVisibilityChanged(int visibility) {
120 super.onWindowVisibilityChanged(visibility);
121 mVisible = visibility == VISIBLE;
Mason Tangf70036b2010-06-14 17:47:24 -0700122 updateRunning(false);
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800123 }
124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 /**
126 * How long to wait before flipping to the next view
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800127 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 * @param milliseconds
129 * time in milliseconds
130 */
131 @android.view.RemotableViewMethod
132 public void setFlipInterval(int milliseconds) {
133 mFlipInterval = milliseconds;
134 }
135
136 /**
137 * Start a timer to cycle through child views
138 */
139 public void startFlipping() {
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800140 mStarted = true;
141 updateRunning();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 }
143
144 /**
145 * No more flips
146 */
147 public void stopFlipping() {
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800148 mStarted = false;
149 updateRunning();
150 }
151
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800152 @Override
153 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
154 super.onInitializeAccessibilityEvent(event);
155 event.setClassName(ViewFlipper.class.getName());
156 }
157
158 @Override
159 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
160 super.onInitializeAccessibilityNodeInfo(info);
161 info.setClassName(ViewFlipper.class.getName());
162 }
163
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800164 /**
165 * Internal method to start or stop dispatching flip {@link Message} based
166 * on {@link #mRunning} and {@link #mVisible} state.
167 */
168 private void updateRunning() {
Mason Tangf70036b2010-06-14 17:47:24 -0700169 updateRunning(true);
170 }
171
172 /**
173 * Internal method to start or stop dispatching flip {@link Message} based
174 * on {@link #mRunning} and {@link #mVisible} state.
175 *
176 * @param flipNow Determines whether or not to execute the animation now, in
177 * addition to queuing future flips. If omitted, defaults to
178 * true.
179 */
180 private void updateRunning(boolean flipNow) {
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800181 boolean running = mVisible && mStarted && mUserPresent;
182 if (running != mRunning) {
183 if (running) {
Mason Tangf70036b2010-06-14 17:47:24 -0700184 showOnly(mWhichChild, flipNow);
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800185 Message msg = mHandler.obtainMessage(FLIP_MSG);
186 mHandler.sendMessageDelayed(msg, mFlipInterval);
187 } else {
188 mHandler.removeMessages(FLIP_MSG);
189 }
190 mRunning = running;
191 }
192 if (LOGD) {
193 Log.d(TAG, "updateRunning() mVisible=" + mVisible + ", mStarted=" + mStarted
194 + ", mUserPresent=" + mUserPresent + ", mRunning=" + mRunning);
195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 }
197
198 /**
199 * Returns true if the child views are flipping.
200 */
201 public boolean isFlipping() {
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800202 return mStarted;
203 }
204
205 /**
206 * Set if this view automatically calls {@link #startFlipping()} when it
207 * becomes attached to a window.
208 */
209 public void setAutoStart(boolean autoStart) {
210 mAutoStart = autoStart;
211 }
212
213 /**
214 * Returns true if this view automatically calls {@link #startFlipping()}
215 * when it becomes attached to a window.
216 */
217 public boolean isAutoStart() {
218 return mAutoStart;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 }
220
221 private final int FLIP_MSG = 1;
222
223 private final Handler mHandler = new Handler() {
224 @Override
225 public void handleMessage(Message msg) {
226 if (msg.what == FLIP_MSG) {
Jeff Sharkey1162fd72009-11-04 17:58:08 -0800227 if (mRunning) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 showNext();
229 msg = obtainMessage(FLIP_MSG);
230 sendMessageDelayed(msg, mFlipInterval);
231 }
232 }
233 }
234 };
235}