blob: e5f9c24136d1968375b930ff263b8427aea9792f [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.deskclock;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import androidx.appcompat.widget.AppCompatImageView;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageView;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
/**
* This widget display an analog clock with two hands for hours and minutes.
*/
public class AnalogClock extends FrameLayout {
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
final String tz = intent.getStringExtra(Intent.EXTRA_TIMEZONE);
mTime = Calendar.getInstance(TimeZone.getTimeZone(tz));
}
onTimeChanged();
}
};
private final Runnable mClockTick = new Runnable() {
@Override
public void run() {
onTimeChanged();
if (mEnableSeconds) {
final long now = System.currentTimeMillis();
final long delay = SECOND_IN_MILLIS - now % SECOND_IN_MILLIS;
postDelayed(this, delay);
}
}
};
private final ImageView mHourHand;
private final ImageView mMinuteHand;
private final ImageView mSecondHand;
private Calendar mTime;
private String mDescFormat;
private TimeZone mTimeZone;
private boolean mEnableSeconds = true;
public AnalogClock(Context context) {
this(context, null /* attrs */);
}
public AnalogClock(Context context, AttributeSet attrs) {
this(context, attrs, 0 /* defStyleAttr */);
}
public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mTime = Calendar.getInstance();
mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
// Must call mutate on these instances, otherwise the drawables will blur, because they're
// sharing their size characteristics with the (smaller) world cities analog clocks.
final ImageView dial = new AppCompatImageView(context);
dial.setImageResource(R.drawable.clock_analog_dial);
dial.getDrawable().mutate();
addView(dial);
mHourHand = new AppCompatImageView(context);
mHourHand.setImageResource(R.drawable.clock_analog_hour);
mHourHand.getDrawable().mutate();
addView(mHourHand);
mMinuteHand = new AppCompatImageView(context);
mMinuteHand.setImageResource(R.drawable.clock_analog_minute);
mMinuteHand.getDrawable().mutate();
addView(mMinuteHand);
mSecondHand = new AppCompatImageView(context);
mSecondHand.setImageResource(R.drawable.clock_analog_second);
mSecondHand.getDrawable().mutate();
addView(mSecondHand);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter);
// Refresh the calendar instance since the time zone may have changed while the receiver
// wasn't registered.
mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
onTimeChanged();
// Tick every second.
if (mEnableSeconds) {
mClockTick.run();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getContext().unregisterReceiver(mIntentReceiver);
removeCallbacks(mClockTick);
}
private void onTimeChanged() {
mTime.setTimeInMillis(System.currentTimeMillis());
final float hourAngle = mTime.get(Calendar.HOUR) * 30f;
mHourHand.setRotation(hourAngle);
final float minuteAngle = mTime.get(Calendar.MINUTE) * 6f;
mMinuteHand.setRotation(minuteAngle);
if (mEnableSeconds) {
final float secondAngle = mTime.get(Calendar.SECOND) * 6f;
mSecondHand.setRotation(secondAngle);
}
setContentDescription(DateFormat.format(mDescFormat, mTime));
invalidate();
}
public void setTimeZone(String id) {
mTimeZone = TimeZone.getTimeZone(id);
mTime.setTimeZone(mTimeZone);
onTimeChanged();
}
public void enableSeconds(boolean enable) {
mEnableSeconds = enable;
if (mEnableSeconds) {
mSecondHand.setVisibility(VISIBLE);
mClockTick.run();
} else {
mSecondHand.setVisibility(GONE);
}
}
}