io.github.carlorodriguez.morningritual.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for io.github.carlorodriguez.morningritual.MainActivity.java

Source

/*
 * Copyright 2016 Carlo Eduardo Rodrguez Espino.
 *
 * 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 io.github.carlorodriguez.morningritual;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import android.view.animation.LinearInterpolator;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;

import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView;

public class MainActivity extends AppCompatActivity {

    public static final int DEFAULT_STEP_MINUTE_DURATION = 3;
    public static final int DEFAULT_STEP_SECOND_DURATION = 20;

    private ObjectAnimator mAnimator;
    private MediaPlayer mMediaPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);

        final TextView title = (TextView) findViewById(R.id.title);

        final TextView quote = (TextView) findViewById(R.id.quote);

        final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);

        final MorningRitual morningRitual = new MorningRitual(this);

        final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (morningRitual.isStarted()) {
                    if (morningRitual.isWaiting()) {
                        setNextMorningRitualStep(progressBar, title, quote, morningRitual, fab);
                    } else {
                        stopMorningRitual(progressBar, title, quote, morningRitual, fab);
                    }
                } else {
                    startMorningRitual(progressBar, title, quote, morningRitual, fab);

                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (mAnimator != null) {
            if (mAnimator.isStarted()) {
                mAnimator.removeAllListeners();

                mAnimator.cancel();
            }
            mAnimator = null;
        }

        if (mMediaPlayer != null) {
            mMediaPlayer = null;
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mMediaPlayer != null) {
            mMediaPlayer.release();
        }
    }

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

        setLandscape();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);

        new Handler().post(new Runnable() {
            @Override
            public void run() {
                View view = findViewById(R.id.action_info);

                new MaterialShowcaseView.Builder(MainActivity.this).setTarget(view)
                        .setDismissText(getString(R.string.got_it)).setContentText(getString(R.string.tutorial))
                        .singleUse(getString(R.string.showcase_info_id)).show();
            }
        });

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        switch (id) {
        case R.id.action_settings:
            startActivity(new Intent(this, PreferenceActivity.class));
            return true;
        case R.id.action_info:
            startActivity(new Intent(this, InfoActivity.class));
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private void setLandscape() {
        AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.app_bar);

        String landscape = getLandscape();

        if (landscape.equalsIgnoreCase(getString(R.string.beach))) {
            appBarLayout.setBackgroundResource(R.drawable.landscape_beach_primary);
        } else if (landscape.equalsIgnoreCase(getString(R.string.beach_primary))) {
            appBarLayout.setBackgroundResource(R.drawable.landscape);
        } else if (landscape.equalsIgnoreCase(getString(R.string.snow))) {
            appBarLayout.setBackgroundResource(R.drawable.landscape_snow);
        } else if (landscape.equalsIgnoreCase(getString(R.string.valley))) {
            appBarLayout.setBackgroundResource(R.drawable.landscape_valley);
        } else if (landscape.equalsIgnoreCase(getString(R.string.nature))) {
            appBarLayout.setBackgroundResource(R.drawable.landscape_nature);
        } else if (landscape.equalsIgnoreCase(getString(R.string.mountains))) {
            appBarLayout.setBackgroundResource(R.drawable.landscape_mountains);
        } else if (landscape.equalsIgnoreCase(getString(R.string.dry))) {
            appBarLayout.setBackgroundResource(R.drawable.landscape_dry);
        } else {
            appBarLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimary));
        }
    }

    private boolean vibrateWhenStepFinish() {
        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

        return prefs.getBoolean(getString(R.string.settings_vibration_key), true);
    }

    private boolean soundWhenStepFinish() {
        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

        return prefs.getBoolean(getString(R.string.settings_notification_sound_key), true);
    }

    private boolean automaticallySetStep() {
        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

        return prefs.getBoolean(getString(R.string.settings_auto_set_next_step_key), true);
    }

    private String getLandscape() {
        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

        return prefs.getString(getString(R.string.settings_landscape_key), getString(R.string.beach));
    }

    private void playLegacyNotificationSound() throws IOException {
        AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.sound);

        if (afd == null)
            throw new IOException();

        if (mMediaPlayer != null) {
            mMediaPlayer.release();
        }

        mMediaPlayer = new MediaPlayer();

        mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());

        afd.close();

        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);

        mMediaPlayer.prepare();

        mMediaPlayer.start();
    }

    private void notifyStepFinish() {
        if (vibrateWhenStepFinish()) {
            ((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(500);
        }

        if (soundWhenStepFinish()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                AudioAttributes audioAttributes = new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                        .setUsage(AudioAttributes.USAGE_NOTIFICATION).build();

                AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

                MediaPlayer.create(this, R.raw.sound, audioAttributes, audioManager.generateAudioSessionId())
                        .start();
            } else {
                try {
                    playLegacyNotificationSound();
                } catch (IOException e) {
                    Toast.makeText(MainActivity.this, R.string.cannot_load_notification_sound, Toast.LENGTH_SHORT)
                            .show();
                }
            }
        }
    }

    private long getStepDurationInMillis(MorningRitual morningRitual) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

        int minuteStepTime = DEFAULT_STEP_MINUTE_DURATION;
        int secondStepTime = DEFAULT_STEP_SECOND_DURATION;

        if (morningRitual.isGratitude()) {
            minuteStepTime = prefs.getInt(getString(R.string.settings_gratitude_minute_time_key),
                    MainActivity.DEFAULT_STEP_MINUTE_DURATION);

            secondStepTime = prefs.getInt(getString(R.string.settings_gratitude_second_time_key),
                    MainActivity.DEFAULT_STEP_SECOND_DURATION);
        } else if (morningRitual.isHealth()) {
            minuteStepTime = prefs.getInt(getString(R.string.settings_health_minute_time_key),
                    MainActivity.DEFAULT_STEP_MINUTE_DURATION);

            secondStepTime = prefs.getInt(getString(R.string.settings_health_second_time_key),
                    MainActivity.DEFAULT_STEP_SECOND_DURATION);
        } else if (morningRitual.isVisualization()) {
            minuteStepTime = prefs.getInt(getString(R.string.settings_visualization_minute_time_key),
                    MainActivity.DEFAULT_STEP_MINUTE_DURATION);

            secondStepTime = prefs.getInt(getString(R.string.settings_visualization_second_time_key),
                    MainActivity.DEFAULT_STEP_SECOND_DURATION);
        }

        return (minuteStepTime * 60 * 1000) + (secondStepTime * 1000);
    }

    private void startMorningRitual(final ProgressBar progressBar, final TextView title, final TextView quote,
            final MorningRitual morningRitual, final FloatingActionButton fab) {
        title.setText(getString(R.string.gratitude_title));

        quote.setText(getString(R.string.gratitude_quote));

        morningRitual.reset();

        morningRitual.start();

        mAnimator = setAnimation(progressBar, title, quote, morningRitual, fab);

        mAnimator.start();

        fab.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fab_stop));
    }

    private void stopMorningRitual(final ProgressBar progressBar, final TextView title, final TextView quote,
            final MorningRitual morningRitual, final FloatingActionButton fab) {
        mAnimator.removeAllListeners();

        mAnimator.cancel();

        morningRitual.stop();

        title.setText(getString(R.string.gratitude_title));

        quote.setText(getString(R.string.gratitude_quote));

        progressBar.setProgress(0);

        fab.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fab_play));
    }

    private void updateUIForNextStep(final TextView title, final int titleResId, final TextView quote,
            final int quoteResId, final ProgressBar progressBar, final MorningRitual morningRitual,
            final FloatingActionButton fab) {
        title.setText(getString(titleResId));

        quote.setText(getString(quoteResId));

        progressBar.clearAnimation();

        mAnimator = setAnimation(progressBar, title, quote, morningRitual, fab);

        mAnimator.start();
    }

    private void updateUI(final ProgressBar progressBar, final TextView title, final TextView quote,
            final MorningRitual morningRitual, final FloatingActionButton fab) {
        if (morningRitual.isGratitude()) {
            updateUIForNextStep(title, R.string.gratitude_title, quote, R.string.gratitude_quote, progressBar,
                    morningRitual, fab);
        } else if (morningRitual.isHealth()) {
            updateUIForNextStep(title, R.string.health_title, quote, R.string.health_quote, progressBar,
                    morningRitual, fab);
        } else if (morningRitual.isVisualization()) {
            updateUIForNextStep(title, R.string.visualization_title, quote, R.string.visualization_quote,
                    progressBar, morningRitual, fab);
        } else if (morningRitual.isFinished()) {
            title.setText(getString(R.string.finished));

            quote.setText(getString(R.string.finished_quote));

            fab.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fab_refresh));

            morningRitual.stop();
        }
    }

    private void setNextMorningRitualStep(final ProgressBar progressBar, final TextView title, final TextView quote,
            final MorningRitual morningRitual, final FloatingActionButton fab) {
        if (morningRitual.isAutomatic() || morningRitual.isFinished()) {
            updateUI(progressBar, title, quote, morningRitual, fab);
        } else if (morningRitual.isWaiting()) {
            morningRitual.waitForUser(false);

            updateUI(progressBar, title, quote, morningRitual, fab);

            fab.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fab_stop));
        } else {
            morningRitual.waitForUser(true);

            fab.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fab_navigate_next));
        }
    }

    private ObjectAnimator setAnimation(final ProgressBar progressBar, final TextView title, final TextView quote,
            final MorningRitual morningRitual, final FloatingActionButton fab) {
        final ObjectAnimator animator = ObjectAnimator.ofInt(progressBar, "progress", 0, 200000);

        animator.setDuration(getStepDurationInMillis(morningRitual));

        animator.setInterpolator(new LinearInterpolator());

        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                notifyStepFinish();

                morningRitual.nextStep();

                setNextMorningRitualStep(progressBar, title, quote, morningRitual, fab);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        return animator;
    }

    class MorningRitual {

        private final int GRATITUDE = 0;
        private final int HEALTH = 1;
        private final int VISUALIZATION = 2;
        private final int FINISHED = 3;

        private int current;
        private boolean started;
        private boolean waiting;

        private Activity activity;

        public MorningRitual(Activity activity) {
            this.activity = activity;
            setup();
        }

        private void setup() {
            current = GRATITUDE;
            started = false;
            waiting = false;
        }

        public void reset() {
            setup();
        }

        public void start() {
            started = true;

            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }

        public void stop() {
            reset();

            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }

        public boolean isStarted() {
            return started;
        }

        /**
         * If the app will automatically set next step this returns true.
         *
         * @return Return true if morning ritual will automatically set next
         *         step.
         */
        public boolean isAutomatic() {
            return automaticallySetStep();
        }

        /**
         * Set if the morning ritual needs to wait until the user manually sets
         * the next step.
         *
         * @param wait If morning ritual should wait for user to set next step.
         */
        public void waitForUser(boolean wait) {
            waiting = wait;
        }

        /**
         * If user will manually set next step this returns true if morning
         * ritual is waiting for the user to manually set the next step.
         *
         * @return If the user will manually set next step.
         */
        public boolean isWaiting() {
            return waiting;
        }

        /**
         * Set next step of morning ritual.
         */
        public void nextStep() {
            switch (current) {
            case GRATITUDE:
                current = HEALTH;
                break;
            case HEALTH:
                current = VISUALIZATION;
                break;
            case VISUALIZATION:
                current = FINISHED;
                break;
            default:
                current = FINISHED;
                break;
            }
        }

        public boolean isGratitude() {
            return current == GRATITUDE;
        }

        public boolean isHealth() {
            return current == HEALTH;
        }

        public boolean isVisualization() {
            return current == VISUALIZATION;
        }

        public boolean isFinished() {
            return current == FINISHED;
        }

    }
}