Home | History | Annotate | Download | only in widget
      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.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     private boolean mUserPresent = true;
     52 
     53     public ViewFlipper(Context context) {
     54         super(context);
     55     }
     56 
     57     public ViewFlipper(Context context, AttributeSet attrs) {
     58         super(context, attrs);
     59 
     60         TypedArray a = context.obtainStyledAttributes(attrs,
     61                 com.android.internal.R.styleable.ViewFlipper);
     62         mFlipInterval = a.getInt(
     63                 com.android.internal.R.styleable.ViewFlipper_flipInterval, DEFAULT_INTERVAL);
     64         mAutoStart = a.getBoolean(
     65                 com.android.internal.R.styleable.ViewFlipper_autoStart, false);
     66         a.recycle();
     67     }
     68 
     69     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
     70         @Override
     71         public void onReceive(Context context, Intent intent) {
     72             final String action = intent.getAction();
     73             if (Intent.ACTION_SCREEN_OFF.equals(action)) {
     74                 mUserPresent = false;
     75                 updateRunning();
     76             } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
     77                 mUserPresent = true;
     78                 updateRunning();
     79             }
     80         }
     81     };
     82 
     83     @Override
     84     protected void onAttachedToWindow() {
     85         super.onAttachedToWindow();
     86 
     87         // Listen for broadcasts related to user-presence
     88         final IntentFilter filter = new IntentFilter();
     89         filter.addAction(Intent.ACTION_SCREEN_OFF);
     90         filter.addAction(Intent.ACTION_USER_PRESENT);
     91         getContext().registerReceiver(mReceiver, filter);
     92 
     93         if (mAutoStart) {
     94             // Automatically start when requested
     95             startFlipping();
     96         }
     97     }
     98 
     99     @Override
    100     protected void onDetachedFromWindow() {
    101         super.onDetachedFromWindow();
    102         mVisible = false;
    103 
    104         getContext().unregisterReceiver(mReceiver);
    105         updateRunning();
    106     }
    107 
    108     @Override
    109     protected void onWindowVisibilityChanged(int visibility) {
    110         super.onWindowVisibilityChanged(visibility);
    111         mVisible = visibility == VISIBLE;
    112         updateRunning();
    113     }
    114 
    115     /**
    116      * How long to wait before flipping to the next view
    117      *
    118      * @param milliseconds
    119      *            time in milliseconds
    120      */
    121     @android.view.RemotableViewMethod
    122     public void setFlipInterval(int milliseconds) {
    123         mFlipInterval = milliseconds;
    124     }
    125 
    126     /**
    127      * Start a timer to cycle through child views
    128      */
    129     public void startFlipping() {
    130         mStarted = true;
    131         updateRunning();
    132     }
    133 
    134     /**
    135      * No more flips
    136      */
    137     public void stopFlipping() {
    138         mStarted = false;
    139         updateRunning();
    140     }
    141 
    142     /**
    143      * Internal method to start or stop dispatching flip {@link Message} based
    144      * on {@link #mRunning} and {@link #mVisible} state.
    145      */
    146     private void updateRunning() {
    147         boolean running = mVisible && mStarted && mUserPresent;
    148         if (running != mRunning) {
    149             if (running) {
    150                 showOnly(mWhichChild);
    151                 Message msg = mHandler.obtainMessage(FLIP_MSG);
    152                 mHandler.sendMessageDelayed(msg, mFlipInterval);
    153             } else {
    154                 mHandler.removeMessages(FLIP_MSG);
    155             }
    156             mRunning = running;
    157         }
    158         if (LOGD) {
    159             Log.d(TAG, "updateRunning() mVisible=" + mVisible + ", mStarted=" + mStarted
    160                     + ", mUserPresent=" + mUserPresent + ", mRunning=" + mRunning);
    161         }
    162     }
    163 
    164     /**
    165      * Returns true if the child views are flipping.
    166      */
    167     public boolean isFlipping() {
    168         return mStarted;
    169     }
    170 
    171     /**
    172      * Set if this view automatically calls {@link #startFlipping()} when it
    173      * becomes attached to a window.
    174      */
    175     public void setAutoStart(boolean autoStart) {
    176         mAutoStart = autoStart;
    177     }
    178 
    179     /**
    180      * Returns true if this view automatically calls {@link #startFlipping()}
    181      * when it becomes attached to a window.
    182      */
    183     public boolean isAutoStart() {
    184         return mAutoStart;
    185     }
    186 
    187     private final int FLIP_MSG = 1;
    188 
    189     private final Handler mHandler = new Handler() {
    190         @Override
    191         public void handleMessage(Message msg) {
    192             if (msg.what == FLIP_MSG) {
    193                 if (mRunning) {
    194                     showNext();
    195                     msg = obtainMessage(FLIP_MSG);
    196                     sendMessageDelayed(msg, mFlipInterval);
    197                 }
    198             }
    199         }
    200     };
    201 }
    202