com.royer.bangstopwatch.app.StopwatchFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.royer.bangstopwatch.app.StopwatchFragment.java

Source

/**
 * Copyright (C) 2013 Royer Wang
 *
 * 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.royer.bangstopwatch.app;

import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import com.actionbarsherlock.app.SherlockFragment;
import com.royer.bangstopwatch.Bang;
import com.royer.bangstopwatch.MainActivity;
import com.royer.bangstopwatch.LapManager;
import com.royer.bangstopwatch.R;
import com.royer.bangstopwatch.RecordService;
import com.royer.bangstopwatch.RecordService.LocalBinder;
import com.royer.bangstopwatch.Timekeeper;
import com.royer.bangstopwatch.adapters.LapArrayAdapter;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;

public class StopwatchFragment extends SherlockFragment implements CountdownDialog.NotifyCountdownListener, Bang {

    public static final String TAG = "StopwatchFragment";

    private static final String STATE_TIMEKEEPER = "royer.bangstopwatch.stopwatch.timekeeper";
    private static final String STATE_LAPS = "royer.bangstopwatch.stopwatch.laps";
    private static final String STATE_COUNTDOWNWND = "royer.bangstopwatch.stopwatch.countdownwnd";
    private static final String STATE_STATE = "royer.bangstopwatch.stopwatch.state";
    private static final String STATE_BOUNDING = "royer.bangstopwatch.stopwatch.bounding";

    private int[] res_img_Digits = { R.drawable.digitaldigit0, R.drawable.digitaldigit1, R.drawable.digitaldigit2,
            R.drawable.digitaldigit3, R.drawable.digitaldigit4, R.drawable.digitaldigit5, R.drawable.digitaldigit6,
            R.drawable.digitaldigit7, R.drawable.digitaldigit8, R.drawable.digitaldigit9 };

    private int[] res_img_smallDigits = { R.drawable.digitaldigit0_small, R.drawable.digitaldigit1_small,
            R.drawable.digitaldigit2_small, R.drawable.digitaldigit3_small, R.drawable.digitaldigit4_small,
            R.drawable.digitaldigit5_small, R.drawable.digitaldigit6_small, R.drawable.digitaldigit7_small,
            R.drawable.digitaldigit8_small, R.drawable.digitaldigit9_small };

    private ImageView[] view_timeDisplay = new ImageView[8];

    private Timer _timer = new Timer();
    private TimerTask _task = null;

    private Timekeeper _timekeeper;

    private Button btnStart;

    private int state;
    private static final int STATE_NONE = 0;
    private static final int STATE_COUNTDOWN = 1;
    private static final int STATE_RUNNING = 2;

    private LapArrayAdapter mLapAdapter;
    private LapManager mLapManager = null;
    private ListView mLapList;

    RecordService mService;
    boolean mBound = false;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate");
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        Log.d(TAG, "Enter onActivityCreated...");

        InitTimeDisplayView();

        mLapList = (ListView) getView().findViewById(R.id.listLap);
        this.registerForContextMenu(mLapList);

        btnStart = (Button) getView().findViewById(R.id.btnStart);
        btnStart.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if (state == STATE_NONE) {
                    // detect does device support record ?
                    if (AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO,
                            AudioFormat.ENCODING_PCM_16BIT) < 0) {
                        Context context = getActivity().getApplicationContext();

                        Toast toast = Toast.makeText(context, R.string.strNoRecorder, 5);
                        toast.show();
                        return;
                    }

                    AudioManager audiomanager = (AudioManager) getActivity()
                            .getSystemService(Context.AUDIO_SERVICE);
                    Log.d(TAG, "AudioMode = " + audiomanager.getMode());
                    if (audiomanager.getMode() != AudioManager.MODE_NORMAL) {
                        Context context = getActivity().getApplicationContext();

                        Toast toast = Toast.makeText(context, R.string.strInCalling, 5);
                        toast.show();
                        return;
                    }

                    state = STATE_COUNTDOWN;
                    DialogFragment newFragment = CountdownDialog.NewInstance(5, getTag());
                    newFragment.show(getFragmentManager(), "countdownDialog");

                } else {
                    changeState();
                    state = STATE_NONE;
                    updateRealElapseTime();
                    printTime();

                    // unBind Recordservice
                    if (mBound) {
                        mService.stopRecord();
                        mService.unsetBang();
                        getActivity().unbindService(mConnection);
                        getActivity().stopService(new Intent(getActivity(), RecordService.class));
                        mBound = false;
                    }
                }
                ((MainActivity) getActivity()).EnableTab(1, state == STATE_NONE);
            }
        });

        if (savedInstanceState != null) {

            Log.d(TAG, "savedInstanceState " + savedInstanceState.toString());
            _timekeeper = savedInstanceState.getParcelable(STATE_TIMEKEEPER);
            mLapManager = savedInstanceState.getParcelable(STATE_LAPS);
            state = savedInstanceState.getInt(STATE_STATE);
            mBound = savedInstanceState.getBoolean(STATE_BOUNDING);
            ((MainActivity) getActivity()).EnableTab(1, state == STATE_NONE);

        } else {
            Log.d(TAG, "savedInstanceState == NULL");
            if (_timekeeper == null)
                _timekeeper = new Timekeeper();
            if (mLapManager == null)
                mLapManager = new LapManager();
        }
        InitLapList();

        printTime();
        updateState();

        Log.d(TAG, "Leave OnActivityCreated...");
    }

    public void InitLapList() {

        mLapAdapter = new LapArrayAdapter(getActivity(), mLapManager.get_laps());

        mLapList.setAdapter(mLapAdapter);

    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);

        if (state == STATE_NONE) {
            MenuInflater inflater = getActivity().getMenuInflater();
            inflater.inflate(R.menu.lapitem, menu);
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {

        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();

        switch (item.getItemId()) {
        case R.id.menu_deletelap:
            this.mLapManager.DeleteLap(info.position);
            mLapAdapter.notifyDataSetChanged();
            updateRealElapseTime();
            printTime();
            return true;
        default:
            return super.onContextItemSelected(item);
        }

    }

    @Override
    public void onStart() {
        super.onStart();

        Log.d(TAG, "onStart()...");
        if (_timekeeper.isrunning()) {

            /**
             * because in onStop() we stop the time task, so we need restart
             * the time task
             */
            startTimerTask();
        }

        if (state == this.STATE_RUNNING) {
            // it must bound the service
            Intent intent = new Intent(getActivity(), RecordService.class);
            getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.d(TAG, "onStop()...");
        if (_timekeeper.isrunning()) {
            stopTimerTask();
        }

        if (state == this.STATE_RUNNING) {
            mService.unsetBang();
            getActivity().unbindService(mConnection);
        }
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy()...");
        stopTimerTask();
        super.onDestroy();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState()");
        outState.putParcelable(STATE_TIMEKEEPER, _timekeeper);
        outState.putParcelable(STATE_LAPS, mLapManager);
        outState.putInt(STATE_STATE, state);
        outState.putBoolean(STATE_BOUNDING, mBound);

    }

    protected void changeState() {
        if (_timekeeper.isrunning()) {

            _timekeeper.stop();

        } else {

            _timekeeper.start();

            // Bang Stopwatch does not support restart, so it always start 
            // new stopwatch when click start button
            mLapManager.clear();
            mLapManager.setTmStart(_timekeeper.get_startStamp());
        }
        updateState();
    }

    protected void onLap() {
        mLapManager.appandLap(SystemClock.elapsedRealtime());
        mLapAdapter.notifyDataSetChanged();
    }

    private void updateState() {
        if (_timekeeper.isrunning()) {
            btnStart.setText(R.string.stop);
            startTimerTask();
        } else {
            btnStart.setText(R.string.start);
            stopTimerTask();
        }

    }

    private void InitTimeDisplayView() {
        view_timeDisplay[0] = (ImageView) getView().findViewById(R.id.tenHourImg);
        view_timeDisplay[1] = (ImageView) getView().findViewById(R.id.HourImg);
        view_timeDisplay[2] = (ImageView) getView().findViewById(R.id.tenMinuteImg);
        view_timeDisplay[3] = (ImageView) getView().findViewById(R.id.minuteImg);
        view_timeDisplay[4] = (ImageView) getView().findViewById(R.id.tenSecondImg);
        view_timeDisplay[5] = (ImageView) getView().findViewById(R.id.secondImg);
        view_timeDisplay[6] = (ImageView) getView().findViewById(R.id.tenhundredthImg);
        view_timeDisplay[7] = (ImageView) getView().findViewById(R.id.hundredthImg);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        //return super.onCreateView(inflater, container, savedInstanceState);
        return inflater.inflate(R.layout.stopwatch, container, false);
    }

    private void startTimerTask() {
        if (_task == null) {
            _task = new TimerTask() {
                @Override
                public void run() {
                    updateTime();
                }
            };
            _timer.scheduleAtFixedRate(_task, 0, 100);
        }
    }

    private void stopTimerTask() {
        if (_task != null) {
            _task.cancel();
            _task = null;
        }
    }

    public void updateTime() {
        getActivity().runOnUiThread(new Runnable() {

            @Override
            public void run() {
                printTime();

            }
        });
    }

    /**
     * when stop recod, if have lap, then display the last lap total elapsed time on
     * digiter screen. 
     */
    private void updateRealElapseTime() {
        if (_timekeeper != null && _timekeeper.isrunning() == false) {
            long rt = mLapManager.getTotalElapsedTime();
            if (rt != 0)
                _timekeeper.set_elapsedTime(rt);
        }
    }

    public void printTime() {
        long time = _timekeeper.getElapsedTime();
        //Hours
        view_timeDisplay[0].setImageResource(res_img_Digits[(int) (time / 36000000)]);
        view_timeDisplay[1].setImageResource(res_img_Digits[(int) ((time / 3600000) % 10)]);

        //Mintues
        view_timeDisplay[2].setImageResource(res_img_Digits[(int) (time / 600000 % 6)]);
        view_timeDisplay[3].setImageResource(res_img_Digits[(int) (time / 60000 % 10)]);

        //Seconds
        view_timeDisplay[4].setImageResource(res_img_Digits[(int) (time / 10000 % 6)]);
        view_timeDisplay[5].setImageResource(res_img_Digits[(int) (time / 1000 % 10)]);

        //milliseconds
        view_timeDisplay[6].setImageResource(res_img_smallDigits[(int) (time / 100 % 10)]);
        view_timeDisplay[7].setImageResource(res_img_smallDigits[(int) (time / 10 % 10)]);
    }

    @Override
    public void onCountdownDismiss(boolean done) {

        if (done == true) {

            state = STATE_RUNNING;
            changeState();

            // bind RecordService
            Intent intent = new Intent(getActivity(), RecordService.class);
            getActivity().startService(intent);
            getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

        } else {
            state = STATE_NONE;
        }

    }

    public void onAppWillQuit() {
        if (state == STATE_RUNNING) {
            Intent intent = new Intent(getActivity(), RecordService.class);
            mService.unsetBang();
            getActivity().unbindService(mConnection);
            getActivity().stopService(intent);
            state = STATE_NONE;
        }
    }

    public void onBang() {
        ArrayList<Long> ary = mService.getLaps(mLapManager.get_laps().size());
        synchronized (this) {
            for (Long l : ary) {
                mLapManager.appandLap(l);
            }
            getActivity().runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    mLapAdapter.notifyDataSetChanged();
                }

            });
        }
    }

    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;

            if (state == STATE_RUNNING) {
                onBang();
            }
            mService.setBang(StopwatchFragment.this);
            mService.startRecord();
            Log.d(TAG, "onServiceConnected");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBound = false;

            Log.d(TAG, "onServiceDisconnected");

        }

    };

}