<commit_before>package com.geekyouup.android.ustopwatch.fragments;

import com.geekyouup.android.ustopwatch.AlarmUpdater;
import com.geekyouup.android.ustopwatch.R;
import com.geekyouup.android.ustopwatch.SoundManager;
import com.geekyouup.android.ustopwatch.UltimateStopwatchActivity;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

/**
 * Animated view that draws the stopwatch, takes keystrokes, etc.
 */
public class StopwatchView extends SurfaceView implements SurfaceHolder.Callback {
	public class StopwatchThead extends Thread implements OnTouchListener {
		/*
		 * State-tracking constants
		 */
		public static final int STATE_PAUSE = 2;
		public static final int STATE_READY = 3;
		public static final int STATE_RUNNING = 4;

		private static final String KEY_STATE = "state";
		private static final String KEY_LASTTIME = "lasttime";
		private static final String KEY_NOWTIME = "currenttime";
        private static final String KEY_COUNTDOWN_SUFFIX = "_cd";
		private double mScaleFactor = 1; //how much to scale the images up or down by
		/*
		 * Member (state) fields
		 */
		/** The drawable to use as the background of the animation canvas */
		private Bitmap mBackgroundImage;
		private int mBackgroundStartY;
		private int mAppOffsetX = 0;
		private int mAppOffsetY = 0;
		private double mMinsAngle = 0;
		private double mSecsAngle = 0;
		private double mDisplayTimeMillis = 0;
		private double twoPI = Math.PI * 2.0;
		private boolean mStopwatchMode = true;

		private int mCanvasWidth = 320;
		private int mCanvasHeight = 480;
		private int mSecsCenterX = 156;
		private int mSecsCenterY = 230;
		private int mMinsCenterX = 156;
		private int mMinsCenterY = 185;

		private int mSecsHalfWidth = 0;
		private int mSecsHalfHeight = 0;
		private int mMinsHalfWidth = 0;
		private int mMinsHalfHeight = 0;

		/** Used to figure out elapsed time between frames */
		private long mLastTime;

		private Drawable mSecHand;
		private Drawable mMinHand;

		/** The state of the game. One of READY, RUNNING, PAUSE, LOSE, or WIN */
		private int mMode = STATE_READY;

		/** Indicate whether the surface has been created & is ready to draw */
		private boolean mRun = false;
		private boolean mSkipDraw = false;
        private long mTouching = 0L;

		/** Handle to the surface manager object we interact with */
		private SurfaceHolder mSurfaceHolder;
		private Handler mHandler;
		private Context mContext;
        int mCountDownBGColor = 0xff000000;

		public StopwatchThead(SurfaceHolder surfaceHolder, Context context, boolean isStopwatchMode) {
			// get handles to some important objects
			mSurfaceHolder = surfaceHolder;
			mContext = context;
			mStopwatchMode=isStopwatchMode;

			Resources res = mContext.getResources();
			//loadGraphics(res, isStopwatchMode());

            mCountDownBGColor = getResources().getColor(R.color.countdown_background);

            //fix the background colour shearing when swiping by setting the surface on top of the window
            //and fixing the window bg color
            setZOrderOnTop(true);
		}

