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