com.hyung.jin.seo.getup.wear.G3tUpActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.hyung.jin.seo.getup.wear.G3tUpActivity.java

Source

/*
 * Copyright (C) 2014 Google Inc. All Rights Reserved.
 *
 * 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.hyung.jin.seo.getup.wear;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;
import com.hyung.jin.seo.getup.R;
import com.hyung.jin.seo.getup.wear.fragments.AbstractFragment;
import com.hyung.jin.seo.getup.wear.fragments.CounterFragment;
import com.hyung.jin.seo.getup.wear.fragments.DisplayFragment;
import com.hyung.jin.seo.getup.wear.fragments.ExerciseFragment;
import com.hyung.jin.seo.getup.wear.utils.G3tUpConstants;

import java.util.concurrent.TimeUnit;

/**
 * The main activity for the Jumping Jack application. This activity registers itself to receive
 * sensor values. Since on wearable devices a full screen activity is very short-lived, we set the
 * FLAG_KEEP_SCREEN_ON to give user adequate time for taking actions but since we don't want to
 * keep screen on for an extended period of time, there is a SCREEN_ON_TIMEOUT_MS that is enforced
 * if no interaction is discovered.
 * <p>
 * This activity includes a {@link android.support.v4.view.ViewPager} with two pages, one that
 * shows the current count and one that allows user to reset the counter. the current value of the
 * counter is persisted so that upon re-launch, the counter picks up from the last value. At any
 * stage, user can set this counter to 0.
 * <p>
 * What to do ?
 * 1. start timer
 * 2. when timer reaches to 0
 * 2-1 trigger alarm & vibration on phone
 * 2-2 start animation
 * 3. update exercise count
 * 4. when count reaches to goal
 * 4-1 trigger stop alarm & vibration on phone
 * 4-2 display good message
 */