        private void loadGraphics(Resources res, boolean isStopwatch)
        {
            if(res==null) res = mContext.getResources();
            mSkipDraw=true;

            int minDim = Math.min(mCanvasHeight,mCanvasWidth);
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inScaled=false;
            double handsScaleFactor = 1;

            if(minDim >= 720){
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background720:R.drawable.background720_cd,options);
            }else if(minDim >= 590){
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background590:R.drawable.background590_cd,options);
                handsScaleFactor=0.82;
            }else if(minDim >= 460){
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background460:R.drawable.background460_cd,options);
                handsScaleFactor= 0.64;
            }else if(minDim >= 320){
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background320:R.drawable.background320_cd,options);
                handsScaleFactor=0.444;
            }else{
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background240:R.drawable.background240_cd,options);
                handsScaleFactor= 0.333;
            }

            mSecHand = res.getDrawable(isStopwatch?R.drawable.sechand:R.drawable.sechand_cd);
            mMinHand = res.getDrawable(isStopwatch?R.drawable.minhand:R.drawable.minhand_cd);

            mSecsHalfWidth = mSecHand.getIntrinsicWidth()/2;
            mSecsHalfHeight = mSecHand.getIntrinsicHeight()/2;

            mMinsHalfWidth = mMinHand.getIntrinsicWidth()/2;
            mMinsHalfHeight = mMinHand.getIntrinsicHeight()/2;

            mMinsHalfHeight = (int) ((double) mMinsHalfHeight * handsScaleFactor);
            mMinsHalfWidth = (int) ((double) mMinsHalfWidth * handsScaleFactor);
            mSecsHalfHeight= (int) ((double) mSecsHalfHeight * handsScaleFactor);
            mSecsHalfWidth= (int) ((double) mSecsHalfWidth * handsScaleFactor);

            mBackgroundStartY = (mCanvasHeight - mBackgroundImage.getHeight()) / 2;
            mAppOffsetX = (mCanvasWidth - mBackgroundImage.getWidth()) / 2;

            if (mBackgroundStartY < 0)
                mAppOffsetY = -mBackgroundStartY;

            mSecsCenterY = mBackgroundStartY + (mBackgroundImage.getHeight() / 2); //new graphics have watch center in center
            mMinsCenterY = mBackgroundStartY + (mBackgroundImage.getHeight() * 314 / 1000);//mSecsCenterY - 44;
            mSecsCenterX = mCanvasWidth/2;
            mMinsCenterX = mCanvasWidth/2;

            mSkipDraw=false;
        }

		public void setHandler(Handler handler) {
			this.mHandler = handler;
		}

		/**
		 * Starts the game, setting parameters for the current difficulty.
		 */
		public void doStart() {
			synchronized (mSurfaceHolder) {
				// First set the game for Medium difficulty
				mLastTime = System.currentTimeMillis();
				setState(STATE_RUNNING);
			}
		}

		/**
		 * Pauses the physics update & animation.
		 */
		public void pause() {
			synchronized (mSurfaceHolder) {
				if (mMode == STATE_RUNNING)
					setState(STATE_PAUSE);
			}
		}

		public void reset() {
			resetVars();
		}

		private void resetVars() {
			synchronized (mSurfaceHolder) {
				setState(STATE_PAUSE);
				mLastTime = 0;
				mMinsAngle = 0;
				mSecsAngle = 0;
				mDisplayTimeMillis = 0;
				
				broadcastClockTime(0);
			}
		}

		public void setTime(int hour, int minute, int seconds, boolean start) {
			synchronized (mSurfaceHolder) {
				setState(STATE_READY);
				mLastTime = System.currentTimeMillis();
				mMinsAngle = (Math.PI * 2 * ((double) minute / 30.0));
				mSecsAngle = (Math.PI * 2 * ((double) seconds / 60.0));
				mDisplayTimeMillis = hour * 3600000 + minute * 60000 + seconds * 1000;
				
				if(start) doStart();
                else
                {
                    updatePhysics();
                }
			}
		}

		@Override
		public void run() {
			while (mRun) {
				Canvas c = null;
				try {
					//auto double buffer by locking canvas
					c = mSurfaceHolder.lockCanvas(null);
					if(c!= null)
					{
						synchronized (mSurfaceHolder) {
							if (mMode == STATE_RUNNING) updatePhysics();
							if(!mSkipDraw) doDraw(c);
						}
					}
				} finally {
					if (c != null) {
						mSurfaceHolder.unlockCanvasAndPost(c);
					}
					try {
						sleep(30);
					} catch (InterruptedException e) {
					}
				}
			}
		}
		
		/**
		 * Update the time
		 */
		private void updatePhysics() {
			long now = System.currentTimeMillis();

			if(mMode == STATE_RUNNING)
			{
				if (isStopwatchMode())
					mDisplayTimeMillis += (now - mLastTime);
				else
					mDisplayTimeMillis -= (now - mLastTime);
			}else
			{
				mLastTime=now;
			}

			// mins is 0 to 30
			mMinsAngle = twoPI * (mDisplayTimeMillis / 1800000.0);
			mSecsAngle = twoPI * (mDisplayTimeMillis / 60000.0);

			if(mDisplayTimeMillis<0) mDisplayTimeMillis=0;
			
			// send the time back to the Activity to update the other views
			broadcastClockTime(isStopwatchMode()?mDisplayTimeMillis:-mDisplayTimeMillis);
			mLastTime = now;

			// stop timer at end
			if (mMode == STATE_RUNNING && !isStopwatchMode() && mDisplayTimeMillis <= 0) {
                Log.d("USW","updatePhysics resetting timer mDisplayTime="+mDisplayTimeMillis);
				resetVars(); // applies pause state
                notifyCountdownComplete();
			}
		}		
		
		/**
		 * Draws the background and hands on the Canvas.
		 */
		private void doDraw(Canvas canvas) {
			// Draw the background image. Operations on the Canvas accumulate
            canvas.drawColor(isStopwatchMode()?Color.WHITE:mCountDownBGColor);
			canvas.drawBitmap(mBackgroundImage, mAppOffsetX, mBackgroundStartY + mAppOffsetY, null);

            // draw the mins hand with its current rotatiom
            canvas.save();
            canvas.rotate((float) Math.toDegrees(mMinsAngle), mMinsCenterX, mMinsCenterY + mAppOffsetY);
            mMinHand.setBounds(mMinsCenterX - mMinsHalfWidth, mMinsCenterY - mMinsHalfHeight + mAppOffsetY,
                    mMinsCenterX + mMinsHalfWidth, mMinsCenterY + mAppOffsetY + mMinsHalfHeight);
            mMinHand.draw(canvas);
            canvas.restore();

			// Draw the secs hand with its current rotation
			canvas.save();
			canvas.rotate((float) Math.toDegrees(mSecsAngle), mSecsCenterX, mSecsCenterY + mAppOffsetY);
			mSecHand.setBounds(mSecsCenterX - mSecsHalfWidth, mSecsCenterY - mSecsHalfHeight + mAppOffsetY,
					mSecsCenterX + mSecsHalfWidth, mSecsCenterY + mAppOffsetY + mSecsHalfHeight);
			mSecHand.draw(canvas);
			canvas.restore();
		}

		/**
		 * Dump state to the provided Bundle. Typically called when the
		 * Activity is being suspended.
		 */
		public void saveState(SharedPreferences.Editor map) {
			synchronized (mSurfaceHolder) {
				if (!isStopwatchMode() || mDisplayTimeMillis > 0) {
					if (!isStopwatchMode() && mDisplayTimeMillis > 0 && mMode == STATE_RUNNING) {
						AlarmUpdater.setCountdownAlarm(mContext, (long) mDisplayTimeMillis);
					}else
					{
						AlarmUpdater.cancelCountdownAlarm(mContext); //just to be sure
					}

					map.putInt(KEY_STATE+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), mMode);
					map.putLong(KEY_LASTTIME+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), mLastTime);
					map.putLong(KEY_NOWTIME+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), (long) mDisplayTimeMillis);
				} else {
					map.clear();
				}
			}
		}

		/**
		 * Restores state from the indicated Bundle. Called when
		 * the Activity is being restored after having been previously
		 * destroyed.
		 */
		private synchronized void restoreState(SharedPreferences savedState) {
			synchronized (mSurfaceHolder) {
				if (savedState != null) {
					setState(savedState.getInt(KEY_STATE+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), STATE_PAUSE));
					mLastTime = savedState.getLong(KEY_LASTTIME+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), System.currentTimeMillis());
					mDisplayTimeMillis = savedState.getLong(KEY_NOWTIME+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), 0);
					//loadGraphics(null, mStopwatchMode);
					updatePhysics();
				}
				notifyStateChanged();
				AlarmUpdater.cancelCountdownAlarm(mContext); //just to be sure
			}
		}

		/**
		 * Used to signal the thread whether it should be running or not.
		 * Passing true allows the thread to run; passing false will shut it
		 * down if it's already running. Calling start() after this was most
		 * recently called with false will result in an immediate shutdown.
		 */
		public void setRunning(boolean b) {
			mRun = b;
		}

		public boolean isRunning() {
			return mRun;
		}

        public boolean isPaused()
        {
            return (mMode != STATE_RUNNING);
        }

		/**
		 * Sets the  mode. That is, whether we are running, paused, in the
		 * failure state etc.
		 */
		public void setState(int mode) {
			synchronized (mSurfaceHolder) {
				mMode = mode;
				Log.d("USW", "Mode set to " + mMode);
			}
		}

		/**
		 * Resumes from a pause.
		 */
		public void unpause() {
			// stop timer at end
			if (!isStopwatchMode() && mDisplayTimeMillis <= 0) {
				resetVars(); // applies pause state
				//requestCountdownDialog();
			} else {
				// Move the real time clock up to now
				synchronized (mSurfaceHolder) {
					mLastTime = System.currentTimeMillis();
				}
				setState(STATE_RUNNING);
			}
		}

        private void broadcastClockTime(double mTime)
		{
			if (mHandler != null) {
				Message msg = mHandler.obtainMessage();
				Bundle b = new Bundle();
				b.putBoolean(UltimateStopwatchActivity.MSG_UPDATE_COUNTER_TIME, true);
				b.putDouble(UltimateStopwatchActivity.MSG_NEW_TIME_DOUBLE, mTime);
				msg.setData(b);
				mHandler.sendMessage(msg);
			}
		}

        private void notifyCountdownComplete()
        {
            if (mHandler != null) {
                Message msg = mHandler.obtainMessage();
                Bundle b = new Bundle();
                b.putBoolean(CountdownFragment.MSG_COUNTDOWN_COMPLETE, true);
                msg.setData(b);
                mHandler.sendMessage(msg);
            }
        }

        private void notifyStateChanged()
        {
            if (mHandler != null) {
                Message msg = mHandler.obtainMessage();
                Bundle b = new Bundle();
                b.putBoolean(UltimateStopwatchActivity.MSG_STATE_CHANGE, true);
                msg.setData(b);
                mHandler.sendMessage(msg);
            }
        }


		public boolean startStop() {
			if (mMode == STATE_PAUSE) {
				unpause();
			} else if (mMode == STATE_RUNNING) {
				pause();
			} else {
				doStart();
			}

            notifyStateChanged();
            return (mMode == STATE_RUNNING);
		}

		public boolean isStopwatchMode() {
			return mStopwatchMode;
		}

		public void setIsStopwatchMode(boolean isStopwatchMode) {
            this.mStopwatchMode = isStopwatchMode;
			resetVars();
			loadGraphics(null, isStopwatchMode);
		}

		public boolean onTouch(View v, MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_DOWN) {
                SoundManager sm = SoundManager.getInstance(mContext);
                if(sm.isEndlessAlarmSounding())
                {
                   sm.stopEndlessAlarm();
                }else
                {
    				mTouching = System.currentTimeMillis();
                }
			}else if(event.getAction() == MotionEvent.ACTION_MOVE)
            {
                if(mTouching>0 && System.currentTimeMillis()-mTouching > 1000)
                    mTouching=0L;   //reset touch if user is swiping
            }
            else if(event.getAction() == MotionEvent.ACTION_UP)
            {
                if(mTouching>0)// && System.currentTimeMillis()-mTouching < 500)
                    startStop();

                mTouching=0L;
            }
			return true;
		}
		
		// none trackball devices
		public boolean doKeypress(int keyCode) {
			if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_SPACE) {
				startStop();
				return true;
			}
			return false;
		}

		//trackball device
		public boolean doTrackBall(MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_DOWN) {
				startStop();
				return true;
			}
			return false;
		}

		/* Callback invoked when the surface dimensions change. */
		public void setSurfaceSize(int width, int height) {
			// synchronized to make sure these all change atomically
			synchronized (mSurfaceHolder) {
				mCanvasWidth = width;
				mCanvasHeight = height;

				loadGraphics(null,isStopwatchMode());
				
				Log.d("USW", "Surface Width:" + width + ", Surface Height:" + height + ", AppXOffset: " + mAppOffsetX + ", bgImageWidth: " + mBackgroundImage.getWidth());
			}
		}
		
		private void scaleImages()
		{
			// need to check 2 things. If image is narrower than canvas
			// scale it down, then if image is taller than canvas shift it down
			int bgImageWidth = mBackgroundImage.getWidth();
			int bgImageHeight = mBackgroundImage.getHeight();
			mScaleFactor=1;

            Log.d("USW","Scaling issue, canvasWidth" + mCanvasWidth + " - imgWidgth " + bgImageWidth + "!!!!!!!!");
            Log.d("USW","Scaling issue, canvasHeight" + mCanvasHeight + " - imgHeight " + bgImageHeight + "!!!!!!!!");

            if(bgImageWidth > mCanvasWidth) mScaleFactor = ((double) mCanvasWidth / (double) bgImageWidth);
			if(bgImageHeight > mCanvasHeight)
            {   double mScaleFactor2 = ((double)mCanvasHeight / (double) bgImageHeight);
                if(mScaleFactor2<mScaleFactor) mScaleFactor = mScaleFactor2;
            }

            /*mScaleFactor = ((double) mCanvasWidth / (double) bgImageWidth);
            if( ((double)bgImageHeight*mScaleFactor) > mCanvasHeight)
            {
                //double mScaleFactor2 = ((double)mCanvasHeight / (double) bgImageHeight);
                //if(mScaleFactor2<mScaleFactor) mScaleFactor = mScaleFactor2;
                mScaleFactor = ((double) mCanvasHeight / (double) bgImageHeight);
            } */

            Log.d("USW","ScaleFactor " + mScaleFactor);
			if(mScaleFactor != 1)
			{
				mBackgroundImage = Bitmap
				.createScaledBitmap(mBackgroundImage, (int) ((double) bgImageWidth * mScaleFactor),
						(int) ((double) bgImageHeight * mScaleFactor),
						true);

				mMinsHalfHeight = (int) ((double) mMinsHalfHeight * mScaleFactor);
				mMinsHalfWidth = (int) ((double) mMinsHalfWidth * mScaleFactor);
				mSecsHalfHeight= (int) ((double) mSecsHalfHeight * mScaleFactor);
				mSecsHalfWidth= (int) ((double) mSecsHalfWidth * mScaleFactor);
				
				bgImageWidth = mBackgroundImage.getWidth();
				bgImageHeight = mBackgroundImage.getHeight();
			}

            mBackgroundStartY = (mCanvasHeight - bgImageHeight) / 2;
			if (mBackgroundStartY < 0)
				mAppOffsetY = -mBackgroundStartY;

			mSecsCenterY = mBackgroundStartY + (bgImageHeight / 2); //new graphics have watch center in center
			mMinsCenterY = mBackgroundStartY + (bgImageHeight * 314 / 1000);//mSecsCenterY - 44;
			
			mAppOffsetX = (mCanvasWidth - mBackgroundImage.getWidth()) / 2;

			mSecsCenterX = mCanvasWidth/2;
			mMinsCenterX = mCanvasWidth/2;
		}
	}

	
	/** Handle to the application context, used to e.g. fetch Drawables. */
	private StopwatchThead thread;
	private SurfaceHolder sHolder;
	private Context mContext;
	private SharedPreferences mRestoreState;
    private boolean mStopwatchMode=true;
