/* * Copyright (C) 2013 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.google.android.glass.sample.stopwatch; import android.content.Context; import android.graphics.Canvas; import android.media.AudioManager; import android.media.SoundPool; import android.os.SystemClock; import android.util.Log; import android.view.LayoutInflater; import android.view.SurfaceHolder; import android.view.View; import java.util.concurrent.TimeUnit; /** * SurfaceHolder.Callback used to draw the chronometer on the timeline LiveCard. */ public class ChronometerDrawer implements SurfaceHolder.Callback { private static final String TAG = "ChronometerDrawer"; private static final long SEC_TO_MILLIS = TimeUnit.SECONDS.toMillis(1); private static final int SOUND_PRIORITY = 1; private static final int MAX_STREAMS = 1; private static final int COUNT_DOWN_VALUE = 3; private final SoundPool mSoundPool; private final int mStartSoundId; private final int mCountDownSoundId; private final CountDownView mCountDownView; private final ChronometerView mChronometerView; private long mCurrentTimeSeconds; private boolean mCountDownSoundPlayed; private SurfaceHolder mHolder; private boolean mCountDownDone; public ChronometerDrawer(Context context) { mCountDownView = new CountDownView(context); mCountDownView.setCountDown(COUNT_DOWN_VALUE); mCountDownView.setListener(new CountDownView.CountDownListener() { @Override public void onTick(long millisUntilFinish) { maybePlaySound(millisUntilFinish); draw(mCountDownView); } @Override public void onFinish() { mCountDownDone = true; mChronometerView.setBaseMillis(SystemClock.elapsedRealtime()); if (mHolder != null) { mChronometerView.start(); } playSound(mStartSoundId); } private void maybePlaySound(long millisUntilFinish) { long currentTimeSeconds = TimeUnit.MILLISECONDS.toSeconds(millisUntilFinish); long milliSecondsPart = millisUntilFinish % SEC_TO_MILLIS; if (currentTimeSeconds != mCurrentTimeSeconds) { mCountDownSoundPlayed = false; mCurrentTimeSeconds = currentTimeSeconds; } if (!mCountDownSoundPlayed && (milliSecondsPart <= CountDownView.ANIMATION_DURATION_IN_MILLIS)) { playSound(mCountDownSoundId); mCountDownSoundPlayed = true; } } }); mChronometerView = new ChronometerView(context); mChronometerView.setListener(new ChronometerView.ChangeListener() { @Override public void onChange() { draw(mChronometerView); } }); mChronometerView.setForceStart(true); mSoundPool = new SoundPool(MAX_STREAMS, AudioManager.STREAM_MUSIC, 0); mStartSoundId = mSoundPool.load(context, R.raw.start, SOUND_PRIORITY); mCountDownSoundId = mSoundPool.load(context, R.raw.countdown_bip, SOUND_PRIORITY); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // Measure and layout the view with the canvas dimensions. int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY); int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY); mCountDownView.measure(measuredWidth, measuredHeight); mCountDownView.layout( 0, 0, mCountDownView.getMeasuredWidth(), mCountDownView.getMeasuredHeight()); mChronometerView.measure(measuredWidth, measuredHeight); mChronometerView.layout( 0, 0, mChronometerView.getMeasuredWidth(), mChronometerView.getMeasuredHeight()); } @Override public void surfaceCreated(SurfaceHolder holder) { Log.d(TAG, "Surface created"); mHolder = holder; if (mCountDownDone) { mChronometerView.start(); } else { mCountDownView.start(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.d(TAG, "Surface destroyed"); mChronometerView.stop(); mHolder = null; } /** * Draws the view in the SurfaceHolder's canvas. */ private void draw(View view) { Canvas canvas; try { canvas = mHolder.lockCanvas(); } catch (Exception e) { return; } if (canvas != null) { view.draw(canvas); mHolder.unlockCanvasAndPost(canvas); } } /** * Plays the provided {@code soundId}. */ private void playSound(int soundId) { mSoundPool.play(soundId, 1 /* leftVolume */, 1 /* rightVolume */, SOUND_PRIORITY, 0 /* loop */, 1 /* rate */); } }