public class G3tUpActivity extends Activity implements SensorEventListener, GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    private SensorManager sensorManager;
    private Sensor sensor;
    private long lastTime = 0;
    private boolean up;

    private int jumpCounter = 0;

    private int status = 0;

    private AbstractFragment fragment;

    private long timerDuration;

    private int exerciseCount;

    private String version = "v14";

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

        status = G3tUpConstants.COUNTER_STATE; // first fragment
        selectFragment();
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
    }

    // load info from SharedPreference
    private void setUpThreshold() {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        timerDuration = Long.parseLong(preferences.getString("timerSet", "5"));
        exerciseCount = Integer.parseInt(preferences.getString("exerciseSet", "5"));
    }

    // determine displaying fragment based on status
    private void selectFragment() {
        fragment = null;
        // If CounterFragment is about to display, trigger timer as well
        if (status == G3tUpConstants.COUNTER_STATE) {
            fragment = new CounterFragment();
            CountDownTimer timer = new MyCountDownTimer(G3tUpConstants.SECOND * timerDuration * 60,
                    G3tUpConstants.SECOND);
            timer.start();

            // ExerciseFragment
        } else if (status == G3tUpConstants.EXERCISE_STATE) {

            fragment = new ExerciseFragment();

            // DisplayFragment
        } else {

            fragment = new DisplayFragment();
        }
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ftx = fm.beginTransaction();
        ftx.replace(R.id.fragment_place, fragment);
        ftx.commit();
    }

    // event handler when button pressed. this is just for testing purpose
    public void clickButton(View view) {
        if (status == G3tUpConstants.COUNTER_STATE) {

        } else if (status == G3tUpConstants.EXERCISE_STATE) {
            increaseCount();
        } else {
            // dismiss
            Log.d(G3tUpConstants.TAG, "Dismiss Activity ?");
        }
    }

    private void increaseCount() {
        jumpCounter++;
        Log.d(G3tUpConstants.TAG, "Exercise - " + jumpCounter);

        if (jumpCounter >= exerciseCount) {
            fragment.stopAction();

            message = G3tUpConstants.ALARM_STOP;
            triggerActionOnPhone();

            status = G3tUpConstants.DISPLAY_STATE;
            selectFragment();
            return;
        }
        fragment.setText(jumpCounter);
    }

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

        // update threshold
        setUpThreshold();

        if (sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL)) {
            if (Log.isLoggable(G3tUpConstants.TAG, Log.DEBUG)) {
                Log.d(G3tUpConstants.TAG, "Successfully registered for the sensor updates");
            }
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
        if (Log.isLoggable(G3tUpConstants.TAG, Log.DEBUG)) {
            Log.d(G3tUpConstants.TAG, "Unregistered for sensor events");
        }
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        detectJump(event.values[0], event.timestamp);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }

    /**
     * A simple algorithm to detect a successful up-down movement of hand(s). The algorithm is
     * based on the assumption that when a person is wearing the watch, the x-component of gravity
     * as measured by the Gravity Sensor is +9.8 when the hand is downward and -9.8 when the hand
     * is upward (signs are reversed if the watch is worn on the right hand). Since the upward or
     * downward may not be completely accurate, we leave some room and instead of 9.8, we use
     * GRAVITY_THRESHOLD. We also consider the up <-> down movement successful if it takes less than
     * TIME_THRESHOLD_NS.
     */
    private void detectJump(float xValue, long timestamp) {
        if ((Math.abs(xValue) > G3tUpConstants.GRAVITY_THRESHOLD)) {
            if (timestamp - lastTime < G3tUpConstants.TIME_THRESHOLD_NS && up != (xValue > 0)) {
                onJumpDetected(!up);
            }
            up = xValue > 0;
            lastTime = timestamp;
        }
    }

    /**
     * Called on detection of a successful down -> up or up -> down movement of hand.
     */
    private void onJumpDetected(boolean up) {
        // we only count a pair of up and down as one successful movement
        if (up) {
            return;
        }
        // update screen
        increaseCount();
    }

    // This is timer class for CounterFragment
    public class MyCountDownTimer extends CountDownTimer {
        public MyCountDownTimer(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

        @Override
        public void onTick(long millisUntilFinished) {
            //            Log.e(G3tUpConstants.TAG, "" + millisUntilFinished/1000);
            long seconds = (long) millisUntilFinished / 1000;
            String remain = String.format("%d Min %d Sec", TimeUnit.SECONDS.toMinutes(seconds),
                    TimeUnit.SECONDS.toSeconds(seconds)
                            - TimeUnit.MINUTES.toSeconds(TimeUnit.SECONDS.toMinutes(seconds))

            );
            fragment.setText(remain);
        }

        @Override
        public void onFinish() {
            message = G3tUpConstants.ALARM_START;
            triggerActionOnPhone();

            status = G3tUpConstants.EXERCISE_STATE;
            selectFragment();
        }
    }

    ///////////////////////////////////////////////////////////////////////////////

    GoogleApiClient googleApiClient;
    String message;

    private void prepareCommunication() {
        GoogleApiClient.Builder builder = new GoogleApiClient.Builder(this);
        builder.addApi(Wearable.API);
        builder.addConnectionCallbacks(this);
        builder.addOnConnectionFailedListener(this);
        googleApiClient = builder.build();
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.d(G3tUpConstants.TAG, "onConnected()");
        //        triggerActionOnPhone();
    }

    public void triggerActionOnPhone() {
        if (googleApiClient != null && googleApiClient.isConnected()) {
            new SendMessageToDataLayer(G3tUpConstants.COMMUNICATIO_PATH, message).start();
            Log.d(G3tUpConstants.TAG, "Communication thread has triggered");
        } else {
            Log.e(G3tUpConstants.TAG, "Failed to send messages");
        }
    }

    public class SendMessageToDataLayer extends Thread {
        String path;
        String message;

        public SendMessageToDataLayer(String path, String message) {
            this.path = path;
            this.message = message;
        }

        @Override
        public void run() {
            NodeApi.GetConnectedNodesResult nodesResult = Wearable.NodeApi.getConnectedNodes(googleApiClient)
                    .await();
            for (Node node : nodesResult.getNodes()) {
                MessageApi.SendMessageResult messageResult = Wearable.MessageApi
                        .sendMessage(googleApiClient, node.getId(), path, message.getBytes()).await();
                if (messageResult.getStatus().isSuccess()) {
                    Log.d(G3tUpConstants.TAG, "Sent to " + node.getDisplayName());
                    Log.d(G3tUpConstants.TAG, "Node Id is " + node.getId());
                    Log.d(G3tUpConstants.TAG, "Node size is " + nodesResult.getNodes().size());
                } else {
                    Log.e(G3tUpConstants.TAG, "Error while sending message");
                }
            }
        }
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

    }

    @Override
    protected void onStart() {
        super.onStart();
        googleApiClient.connect();
        Log.d(G3tUpConstants.TAG, "onStop()");
    }

    @Override
    protected void onStop() {
        if (googleApiClient != null && googleApiClient.isConnected()) {
            googleApiClient.disconnect();
        }
        super.onStop();
        Log.d(G3tUpConstants.TAG, "onStop()");
    }
}