| /* |
| * 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.example.android.wearable.jumpingjack; |
| |
| import com.example.android.wearable.jumpingjack.fragments.CounterFragment; |
| import com.example.android.wearable.jumpingjack.fragments.SettingsFragment; |
| |
| import android.app.Activity; |
| import android.content.Context; |
| import android.hardware.Sensor; |
| import android.hardware.SensorEvent; |
| import android.hardware.SensorEventListener; |
| import android.hardware.SensorManager; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.support.v4.view.ViewPager; |
| import android.util.Log; |
| import android.view.WindowManager; |
| import android.widget.ImageView; |
| |
| import java.util.Timer; |
| import java.util.TimerTask; |
| |
| /** |
| * 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. |
| * |
| * 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. |
| */ |
| public class MainActivity extends Activity |
| implements SensorEventListener { |
| |
| private static final String TAG = "JJMainActivity"; |
| |
| /** How long to keep the screen on when no activity is happening **/ |
| private static final long SCREEN_ON_TIMEOUT_MS = 20000; // in milliseconds |
| |
| /** an up-down movement that takes more than this will not be registered as such **/ |
| private static final long TIME_THRESHOLD_NS = 2000000000; // in nanoseconds (= 2sec) |
| |
| /** |
| * Earth gravity is around 9.8 m/s^2 but user may not completely direct his/her hand vertical |
| * during the exercise so we leave some room. Basically if the x-component of gravity, as |
| * measured by the Gravity sensor, changes with a variation (delta) > GRAVITY_THRESHOLD, |
| * we consider that a successful count. |
| */ |
| private static final float GRAVITY_THRESHOLD = 7.0f; |
| |
| private SensorManager mSensorManager; |
| private Sensor mSensor; |
| private long mLastTime = 0; |
| private boolean mUp = false; |
| private int mJumpCounter = 0; |
| private ViewPager mPager; |
| private CounterFragment mCounterPage; |
| private SettingsFragment mSettingPage; |
| private ImageView mSecondIndicator; |
| private ImageView mFirstIndicator; |
| private Timer mTimer; |
| private TimerTask mTimerTask; |
| private Handler mHandler; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| setContentView(R.layout.jj_layout); |
| setupViews(); |
| mHandler = new Handler(); |
| mJumpCounter = Utils.getCounterFromPreference(this); |
| getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); |
| renewTimer(); |
| mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); |
| mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); |
| } |
| |
| private void setupViews() { |
| mPager = (ViewPager) findViewById(R.id.pager); |
| mFirstIndicator = (ImageView) findViewById(R.id.indicator_0); |
| mSecondIndicator = (ImageView) findViewById(R.id.indicator_1); |
| final PagerAdapter adapter = new PagerAdapter(getFragmentManager()); |
| mCounterPage = new CounterFragment(); |
| mSettingPage = new SettingsFragment(); |
| adapter.addFragment(mCounterPage); |
| adapter.addFragment(mSettingPage); |
| setIndicator(0); |
| mPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { |
| @Override |
| public void onPageScrolled(int i, float v, int i2) { |
| } |
| |
| @Override |
| public void onPageSelected(int i) { |
| setIndicator(i); |
| renewTimer(); |
| } |
| |
| @Override |
| public void onPageScrollStateChanged(int i) { |
| } |
| }); |
| |
| mPager.setAdapter(adapter); |
| } |
| |
| @Override |
| protected void onResume() { |
| super.onResume(); |
| if (mSensorManager.registerListener(this, mSensor, |
| SensorManager.SENSOR_DELAY_NORMAL)) { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Successfully registered for the sensor updates"); |
| } |
| } |
| } |
| |
| @Override |
| protected void onPause() { |
| super.onPause(); |
| mSensorManager.unregisterListener(this); |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(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) > GRAVITY_THRESHOLD)) { |
| if(timestamp - mLastTime < TIME_THRESHOLD_NS && mUp != (xValue > 0)) { |
| onJumpDetected(!mUp); |
| } |
| mUp = xValue > 0; |
| mLastTime = 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; |
| } |
| mJumpCounter++; |
| setCounter(mJumpCounter); |
| renewTimer(); |
| } |
| |
| /** |
| * Updates the counter on UI, saves it to preferences and vibrates the watch when counter |
| * reaches a multiple of 10. |
| */ |
| private void setCounter(int i) { |
| mCounterPage.setCounter(i); |
| Utils.saveCounterToPreference(this, i); |
| if (i > 0 && i % 10 == 0) { |
| Utils.vibrate(this, 0); |
| } |
| } |
| |
| public void resetCounter() { |
| setCounter(0); |
| renewTimer(); |
| } |
| |
| /** |
| * Starts a timer to clear the flag FLAG_KEEP_SCREEN_ON. |
| */ |
| private void renewTimer() { |
| if (null != mTimer) { |
| mTimer.cancel(); |
| } |
| mTimerTask = new TimerTask() { |
| @Override |
| public void run() { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, |
| "Removing the FLAG_KEEP_SCREEN_ON flag to allow going to background"); |
| } |
| resetFlag(); |
| } |
| }; |
| mTimer = new Timer(); |
| mTimer.schedule(mTimerTask, SCREEN_ON_TIMEOUT_MS); |
| } |
| |
| /** |
| * Resets the FLAG_KEEP_SCREEN_ON flag so activity can go into background. |
| */ |
| private void resetFlag() { |
| mHandler.post(new Runnable() { |
| @Override |
| public void run() { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Resetting FLAG_KEEP_SCREEN_ON flag to allow going to background"); |
| } |
| getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); |
| finish(); |
| } |
| }); |
| } |
| |
| /** |
| * Sets the page indicator for the ViewPager. |
| */ |
| private void setIndicator(int i) { |
| switch (i) { |
| case 0: |
| mFirstIndicator.setImageResource(R.drawable.full_10); |
| mSecondIndicator.setImageResource(R.drawable.empty_10); |
| break; |
| case 1: |
| mFirstIndicator.setImageResource(R.drawable.empty_10); |
| mSecondIndicator.setImageResource(R.drawable.full_10); |
| break; |
| } |
| } |
| |
| |
| } |