<commit_msg>Code cleanup<commit_after>package com.geekyouup.android.ustopwatch.fragments;

import com.geekyouup.android.ustopwatch.AlarmUpdater;
import com.geekyouup.android.ustopwatch.R;
import com.geekyouup.android.ustopwatch.SoundManager;
import com.geekyouup.android.ustopwatch.UltimateStopwatchActivity;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

/**
 * Animated view that draws the stopwatch, takes keystrokes, etc.
 */
public class StopwatchView extends SurfaceView implements SurfaceHolder.Callback {
	public class StopwatchThead extends Thread implements OnTouchListener {
		/*
		 * State-tracking constants
		 */
		public static final int STATE_PAUSE = 2;
		public static final int STATE_READY = 3;
		public static final int STATE_RUNNING = 4;

		private static final String KEY_STATE = "state";
		private static final String KEY_LASTTIME = "lasttime";
		private static final String KEY_NOWTIME = "currenttime";
        private static final String KEY_COUNTDOWN_SUFFIX = "_cd";
		private double mScaleFactor = 1; //how much to scale the images up or down by
		/*
		 * Member (state) fields
		 */
		/** The drawable to use as the background of the animation canvas */
		private Bitmap mBackgroundImage;
		private int mBackgroundStartY;
		private int mAppOffsetX = 0;
		private int mAppOffsetY = 0;
		private double mMinsAngle = 0;
		private double mSecsAngle = 0;
		private double mDisplayTimeMillis = 0;
		private double twoPI = Math.PI * 2.0;
		private boolean mStopwatchMode = true;

