mrksbrg/RacketGhost

View on GitHub
app/src/main/java/com/markusborg/ui/MainActivity.java

Summary

Maintainability
A
3 hrs
Test Coverage
package com.markusborg.ui;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;

import com.markusborg.logic.LogHandler;

import java.util.ArrayList;
import java.util.List;

/**
 * Main activity that displays the initial settings dialog.
 *
 * @author  Markus Borg
 * @since   2015-07-29
 */
public class MainActivity extends AppCompatActivity {

    private Context mAppContext;
    private Spinner mSpinner;
    private SeekBar mSeekBarSets, mSeekBarReps, mSeekBarInterval, mSeekBarBreak;
    private EditText mTxtSets, mTxtReps, mTxtInterval, mTxtBreak, mTxtHistory;
    private CheckBox mChk6Points, mChkAudio;
    private LogHandler mLogger;
    private SharedPreferences mSharedPrefs;
    private AudioManager mAudioManager;
    private SoundPool mSoundPool;
    private int[] mSoundIDs; // two sounds, squash and badminton
    private boolean mLoaded;

    private static final String PREFERENCES = "GhostingPrefs";
    public static final String ISSQUASH = "IS_SQUASH";
    public static final String SETS = "NBR_SETS";
    public static final String REPS = "NBR_REPS";
    public static final String INTERVAL = "TIME_INTERVAL";
    public static final String BREAK = "TIME_BREAK";
    public static final String IS6POINTS = "IS_6POINTS";
    public static final String ISAUDIO = "IS_AUDIO";
    public final static String FILENAME = "history.log";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAppContext = getApplicationContext();
        setGUIComponents();
        initSounds();

        // Load previous setting
        loadSharedPrefs();

        mLogger = new LogHandler(mAppContext);
        displayHistory();


        final Button btnGo = (Button) findViewById(R.id.btnGo);
        btnGo.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // Perform action on click
                Intent ghostingIntent = new Intent(mAppContext, GhostingActivity.class);

                boolean squashMode = mSpinner.getSelectedItemPosition() == 0; // squash is the first
                int sets = mSeekBarSets.getProgress() + 1; // add one, due to slider starts at 1
                int reps = mSeekBarReps.getProgress() + 1; // add one, due to slider starts at 1
                int interval = (mSeekBarInterval.getProgress() + 10) * 100; // from ds to ms
                int breakTime = mSeekBarBreak.getProgress();
                boolean is6Points = mChk6Points.isChecked();
                boolean isAudio = mChkAudio.isChecked();

                ghostingIntent.putExtra(ISSQUASH, squashMode);
                ghostingIntent.putExtra(SETS, sets);
                ghostingIntent.putExtra(REPS, reps);
                ghostingIntent.putExtra(INTERVAL, interval);
                ghostingIntent.putExtra(BREAK, breakTime);
                ghostingIntent.putExtra(IS6POINTS, is6Points);
                ghostingIntent.putExtra(ISAUDIO, isAudio);

                // Save the settings as SharedPreferences
                SharedPreferences.Editor editor = mSharedPrefs.edit();
                editor.putBoolean(ISSQUASH, squashMode);
                editor.putInt(SETS, sets);
                editor.putInt(REPS, reps);
                editor.putInt(INTERVAL, interval);
                editor.putInt(BREAK, breakTime);
                editor.putBoolean(IS6POINTS, is6Points);
                editor.putBoolean(ISAUDIO, isAudio);
                editor.apply();

                // Play sound corresponding to selected sport
                if (mLoaded) {
                    if (squashMode) {
                        mSoundPool.play(mSoundIDs[0], 1.0f, 1.0f, 1, 0, 1.0f);
                    }
                    else {
                        mSoundPool.play(mSoundIDs[1], 1.0f, 1.0f, 1, 0, 1.0f);
                    }
                }

