content: /*
   * Copyright (C) 2006 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 android.widget;
  
  import android.annotation.UnsupportedAppUsage;
  import android.content.BroadcastReceiver;
  import android.content.Context;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.content.res.Resources;
  import android.content.res.TypedArray;
  import android.graphics.Canvas;
  import android.graphics.drawable.Drawable;
  import android.text.format.DateUtils;
  import android.text.format.Time;
  import android.util.AttributeSet;
  import android.view.View;
  import android.widget.RemoteViews.RemoteView;
  
  import java.util.TimeZone;
  
  /**
   * This widget display an analogic clock with two hands for hours and
   * minutes.
   *
   * @attr ref android.R.styleable#AnalogClock_dial
   * @attr ref android.R.styleable#AnalogClock_hand_hour
   * @attr ref android.R.styleable#AnalogClock_hand_minute
   * @deprecated This widget is no longer supported.
   */
  @RemoteView
  @Deprecated
  public class AnalogClock extends View {
      private Time mCalendar;
  
      @UnsupportedAppUsage
      private Drawable mHourHand;
      @UnsupportedAppUsage
      private Drawable mMinuteHand;
      @UnsupportedAppUsage
      private Drawable mDial;
  
      private int mDialWidth;
      private int mDialHeight;
  
      private boolean mAttached;
  
      private float mMinutes;
      private float mHour;
      private boolean mChanged;
  
      public AnalogClock(Context context) {
          this(context, null);
      }
  
      public AnalogClock(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
          this(context, attrs, defStyleAttr, 0);
      }
  
      public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
          super(context, attrs, defStyleAttr, defStyleRes);
  
          final Resources r = context.getResources();
          final TypedArray a = context.obtainStyledAttributes(
                  attrs, com.android.internal.R.styleable.AnalogClock, defStyleAttr, defStyleRes);
          saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AnalogClock,
                  attrs, a, defStyleAttr, defStyleRes);
  
          mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial);
          if (mDial == null) {
              mDial = context.getDrawable(com.android.internal.R.drawable.clock_dial);
          }
  
          mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour);
          if (mHourHand == null) {
              mHourHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_hour);
          }
  
          mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute);
          if (mMinuteHand == null) {
              mMinuteHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_minute);
          }
  
          mCalendar = new Time();
  
          mDialWidth = mDial.getIntrinsicWidth();
          mDialHeight = mDial.getIntrinsicHeight();
      }
  
      @Override
      protected void onAttachedToWindow() {
          super.onAttachedToWindow();
  
          if (!mAttached) {
              mAttached = true;
              IntentFilter filter = new IntentFilter();
  
              filter.addAction(Intent.ACTION_TIME_TICK);
              filter.addAction(Intent.ACTION_TIME_CHANGED);
              filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
  
              // OK, this is gross but needed. This class is supported by the
              // remote views machanism and as a part of that the remote views
              // can be inflated by a context for another user without the app
              // having interact users permission - just for loading resources.
              // For exmaple, when adding widgets from a user profile to the
              // home screen. Therefore, we register the receiver as the current
              // user not the one the context is for.
              getContext().registerReceiverAsUser(mIntentReceiver,
                      android.os.Process.myUserHandle(), filter, null, getHandler());
          }
  
          // NOTE: It's safe to do these after registering the receiver since the receiver always runs
          // in the main thread, therefore the receiver can't run before this method returns.
  
          // The time zone may have changed while the receiver wasn't registered, so update the Time
          mCalendar = new Time();
  
          // Make sure we update to the current time
          onTimeChanged();
      }
  
      @Override
      protected void onDetachedFromWindow() {
          super.onDetachedFromWindow();
          if (mAttached) {
              getContext().unregisterReceiver(mIntentReceiver);
              mAttached = false;
          }
      }
  
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  
          int widthMode = MeasureSpec.getMode(widthMeasureSpec);
          int widthSize =  MeasureSpec.getSize(widthMeasureSpec);
          int heightMode = MeasureSpec.getMode(heightMeasureSpec);
          int heightSize =  MeasureSpec.getSize(heightMeasureSpec);
  
          float hScale = 1.0f;
          float vScale = 1.0f;
  
          if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
              hScale = (float) widthSize / (float) mDialWidth;
          }
  
          if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
              vScale = (float )heightSize / (float) mDialHeight;
          }
  
          float scale = Math.min(hScale, vScale);
  
          setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
                  resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
      }
  
      @Override
      protected void onSizeChanged(int w, int h, int oldw, int oldh) {
          super.onSizeChanged(w, h, oldw, oldh);
          mChanged = true;
      }
  
      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
  
          boolean changed = mChanged;
          if (changed) {
              mChanged = false;
          }
  
          int availableWidth = mRight - mLeft;
          int availableHeight = mBottom - mTop;
  
          int x = availableWidth / 2;
          int y = availableHeight / 2;
  
          final Drawable dial = mDial;
          int w = dial.getIntrinsicWidth();
          int h = dial.getIntrinsicHeight();
  
          boolean scaled = false;
  
          if (availableWidth < w || availableHeight < h) {
              scaled = true;
              float scale = Math.min((float) availableWidth / (float) w,
                                     (float) availableHeight / (float) h);
              canvas.save();
              canvas.scale(scale, scale, x, y);
          }
  
          if (changed) {
              dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
          }
          dial.draw(canvas);
  
          canvas.save();
          canvas.rotate(mHour / 12.0f * 360.0f, x, y);
          final Drawable hourHand = mHourHand;
          if (changed) {
              w = hourHand.getIntrinsicWidth();
              h = hourHand.getIntrinsicHeight();
              hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
          }
          hourHand.draw(canvas);
          canvas.restore();
  
          canvas.save();
          canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);
  
          final Drawable minuteHand = mMinuteHand;
          if (changed) {
              w = minuteHand.getIntrinsicWidth();
              h = minuteHand.getIntrinsicHeight();
              minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
          }
          minuteHand.draw(canvas);
          canvas.restore();
  
          if (scaled) {
              canvas.restore();
          }
      }
  
      private void onTimeChanged() {
          mCalendar.setToNow();
  
          int hour = mCalendar.hour;
          int minute = mCalendar.minute;
          int second = mCalendar.second;
  
          mMinutes = minute + second / 60.0f;
          mHour = hour + mMinutes / 60.0f;
          mChanged = true;
  
          updateContentDescription(mCalendar);
      }
  
      private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
              if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
                  String tz = intent.getStringExtra("time-zone");
                  mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
              }
  
              onTimeChanged();
  
              invalidate();
          }
      };
  
      private void updateContentDescription(Time time) {
          final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR;
          String contentDescription = DateUtils.formatDateTime(mContext,
                  time.toMillis(false), flags);
          setContentDescription(contentDescription);
      }
  }
  