		private int mCanvasWidth = 320;
		private int mCanvasHeight = 480;
		private int mSecsCenterX = 156;
		private int mSecsCenterY = 230;
		private int mMinsCenterX = 156;
		private int mMinsCenterY = 185;

		private int mSecsHalfWidth = 0;
		private int mSecsHalfHeight = 0;
		private int mMinsHalfWidth = 0;
		private int mMinsHalfHeight = 0;

		/** Used to figure out elapsed time between frames */
		private long mLastTime;

		private Drawable mSecHand;
		private Drawable mMinHand;

		/** The state of the game. One of READY, RUNNING, PAUSE, LOSE, or WIN */
		private int mMode = STATE_READY;

		/** Indicate whether the surface has been created & is ready to draw */
		private boolean mRun = false;
		private boolean mSkipDraw = false;
        private long mTouching = 0L;

		/** Handle to the surface manager object we interact with */
		private SurfaceHolder mSurfaceHolder;
		private Handler mHandler;
		private Context mContext;
        int mCountDownBGColor = 0xff000000;

		public StopwatchThead(SurfaceHolder surfaceHolder, Context context, boolean isStopwatchMode) {
			// get handles to some important objects
			mSurfaceHolder = surfaceHolder;
			mContext = context;
			mStopwatchMode=isStopwatchMode;

			Resources res = mContext.getResources();
			//loadGraphics(res, isStopwatchMode());

            mCountDownBGColor = getResources().getColor(R.color.countdown_background);

            //fix the background colour shearing when swiping by setting the surface on top of the window
            //and fixing the window bg color
            setZOrderOnTop(true);
		}

