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.Context;
     20 import android.content.Intent;
     21 import android.content.IntentFilter;
     22 import android.content.BroadcastReceiver;
     23 import android.content.res.Resources;
     24 import android.content.res.TypedArray;
     25 import android.graphics.Canvas;
     26 import android.graphics.drawable.Drawable;
     27 import android.os.Handler;
     28 import android.text.format.DateUtils;
     29 import android.text.format.Time;
     30 import android.util.AttributeSet;
     31 import android.view.View;
     32 import android.widget.RemoteViews.RemoteView;
     33 
     34 import java.util.TimeZone;
     35 
     36 /**
     37  * This widget display an analogic clock with two hands for hours and
     38  * minutes.
     39  *
     40  * @attr ref android.R.styleable#AnalogClock_dial
     41  * @attr ref android.R.styleable#AnalogClock_hand_hour
     42  * @attr ref android.R.styleable#AnalogClock_hand_minute
     43  * @deprecated This widget is no longer supported.
     44  */
     45 @RemoteView
     46 @Deprecated
     47 public class AnalogClock extends View {
     48     private Time mCalendar;
     49 
     50     private Drawable mHourHand;
     51     private Drawable mMinuteHand;
     52     private Drawable mDial;
     53 
     54     private int mDialWidth;
     55     private int mDialHeight;
     56 
     57     private boolean mAttached;
     58 
     59     private float mMinutes;
     60     private float mHour;
     61     private boolean mChanged;
     62 
     63     public AnalogClock(Context context) {
     64         this(context, null);
     65     }
     66 
     67     public AnalogClock(Context context, AttributeSet attrs) {
     68         this(context, attrs, 0);
     69     }
     70 
     71     public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
     72         this(context, attrs, defStyleAttr, 0);
     73     }
     74 
     75     public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     76         super(context, attrs, defStyleAttr, defStyleRes);
     77 
     78         final Resources r = context.getResources();
     79         final TypedArray a = context.obtainStyledAttributes(
     80                 attrs, com.android.internal.R.styleable.AnalogClock, defStyleAttr, defStyleRes);
     81 
     82         mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial);
     83         if (mDial == null) {
     84             mDial = context.getDrawable(com.android.internal.R.drawable.clock_dial);
     85         }
     86 
     87         mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour);
     88         if (mHourHand == null) {
     89             mHourHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_hour);
     90         }
     91 
     92         mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute);
     93         if (mMinuteHand == null) {
     94             mMinuteHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_minute);
     95         }
     96 
     97         mCalendar = new Time();
     98 
     99         mDialWidth = mDial.getIntrinsicWidth();
    100         mDialHeight = mDial.getIntrinsicHeight();
    101     }
    102 
    103     @Override
    104     protected void onAttachedToWindow() {
    105         super.onAttachedToWindow();
    106 
    107         if (!mAttached) {
    108             mAttached = true;
    109             IntentFilter filter = new IntentFilter();
    110 
    111             filter.addAction(Intent.ACTION_TIME_TICK);
    112             filter.addAction(Intent.ACTION_TIME_CHANGED);
    113             filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
    114 
    115             // OK, this is gross but needed. This class is supported by the
    116             // remote views machanism and as a part of that the remote views
    117             // can be inflated by a context for another user without the app
    118             // having interact users permission - just for loading resources.
    119             // For exmaple, when adding widgets from a user profile to the
    120             // home screen. Therefore, we register the receiver as the current
    121             // user not the one the context is for.
    122             getContext().registerReceiverAsUser(mIntentReceiver,
    123                     android.os.Process.myUserHandle(), filter, null, getHandler());
    124         }
    125 
    126         // NOTE: It's safe to do these after registering the receiver since the receiver always runs
    127         // in the main thread, therefore the receiver can't run before this method returns.
    128 
    129         // The time zone may have changed while the receiver wasn't registered, so update the Time
    130         mCalendar = new Time();
    131 
    132         // Make sure we update to the current time
    133         onTimeChanged();
    134     }
    135 
    136     @Override
    137     protected void onDetachedFromWindow() {
    138         super.onDetachedFromWindow();
    139         if (mAttached) {
    140             getContext().unregisterReceiver(mIntentReceiver);
    141             mAttached = false;
    142         }
    143     }
    144 
    145     @Override
    146     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    147 
    148         int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    149         int widthSize =  MeasureSpec.getSize(widthMeasureSpec);
    150         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    151         int heightSize =  MeasureSpec.getSize(heightMeasureSpec);
    152 
    153         float hScale = 1.0f;
    154         float vScale = 1.0f;
    155 
    156         if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
    157             hScale = (float) widthSize / (float) mDialWidth;
    158         }
    159 
    160         if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
    161             vScale = (float )heightSize / (float) mDialHeight;
    162         }
    163 
    164         float scale = Math.min(hScale, vScale);
    165 
    166         setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
    167                 resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
    168     }
    169 
    170     @Override
    171     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    172         super.onSizeChanged(w, h, oldw, oldh);
    173         mChanged = true;
    174     }
    175 
    176     @Override
    177     protected void onDraw(Canvas canvas) {
    178         super.onDraw(canvas);
    179 
    180         boolean changed = mChanged;
    181         if (changed) {
    182             mChanged = false;
    183         }
    184 
    185         int availableWidth = mRight - mLeft;
    186         int availableHeight = mBottom - mTop;
    187 
    188         int x = availableWidth / 2;
    189         int y = availableHeight / 2;
    190 
    191         final Drawable dial = mDial;
    192         int w = dial.getIntrinsicWidth();
    193         int h = dial.getIntrinsicHeight();
    194 
    195         boolean scaled = false;
    196 
    197         if (availableWidth < w || availableHeight < h) {
    198             scaled = true;
    199             float scale = Math.min((float) availableWidth / (float) w,
    200                                    (float) availableHeight / (float) h);
    201             canvas.save();
    202             canvas.scale(scale, scale, x, y);
    203         }
    204 
    205         if (changed) {
    206             dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
    207         }
    208         dial.draw(canvas);
    209 
    210         canvas.save();
    211         canvas.rotate(mHour / 12.0f * 360.0f, x, y);
    212         final Drawable hourHand = mHourHand;
    213         if (changed) {
    214             w = hourHand.getIntrinsicWidth();
    215             h = hourHand.getIntrinsicHeight();
    216             hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
    217         }
    218         hourHand.draw(canvas);
    219         canvas.restore();
    220 
    221         canvas.save();
    222         canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);
    223 
    224         final Drawable minuteHand = mMinuteHand;
    225         if (changed) {
    226             w = minuteHand.getIntrinsicWidth();
    227             h = minuteHand.getIntrinsicHeight();
    228             minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
    229         }
    230         minuteHand.draw(canvas);
    231         canvas.restore();
    232 
    233         if (scaled) {
    234             canvas.restore();
    235         }
    236     }
    237 
    238     private void onTimeChanged() {
    239         mCalendar.setToNow();
    240 
    241         int hour = mCalendar.hour;
    242         int minute = mCalendar.minute;
    243         int second = mCalendar.second;
    244 
    245         mMinutes = minute + second / 60.0f;
    246         mHour = hour + mMinutes / 60.0f;
    247         mChanged = true;
    248 
    249         updateContentDescription(mCalendar);
    250     }
    251 
    252     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    253         @Override
    254         public void onReceive(Context context, Intent intent) {
    255             if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
    256                 String tz = intent.getStringExtra("time-zone");
    257                 mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
    258             }
    259 
    260             onTimeChanged();
    261 
    262             invalidate();
    263         }
    264     };
    265 
    266     private void updateContentDescription(Time time) {
    267         final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR;
    268         String contentDescription = DateUtils.formatDateTime(mContext,
    269                 time.toMillis(false), flags);
    270         setContentDescription(contentDescription);
    271     }
    272 }
    273