                startActivity(ghostingIntent);
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        switch (id) {
            case R.id.action_help:
                HelpBox.Show(MainActivity.this);
                break;
            case R.id.action_about:
                AboutBox.Show(MainActivity.this);
                break;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onResume() {
        super.onResume();
        displayHistory();
    }

    /**
     * Set all GUI components.
     */
    private void setGUIComponents() {
        mTxtSets = (EditText) findViewById(R.id.txtSets);
        mTxtReps = (EditText) findViewById(R.id.txtReps);
        mTxtInterval = (EditText) findViewById(R.id.txtInterval);
        mTxtBreak = (EditText) findViewById(R.id.txtBreak);
        mChk6Points = (CheckBox) findViewById(R.id.chk6Point);
        mChkAudio = (CheckBox) findViewById(R.id.chkAudio);
        mTxtHistory = (EditText) findViewById(R.id.txtHistory);

        // Squash/Badminton spinner. No action listener needed.
        mSpinner = (Spinner) findViewById(R.id.spinner);
        List<String> list = new ArrayList<String>();
        list.add("Squash");
        list.add("Badminton");
        ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_spinner_item, list);
        dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        mSpinner.setAdapter(dataAdapter);

        // SeekBars
        mSeekBarSets = (SeekBar) findViewById(R.id.seekBarSets);
        mSeekBarSets.setOnSeekBarChangeListener(new SeekBarListener());
        mSeekBarReps = (SeekBar) findViewById(R.id.seekBarReps);
        mSeekBarReps.setOnSeekBarChangeListener(new SeekBarListener());
        mSeekBarInterval = (SeekBar) findViewById(R.id.seekBarInterval);
        mSeekBarInterval.setOnSeekBarChangeListener(new SeekBarListener());
        mSeekBarBreak = (SeekBar) findViewById(R.id.seekBarBreak);
        mSeekBarBreak.setOnSeekBarChangeListener(new SeekBarListener());
    }

    /**
     * Load shared preferences containing the previous setting. If none are available, return false.
     *u
     * @return True if successful, otherwise false.
     */
    private boolean loadSharedPrefs() {
        mSharedPrefs = getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
        int prevSets = mSharedPrefs.getInt(SETS, -1);
        if (prevSets != -1) {
            if (mSharedPrefs.getBoolean(ISSQUASH, true)) {
                mSpinner.setSelection(0);
            } else {
                mSpinner.setSelection(1);
            }
            // set all SeekBars, adjusted to take care of non-zero min values
            mTxtSets.setText("Sets: " + prevSets);
            mSeekBarSets.setProgress(prevSets-1);
            int prevReps = mSharedPrefs.getInt(REPS, 15);
            mTxtReps.setText("Reps: " + prevReps);
            mSeekBarReps.setProgress(prevReps-1);
            int prevInt = mSharedPrefs.getInt(INTERVAL, 50);
            mTxtInterval.setText("Interval (s): " + prevInt);
            mSeekBarInterval.setProgress((prevInt / 100) - 10); // from ms to ds
            int prevBreak = mSharedPrefs.getInt(BREAK, 15);
            mTxtBreak.setText("Break btw. sets (s): " + prevBreak);
            mSeekBarBreak.setProgress(prevBreak);
            mChk6Points.setChecked(mSharedPrefs.getBoolean(IS6POINTS, true));
            mChkAudio.setChecked(mSharedPrefs.getBoolean(ISAUDIO, true));
        }
        return prevSets != -1;
    }

    /**
     * Display the three latest ghosting sessions.
     */
    private void displayHistory() {
        mTxtHistory.setText("Recent history:\n" + mLogger.getFromLog(3));
    }

    private void initSounds() {
        mSoundIDs = new int[6];
        mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
        int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVolume, 0);

        // Take care of the deprecated SoundPool constructor
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            createNewSoundPool();
        } else {
            createOldSoundPool();
        }

        // Load the actual sounds
        mSoundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                mLoaded = true;
            }
        });
        mSoundIDs[0] = mSoundPool.load(this, R.raw.squash, 1);
        mSoundIDs[1] = mSoundPool.load(this, R.raw.badminton, 1);
    }

    /**
     * Create a new SoundPool from Lollipop and later Android versions
     */
    @TargetApi(android.os.Build.VERSION_CODES.LOLLIPOP)
    private void createNewSoundPool(){
        AudioAttributes attributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_GAME)
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .build();
        mSoundPool = new SoundPool.Builder()
                .setAudioAttributes(attributes)
                .build();
    }

    /**
     * Create a new SoundPool using the deprecated constructor for Android versions before Lollipop.
     */
    @SuppressWarnings("deprecation")
    protected void createOldSoundPool(){
        mSoundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
    }

    private class SeekBarListener implements SeekBar.OnSeekBarChangeListener {

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,
                                      boolean fromUser) {
            TextView tmp = null;
            switch (seekBar.getId()) {
                case R.id.seekBarSets:
                    tmp = (TextView) findViewById(R.id.txtSets);
                    tmp.setText("Sets: " + (seekBar.getProgress() + 1));
                    break;
                case R.id.seekBarReps:
                    tmp = (TextView) findViewById(R.id.txtReps);
                    tmp.setText("Reps: " + (seekBar.getProgress() + 1));
                    break;
                case R.id.seekBarInterval:
                    tmp = (TextView) findViewById(R.id.txtInterval);
                    tmp.setText("Interval (s): " + (((float) seekBar.getProgress() / 10.0) + 1));
                    break;
                case R.id.seekBarBreak:
                    tmp = (TextView) findViewById(R.id.txtBreak);
                    tmp.setText("Break btw. sets (s): " + seekBar.getProgress());
                    break;
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
        }
    }
}