• 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.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 
AnalogClock(Context context)63     public AnalogClock(Context context) {
64         this(context, null);
65     }
66 
AnalogClock(Context context, AttributeSet attrs)67     public AnalogClock(Context context, AttributeSet attrs) {
68         this(context, attrs, 0);
69     }
70 
AnalogClock(Context context, AttributeSet attrs, int defStyleAttr)71     public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
72         this(context, attrs, defStyleAttr, 0);
73     }
74 
AnalogClock(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)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
onAttachedToWindow()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
onDetachedFromWindow()137     protected void onDetachedFromWindow() {
138         super.onDetachedFromWindow();
139         if (mAttached) {
140             getContext().unregisterReceiver(mIntentReceiver);
141             mAttached = false;
142         }
143     }
144 
145     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)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
onSizeChanged(int w, int h, int oldw, int oldh)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
onDraw(Canvas canvas)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 
onTimeChanged()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 
updateContentDescription(Time time)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