        private void loadGraphics(Resources res, boolean isStopwatch)
        {
            if(res==null) res = mContext.getResources();
            mSkipDraw=true;

            int minDim = Math.min(mCanvasHeight,mCanvasWidth);
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inScaled=false;
            double handsScaleFactor = 1;

            if(minDim >= 720){
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background720:R.drawable.background720_cd,options);
            }else if(minDim >= 590){
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background590:R.drawable.background590_cd,options);
                handsScaleFactor=0.82;
            }else if(minDim >= 460){
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background460:R.drawable.background460_cd,options);
                handsScaleFactor= 0.64;
            }else if(minDim >= 320){
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background320:R.drawable.background320_cd,options);
                handsScaleFactor=0.444;
            }else{
                mBackgroundImage = BitmapFactory.decodeResource(res, isStopwatch?R.drawable.background240:R.drawable.background240_cd,options);
                handsScaleFactor= 0.333;
            }

            mSecHand = res.getDrawable(isStopwatch?R.drawable.sechand:R.drawable.sechand_cd);
            mMinHand = res.getDrawable(isStopwatch?R.drawable.minhand:R.drawable.minhand_cd);

            mSecsHalfWidth = mSecHand.getIntrinsicWidth()/2;
            mSecsHalfHeight = mSecHand.getIntrinsicHeight()/2;

            mMinsHalfWidth = mMinHand.getIntrinsicWidth()/2;
            mMinsHalfHeight = mMinHand.getIntrinsicHeight()/2;

            mMinsHalfHeight = (int) ((double) mMinsHalfHeight * handsScaleFactor);
            mMinsHalfWidth = (int) ((double) mMinsHalfWidth * handsScaleFactor);
            mSecsHalfHeight= (int) ((double) mSecsHalfHeight * handsScaleFactor);
            mSecsHalfWidth= (int) ((double) mSecsHalfWidth * handsScaleFactor);

            mBackgroundStartY = (mCanvasHeight - mBackgroundImage.getHeight()) / 2;
            mAppOffsetX = (mCanvasWidth - mBackgroundImage.getWidth()) / 2;

            if (mBackgroundStartY < 0)
                mAppOffsetY = -mBackgroundStartY;

            mSecsCenterY = mBackgroundStartY + (mBackgroundImage.getHeight() / 2); //new graphics have watch center in center
            mMinsCenterY = mBackgroundStartY + (mBackgroundImage.getHeight() * 314 / 1000);//mSecsCenterY - 44;
            mSecsCenterX = mCanvasWidth/2;
            mMinsCenterX = mCanvasWidth/2;

            mSkipDraw=false;
        }

		public void setHandler(Handler handler) {
			this.mHandler = handler;
		}

		/**
		 * Starts the game, setting parameters for the current difficulty.
		 */
		public void doStart() {
			synchronized (mSurfaceHolder) {
				// First set the game for Medium difficulty
				mLastTime = System.currentTimeMillis();
				setState(STATE_RUNNING);
			}
		}

		/**
		 * Pauses the physics update & animation.
		 */
		public void pause() {
			synchronized (mSurfaceHolder) {
				if (mMode == STATE_RUNNING)
					setState(STATE_PAUSE);
			}
		}

		public void reset() {
			resetVars();
		}

		private void resetVars() {
			synchronized (mSurfaceHolder) {
				setState(STATE_PAUSE);
				mLastTime = 0;
				mMinsAngle = 0;
				mSecsAngle = 0;
				mDisplayTimeMillis = 0;
				
				broadcastClockTime(0);
			}
		}

		public void setTime(int hour, int minute, int seconds, boolean start) {
			synchronized (mSurfaceHolder) {
				setState(STATE_READY);
				mLastTime = System.currentTimeMillis();
				mMinsAngle = (Math.PI * 2 * ((double) minute / 30.0));
				mSecsAngle = (Math.PI * 2 * ((double) seconds / 60.0));
				mDisplayTimeMillis = hour * 3600000 + minute * 60000 + seconds * 1000;
				
				if(start) doStart();
                else
                {
                    updatePhysics();
                }
			}
		}

		@Override
		public void run() {
			while (mRun) {
				Canvas c = null;
				try {
					//auto double buffer by locking canvas
					c = mSurfaceHolder.lockCanvas(null);
					if(c!= null)
					{
						synchronized (mSurfaceHolder) {
							if (mMode == STATE_RUNNING) updatePhysics();
							if(!mSkipDraw) doDraw(c);
						}
					}
				} finally {
					if (c != null) {
						mSurfaceHolder.unlockCanvasAndPost(c);
					}
					try {
						sleep(30);
					} catch (InterruptedException e) {
					}
				}
			}
		}
		
		/**
		 * Update the time
		 */
		private void updatePhysics() {
			long now = System.currentTimeMillis();

			if(mMode == STATE_RUNNING)
			{
				if (isStopwatchMode())
					mDisplayTimeMillis += (now - mLastTime);
				else
					mDisplayTimeMillis -= (now - mLastTime);
			}else
			{
				mLastTime=now;
			}

			// mins is 0 to 30
			mMinsAngle = twoPI * (mDisplayTimeMillis / 1800000.0);
			mSecsAngle = twoPI * (mDisplayTimeMillis / 60000.0);

			if(mDisplayTimeMillis<0) mDisplayTimeMillis=0;
			
			// send the time back to the Activity to update the other views
			broadcastClockTime(isStopwatchMode()?mDisplayTimeMillis:-mDisplayTimeMillis);
			mLastTime = now;

			// stop timer at end
			if (mMode == STATE_RUNNING && !isStopwatchMode() && mDisplayTimeMillis <= 0) {
                Log.d("USW","updatePhysics resetting timer mDisplayTime="+mDisplayTimeMillis);
				resetVars(); // applies pause state
                notifyCountdownComplete();
			}
		}		
		
		/**
		 * Draws the background and hands on the Canvas.
		 */
		private void doDraw(Canvas canvas) {
			// Draw the background image. Operations on the Canvas accumulate
            canvas.drawColor(isStopwatchMode()?Color.WHITE:mCountDownBGColor);
			canvas.drawBitmap(mBackgroundImage, mAppOffsetX, mBackgroundStartY + mAppOffsetY, null);

            // draw the mins hand with its current rotatiom
            canvas.save();
            canvas.rotate((float) Math.toDegrees(mMinsAngle), mMinsCenterX, mMinsCenterY + mAppOffsetY);
            mMinHand.setBounds(mMinsCenterX - mMinsHalfWidth, mMinsCenterY - mMinsHalfHeight + mAppOffsetY,
                    mMinsCenterX + mMinsHalfWidth, mMinsCenterY + mAppOffsetY + mMinsHalfHeight);
            mMinHand.draw(canvas);
            canvas.restore();

			// Draw the secs hand with its current rotation
			canvas.save();
			canvas.rotate((float) Math.toDegrees(mSecsAngle), mSecsCenterX, mSecsCenterY + mAppOffsetY);
			mSecHand.setBounds(mSecsCenterX - mSecsHalfWidth, mSecsCenterY - mSecsHalfHeight + mAppOffsetY,
					mSecsCenterX + mSecsHalfWidth, mSecsCenterY + mAppOffsetY + mSecsHalfHeight);
			mSecHand.draw(canvas);
			canvas.restore();
		}

		/**
		 * Dump state to the provided Bundle. Typically called when the
		 * Activity is being suspended.
		 */
		public void saveState(SharedPreferences.Editor map) {
			synchronized (mSurfaceHolder) {
				if (!isStopwatchMode() || mDisplayTimeMillis > 0) {
					if (!isStopwatchMode() && mDisplayTimeMillis > 0 && mMode == STATE_RUNNING) {
						AlarmUpdater.setCountdownAlarm(mContext, (long) mDisplayTimeMillis);
					}else
					{
						AlarmUpdater.cancelCountdownAlarm(mContext); //just to be sure
					}

					map.putInt(KEY_STATE+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), mMode);
					map.putLong(KEY_LASTTIME+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), mLastTime);
					map.putLong(KEY_NOWTIME+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), (long) mDisplayTimeMillis);
				} else {
					map.clear();
				}
			}
		}

		/**
		 * Restores state from the indicated Bundle. Called when
		 * the Activity is being restored after having been previously
		 * destroyed.
		 */
		private synchronized void restoreState(SharedPreferences savedState) {
			synchronized (mSurfaceHolder) {
				if (savedState != null) {
					setState(savedState.getInt(KEY_STATE+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), STATE_PAUSE));
					mLastTime = savedState.getLong(KEY_LASTTIME+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), System.currentTimeMillis());
					mDisplayTimeMillis = savedState.getLong(KEY_NOWTIME+(mStopwatchMode?"":KEY_COUNTDOWN_SUFFIX), 0);
					//loadGraphics(null, mStopwatchMode);
					updatePhysics();
				}
				notifyStateChanged();
				AlarmUpdater.cancelCountdownAlarm(mContext); //just to be sure
			}
		}

		/**
		 * Used to signal the thread whether it should be running or not.
		 * Passing true allows the thread to run; passing false will shut it
		 * down if it's already running. Calling start() after this was most
		 * recently called with false will result in an immediate shutdown.
		 */
		public void setRunning(boolean b) {
			mRun = b;
		}

		public boolean isRunning() {
			return mRun;
		}

        public boolean isPaused()
        {
            return (mMode != STATE_RUNNING);
        }

		/**
		 * Sets the  mode. That is, whether we are running, paused, in the
		 * failure state etc.
		 */
		public void setState(int mode) {
			synchronized (mSurfaceHolder) {
				mMode = mode;
				Log.d("USW", "Mode set to " + mMode);
			}
		}

		/**
		 * Resumes from a pause.
		 */
		public void unpause() {
			// stop timer at end
			if (!isStopwatchMode() && mDisplayTimeMillis <= 0) {
				resetVars(); // applies pause state
				//requestCountdownDialog();
			} else {
				// Move the real time clock up to now
				synchronized (mSurfaceHolder) {
					mLastTime = System.currentTimeMillis();
				}
				setState(STATE_RUNNING);
			}
		}

        private void broadcastClockTime(double mTime)
		{
			if (mHandler != null) {
				Message msg = mHandler.obtainMessage();
				Bundle b = new Bundle();
				b.putBoolean(UltimateStopwatchActivity.MSG_UPDATE_COUNTER_TIME, true);
				b.putDouble(UltimateStopwatchActivity.MSG_NEW_TIME_DOUBLE, mTime);
				msg.setData(b);
				mHandler.sendMessage(msg);
			}
		}

        private void notifyCountdownComplete()
        {
            if (mHandler != null) {
                Message msg = mHandler.obtainMessage();
                Bundle b = new Bundle();
                b.putBoolean(CountdownFragment.MSG_COUNTDOWN_COMPLETE, true);
                msg.setData(b);
                mHandler.sendMessage(msg);
            }
        }

        private void notifyStateChanged()
        {
            if (mHandler != null) {
                Message msg = mHandler.obtainMessage();
                Bundle b = new Bundle();
                b.putBoolean(UltimateStopwatchActivity.MSG_STATE_CHANGE, true);
                msg.setData(b);
                mHandler.sendMessage(msg);
            }
        }


		public boolean startStop() {
			if (mMode == STATE_PAUSE) {
				unpause();
			} else if (mMode == STATE_RUNNING) {
				pause();
			} else {
				doStart();
			}

            notifyStateChanged();
            return (mMode == STATE_RUNNING);
		}

		public boolean isStopwatchMode() {
			return mStopwatchMode;
		}

		public void setIsStopwatchMode(boolean isStopwatchMode) {
            this.mStopwatchMode = isStopwatchMode;
			resetVars();
			loadGraphics(null, isStopwatchMode);
		}

		public boolean onTouch(View v, MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_DOWN) {
                SoundManager sm = SoundManager.getInstance(mContext);
                if(sm.isEndlessAlarmSounding())
                {
                   sm.stopEndlessAlarm();
                }else
                {
    				mTouching = System.currentTimeMillis();
                }
			}else if(event.getAction() == MotionEvent.ACTION_MOVE)
            {
                if(mTouching>0 && System.currentTimeMillis()-mTouching > 1000)
                    mTouching=0L;   //reset touch if user is swiping
            }
            else if(event.getAction() == MotionEvent.ACTION_UP)
            {
                if(mTouching>0)// && System.currentTimeMillis()-mTouching < 500)
                    startStop();

                mTouching=0L;
            }
			return true;
		}
		
		// none trackball devices
		public boolean doKeypress(int keyCode) {
			if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_SPACE) {
				startStop();
				return true;
			}
			return false;
		}

		//trackball device
		public boolean doTrackBall(MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_DOWN) {
				startStop();
				return true;
			}
			return false;
		}

		/* Callback invoked when the surface dimensions change. */
		public void setSurfaceSize(int width, int height) {
			// synchronized to make sure these all change atomically
			synchronized (mSurfaceHolder) {
				mCanvasWidth = width;
				mCanvasHeight = height;

				loadGraphics(null,isStopwatchMode());
			}
		}

	}

	
	/** Handle to the application context, used to e.g. fetch Drawables. */
	private StopwatchThead thread;
	private SurfaceHolder sHolder;
	private Context mContext;
	private SharedPreferences mRestoreState;
    private boolean mStopwatchMode=true;

{'fraction_non_alphanumeric': 0.09868861607142858, 'fraction_numerical': 0.010881696428571428, 'mean_word_length': 2.8279397628965075, 'pattern_counts': {'":': 12, '<': 16, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6722904', 'n_tokens_mistral': 12564, 'n_tokens_neox': 10516, 'n_words': 2530}