1 /* 2 * Copyright (C) 2014 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 com.android.camera.ui; 18 19 import java.util.Locale; 20 21 import android.content.Context; 22 import android.graphics.RectF; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.util.AttributeSet; 26 import android.view.View; 27 import android.widget.FrameLayout; 28 import android.widget.TextView; 29 30 import com.android.camera.debug.Log; 31 import com.android.camera2.R; 32 33 /** 34 * This class manages the looks of the countdown. 35 */ 36 public class CountDownView extends FrameLayout { 37 38 private static final Log.Tag TAG = new Log.Tag("CountDownView"); 39 private static final int SET_TIMER_TEXT = 1; 40 private static final long ANIMATION_DURATION_MS = 800; 41 private TextView mRemainingSecondsView; 42 private int mRemainingSecs = 0; 43 private OnCountDownStatusListener mListener; 44 private final Handler mHandler = new MainHandler(); 45 private final RectF mPreviewArea = new RectF(); 46 47 /** 48 * Listener that gets notified when the countdown status has 49 * been updated (i.e. remaining seconds changed, or finished). 50 */ 51 public interface OnCountDownStatusListener { 52 /** 53 * Gets notified when the remaining seconds for the countdown 54 * has changed. 55 * 56 * @param remainingSeconds seconds remained for countdown 57 */ onRemainingSecondsChanged(int remainingSeconds)58 public void onRemainingSecondsChanged(int remainingSeconds); 59 60 /** 61 * Gets called when countdown is finished. 62 */ onCountDownFinished()63 public void onCountDownFinished(); 64 } 65 CountDownView(Context context, AttributeSet attrs)66 public CountDownView(Context context, AttributeSet attrs) { 67 super(context, attrs); 68 } 69 70 /** 71 * Returns whether countdown is on-going. 72 */ isCountingDown()73 public boolean isCountingDown() { 74 return mRemainingSecs > 0; 75 }; 76 77 /** 78 * Responds to preview area change by centering th countdown UI in the new 79 * preview area. 80 */ onPreviewAreaChanged(RectF previewArea)81 public void onPreviewAreaChanged(RectF previewArea) { 82 mPreviewArea.set(previewArea); 83 } 84 remainingSecondsChanged(int newVal)85 private void remainingSecondsChanged(int newVal) { 86 mRemainingSecs = newVal; 87 if (mListener != null) { 88 mListener.onRemainingSecondsChanged(mRemainingSecs); 89 } 90 91 if (newVal == 0) { 92 // Countdown has finished. 93 setVisibility(View.INVISIBLE); 94 if (mListener != null) { 95 mListener.onCountDownFinished(); 96 } 97 } else { 98 Locale locale = getResources().getConfiguration().locale; 99 String localizedValue = String.format(locale, "%d", newVal); 100 mRemainingSecondsView.setText(localizedValue); 101 // Fade-out animation. 102 startFadeOutAnimation(); 103 // Schedule the next remainingSecondsChanged() call in 1 second 104 mHandler.sendEmptyMessageDelayed(SET_TIMER_TEXT, 1000); 105 } 106 } 107 startFadeOutAnimation()108 private void startFadeOutAnimation() { 109 int textWidth = mRemainingSecondsView.getMeasuredWidth(); 110 int textHeight = mRemainingSecondsView.getMeasuredHeight(); 111 mRemainingSecondsView.setScaleX(1f); 112 mRemainingSecondsView.setScaleY(1f); 113 mRemainingSecondsView.setTranslationX(mPreviewArea.centerX() - textWidth / 2); 114 mRemainingSecondsView.setTranslationY(mPreviewArea.centerY() - textHeight / 2); 115 mRemainingSecondsView.setPivotX(textWidth / 2); 116 mRemainingSecondsView.setPivotY(textHeight / 2); 117 mRemainingSecondsView.setAlpha(1f); 118 float endScale = 2.5f; 119 mRemainingSecondsView.animate().scaleX(endScale).scaleY(endScale) 120 .alpha(0f).setDuration(ANIMATION_DURATION_MS).start(); 121 } 122 123 @Override onFinishInflate()124 protected void onFinishInflate() { 125 super.onFinishInflate(); 126 mRemainingSecondsView = (TextView) findViewById(R.id.remaining_seconds); 127 } 128 129 /** 130 * Sets a listener that gets notified when the status of countdown has changed. 131 */ setCountDownStatusListener(OnCountDownStatusListener listener)132 public void setCountDownStatusListener(OnCountDownStatusListener listener) { 133 mListener = listener; 134 } 135 136 /** 137 * Starts showing countdown in the UI. 138 * 139 * @param sec duration of the countdown, in seconds 140 */ startCountDown(int sec)141 public void startCountDown(int sec) { 142 if (sec <= 0) { 143 Log.w(TAG, "Invalid input for countdown timer: " + sec + " seconds"); 144 return; 145 } 146 if (isCountingDown()) { 147 cancelCountDown(); 148 } 149 setVisibility(View.VISIBLE); 150 remainingSecondsChanged(sec); 151 } 152 153 /** 154 * Cancels the on-going countdown in the UI, if any. 155 */ cancelCountDown()156 public void cancelCountDown() { 157 if (mRemainingSecs > 0) { 158 mRemainingSecs = 0; 159 mHandler.removeMessages(SET_TIMER_TEXT); 160 setVisibility(View.INVISIBLE); 161 } 162 } 163 164 private class MainHandler extends Handler { 165 @Override handleMessage(Message message)166 public void handleMessage(Message message) { 167 if (message.what == SET_TIMER_TEXT) { 168 remainingSecondsChanged(mRemainingSecs -1); 169 } 170 } 171 } 172 }