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