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