diff --git a/JumpingJack/.google/packaging.yaml b/JumpingJack/.google/packaging.yaml new file mode 100644 index 000000000..46444f231 --- /dev/null +++ b/JumpingJack/.google/packaging.yaml @@ -0,0 +1,18 @@ + +# GOOGLE SAMPLE PACKAGING DATA +# +# This file is used by Google as part of our samples packaging process. +# End users may safely ignore this file. It has no relevance to other systems. +--- +status: PUBLISHED +technologies: [Android] +categories: [Wearable] +languages: [Java] +solutions: [Mobile] +github: android-JumpingJack +level: INTERMEDIATE +icon: screenshots/web-icon.png +apiRefs: + - android:android.hardware.SensorEvent + - android:android.hardware.SensorEventManager +license: apache2 diff --git a/JumpingJack/CONTRIB.md b/JumpingJack/CONTRIB.md new file mode 100644 index 000000000..14a4fcffa --- /dev/null +++ b/JumpingJack/CONTRIB.md @@ -0,0 +1,35 @@ +# How to become a contributor and submit your own code + +## Contributor License Agreements + +We'd love to accept your sample apps and patches! Before we can take them, we +have to jump a couple of legal hurdles. + +Please fill out either the individual or corporate Contributor License Agreement (CLA). + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual CLA] + (https://developers.google.com/open-source/cla/individual). + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA] + (https://developers.google.com/open-source/cla/corporate). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. Once we receive it, we'll be able to +accept your pull requests. + +## Contributing A Patch + +1. Submit an issue describing your proposed change to the repo in question. +1. The repo owner will respond to your issue promptly. +1. If your proposed change is accepted, and you haven't already done so, sign a + Contributor License Agreement (see details above). +1. Fork the desired repo, develop and test your code changes. +1. Ensure that your code adheres to the existing style in the sample to which + you are contributing. Refer to the + [Android Code Style Guide] + (https://source.android.com/source/code-style.html) for the + recommended coding standards for this organization. +1. Ensure that your code has an appropriate set of unit tests which all pass. +1. Submit a pull request. + diff --git a/JumpingJack/CONTRIBUTING.md b/JumpingJack/CONTRIBUTING.md new file mode 100644 index 000000000..faa8b5c68 --- /dev/null +++ b/JumpingJack/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# How to become a contributor and submit your own code + +## Contributor License Agreements + +We'd love to accept your sample apps and patches! Before we can take them, we +have to jump a couple of legal hurdles. + +Please fill out either the individual or corporate Contributor License Agreement (CLA). + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual CLA] + (https://cla.developers.google.com). + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA] + (https://cla.developers.google.com). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. Once we receive it, we'll be able to +accept your pull requests. + +## Contributing A Patch + +1. Submit an issue describing your proposed change to the repo in question. +1. The repo owner will respond to your issue promptly. +1. If your proposed change is accepted, and you haven't already done so, sign a + Contributor License Agreement (see details above). +1. Fork the desired repo, develop and test your code changes. +1. Ensure that your code adheres to the existing style in the sample to which + you are contributing. Refer to the + [Android Code Style Guide] + (https://source.android.com/source/code-style.html) for the + recommended coding standards for this organization. +1. Ensure that your code has an appropriate set of unit tests which all pass. +1. Submit a pull request. + diff --git a/JumpingJack/LICENSE b/JumpingJack/LICENSE new file mode 100644 index 000000000..d5cf8f3aa --- /dev/null +++ b/JumpingJack/LICENSE @@ -0,0 +1,203 @@ +Apache License +-------------- + + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/JumpingJack/NOTICE b/JumpingJack/NOTICE new file mode 100644 index 000000000..0f504823e --- /dev/null +++ b/JumpingJack/NOTICE @@ -0,0 +1,16 @@ + +This sample uses the following software: + +Copyright 2019 The Android Open Source Project + +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. diff --git a/JumpingJack/README.md b/JumpingJack/README.md new file mode 100644 index 000000000..c06f366e3 --- /dev/null +++ b/JumpingJack/README.md @@ -0,0 +1,92 @@ + +Android JumpingJack Sample +=================================== + +A basic sample showing how to use the Gravity sensor on the wearable device +by counting how many jumping jacks you have performed. + +Introduction +------------ + +[SensorEventListener][1] offers you methods used for receiving notifications from the +[SensorManager][2] when sensor values have changed. + +This example counts how many times Jumping Jacks are performed by detecting the value +of the Gravity sensor by the following code: + +```java +@Override +public void onSensorChanged(SensorEvent event) { + detectJump(event.values[0], event.timestamp); +} + +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; + } +} +``` + +The detectJump method above assumes 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 (7.0f). We also consider the up <-> down movement successful if it takes less than +TIME_THRESHOLD_NS (2000000000 nanoseconds). + +[1]: http://developer.android.com/reference/android/hardware/SensorEventListener.html +[2]: http://developer.android.com/reference/android/hardware/SensorManager.html + +Pre-requisites +-------------- + +- Android SDK 28 +- Android Build Tools v28.0.3 +- Android Support Repository + +Screenshots +------------- + +Screenshot + +Getting Started +--------------- + +This sample uses the Gradle build system. To build this project, use the +"gradlew build" command or use "Import Project" in Android Studio. + +Support +------- + +- Google+ Community: https://plus.google.com/communities/105153134372062985968 +- Stack Overflow: http://stackoverflow.com/questions/tagged/android + +If you've found an error in this sample, please file an issue: +https://github.com/googlesamples/android-JumpingJack + +Patches are encouraged, and may be submitted by forking this project and +submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details. + +License +------- + +Copyright 2019 The Android Open Source Project, Inc. + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you 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. diff --git a/JumpingJack/Wearable/build.gradle b/JumpingJack/Wearable/build.gradle new file mode 100644 index 000000000..4a51493c8 --- /dev/null +++ b/JumpingJack/Wearable/build.gradle @@ -0,0 +1,77 @@ + +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.3.2' + } +} + +apply plugin: 'com.android.application' + +repositories { + google() + jcenter() +} + + + +dependencies { + + + + implementation 'com.google.android.gms:play-services-wearable:16.0.1' + + implementation 'com.android.support:support-v13:28.0.0' + + compileOnly 'com.google.android.wearable:wearable:2.4.0' + + implementation 'com.google.android.support:wearable:2.4.0' + +} + +// The sample build uses multiple directories to +// keep boilerplate and common code separate from +// the main sample code. +List dirs = [ + 'main', // main sample code; look here for the interesting stuff. + 'common', // components that are reused by multiple samples + 'template'] // boilerplate code that is generated by the sample template process + +android { + + compileSdkVersion 28 + + buildToolsVersion "28.0.3" + + defaultConfig { + versionCode 1 + versionName "1.0" + + minSdkVersion 24 + + targetSdkVersion 25 + + + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + sourceSets { + main { + dirs.each { dir -> + java.srcDirs "src/${dir}/java" + res.srcDirs "src/${dir}/res" + } + } + androidTest.setRoot('tests') + androidTest.java.srcDirs = ['tests/src'] + + } +} diff --git a/JumpingJack/Wearable/src/main/AndroidManifest.xml b/JumpingJack/Wearable/src/main/AndroidManifest.xml new file mode 100644 index 000000000..eff177c89 --- /dev/null +++ b/JumpingJack/Wearable/src/main/AndroidManifest.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/MainActivity.java b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/MainActivity.java new file mode 100644 index 000000000..f344cfeef --- /dev/null +++ b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/MainActivity.java @@ -0,0 +1,260 @@ +/* + * 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 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.util.Log; +import android.widget.ImageView; + +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager.widget.ViewPager; +import androidx.wear.ambient.AmbientModeSupport; + +import com.example.android.wearable.jumpingjack.fragments.CounterFragment; +import com.example.android.wearable.jumpingjack.fragments.SettingsFragment; + +import java.util.concurrent.TimeUnit; + +/** + * The main activity for the Jumping Jack application. This activity registers itself to receive + * sensor values. + * + * This activity includes a {@link 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 FragmentActivity + implements AmbientModeSupport.AmbientCallbackProvider, SensorEventListener { + + private static final String TAG = "MainActivity"; + + // An up-down movement that takes more than 2 seconds will not be registered (in nanoseconds). + private static final long TIME_THRESHOLD_NS = TimeUnit.SECONDS.toNanos(2); + + /** + * 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 > 0.03 from the hand down + * and hand up threshold we define below, we consider that a successful count. + * + * This is a very rudimentary formula and is by no means production accurate. You will want to + * take into account Y and Z gravity changes to get a truly accurate jumping jack. + * + * This sample is just meant to show how to easily get sensor values and use them. + */ + private static final float HAND_DOWN_GRAVITY_X_THRESHOLD = -.040f; + private static final float HAND_UP_GRAVITY_X_THRESHOLD = -.010f; + + private SensorManager mSensorManager; + private Sensor mSensor; + private long mLastTime = 0; + private int mJumpCounter = 0; + private boolean mHandDown = true; + + + private ViewPager mPager; + private CounterFragment mCounterPage; + private SettingsFragment mSettingPage; + private ImageView mSecondIndicator; + private ImageView mFirstIndicator; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.jumping_jack_layout); + + AmbientModeSupport.attach(this); + + setupViews(); + + mJumpCounter = Utils.getCounterFromPreference(this); + mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); + mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); + } + + private void setupViews() { + mPager = findViewById(R.id.pager); + mFirstIndicator = findViewById(R.id.indicator_0); + mSecondIndicator = 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); + } + + @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) { + // No op. + } + + /** + * A very simple algorithm to detect a successful up-down movement of hand(s). The algorithm + * is based on a delta of the handing being up vs. down and taking less than TIME_THRESHOLD_NS + * to happen. + * + * + * This algorithm isn't intended to be used in production but just to show what's possible with + * sensors. You will want to take into account other components (y and z) and other sensors to + * get a more accurate reading. + */ + private void detectJump(float xGravity, long timestamp) { + + if ((xGravity <= HAND_DOWN_GRAVITY_X_THRESHOLD) + || (xGravity >= HAND_UP_GRAVITY_X_THRESHOLD)) { + + if (timestamp - mLastTime < TIME_THRESHOLD_NS) { + // Hand is down when yValue is negative. + onJumpDetected(xGravity <= HAND_DOWN_GRAVITY_X_THRESHOLD); + } + + mLastTime = timestamp; + } + } + + /** + * Called on detection of a successful down -> up or up -> down movement of hand. + */ + private void onJumpDetected(boolean handDown) { + if (mHandDown != handDown) { + mHandDown = handDown; + + // Only count when the hand is down (means the hand has gone up, then down). + if (mHandDown) { + mJumpCounter++; + setCounter(mJumpCounter); + } + } + } + + /** + * 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) { + mJumpCounter = i; + mCounterPage.setCounter(i); + Utils.saveCounterToPreference(this, i); + if (i > 0 && i % 10 == 0) { + Utils.vibrate(this, 0); + } + } + + public void resetCounter() { + setCounter(0); + } + + /** + * 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; + } + } + + + @Override + public AmbientModeSupport.AmbientCallback getAmbientCallback() { + return new MyAmbientCallback(); + } + + /** Customizes appearance for Ambient mode. (We don't do anything minus default.) */ + private class MyAmbientCallback extends AmbientModeSupport.AmbientCallback { + /** Prepares the UI for ambient mode. */ + @Override + public void onEnterAmbient(Bundle ambientDetails) { + super.onEnterAmbient(ambientDetails); + } + + /** + * Updates the display in ambient mode on the standard interval. Since we're using a custom + * refresh cycle, this method does NOT update the data in the display. Rather, this method + * simply updates the positioning of the data in the screen to avoid burn-in, if the display + * requires it. + */ + @Override + public void onUpdateAmbient() { + super.onUpdateAmbient(); + } + + /** Restores the UI to active (non-ambient) mode. */ + @Override + public void onExitAmbient() { + super.onExitAmbient(); + } + } + +} diff --git a/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/PagerAdapter.java b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/PagerAdapter.java new file mode 100644 index 000000000..d4532e718 --- /dev/null +++ b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/PagerAdapter.java @@ -0,0 +1,54 @@ +/* + * 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 android.app.Fragment; +import android.app.FragmentManager; + +import androidx.legacy.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import java.util.ArrayList; +import java.util.List; + +/** + * A simple adapter for the {@link ViewPager} + */ +public class PagerAdapter extends FragmentPagerAdapter { + + List mFragments = null; + + public PagerAdapter(FragmentManager fm) { + super(fm); + mFragments = new ArrayList(); + } + + @Override + public Fragment getItem(int position) { + return mFragments.get(position); + } + + @Override + public int getCount() { + return mFragments.size(); + } + + public void addFragment(Fragment fragment) { + mFragments.add(fragment); + notifyDataSetChanged(); + } +} diff --git a/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/Utils.java b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/Utils.java new file mode 100644 index 000000000..4db66c9a8 --- /dev/null +++ b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/Utils.java @@ -0,0 +1,67 @@ +/* + * 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 android.content.Context; +import android.content.SharedPreferences; +import android.os.Vibrator; +import android.preference.PreferenceManager; + +/** + * A utility class for some helper methods. + */ +public class Utils { + + private static final int DEFAULT_VIBRATION_DURATION_MS = 200; // in millis + private static final String PREF_KEY_COUNTER = "counter"; + + /** + * Causes device to vibrate for the given duration (in millis). If duration is set to 0, then it + * will use the DEFAULT_VIBRATION_DURATION_MS. + */ + public final static void vibrate(Context context, int duration) { + if (duration == 0) { + duration = DEFAULT_VIBRATION_DURATION_MS; + } + Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + v.vibrate(duration); + } + + /** + * Saves the counter value in the preference storage. If value + * is negative, then the value will be removed from the preferences. + */ + public static void saveCounterToPreference(Context context, int value) { + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context); + if (value < 0) { + // we want to remove + pref.edit().remove(PREF_KEY_COUNTER).apply(); + } else { + pref.edit().putInt(PREF_KEY_COUNTER, value).apply(); + } + } + + /** + * Retrieves the value of counter from preference manager. If no value exists, it will return + * 0. + */ + public static int getCounterFromPreference(Context context) { + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context); + return pref.getInt(PREF_KEY_COUNTER, 0); + } + +} diff --git a/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/CounterFragment.java b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/CounterFragment.java new file mode 100644 index 000000000..c55eb9b04 --- /dev/null +++ b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/CounterFragment.java @@ -0,0 +1,94 @@ +/* + * 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.fragments; + +import com.example.android.wearable.jumpingjack.R; +import com.example.android.wearable.jumpingjack.Utils; + +import android.app.Fragment; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * A simple fragment for showing the count + */ +public class CounterFragment extends Fragment { + + private static final long ANIMATION_INTERVAL_MS = 500; // in milliseconds + private TextView mCounterText; + private Timer mAnimationTimer; + private Handler mHandler; + private TimerTask mAnimationTask; + private boolean up = false; + private Drawable mDownDrawable; + private Drawable mUpDrawable; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.counter_layout, container, false); + mDownDrawable = getResources().getDrawable(R.drawable.jump_down_50); + mUpDrawable = getResources().getDrawable(R.drawable.jump_up_50); + mCounterText = (TextView) view.findViewById(R.id.counter); + mCounterText.setCompoundDrawablesWithIntrinsicBounds(mUpDrawable, null, null, null); + setCounter(Utils.getCounterFromPreference(getActivity())); + mHandler = new Handler(); + startAnimation(); + return view; + } + + private void startAnimation() { + mAnimationTask = new TimerTask() { + @Override + public void run() { + mHandler.post(new Runnable() { + @Override + public void run() { + mCounterText.setCompoundDrawablesWithIntrinsicBounds( + up ? mUpDrawable : mDownDrawable, null, null, null); + up = !up; + } + }); + } + }; + mAnimationTimer = new Timer(); + mAnimationTimer.scheduleAtFixedRate(mAnimationTask, ANIMATION_INTERVAL_MS, + ANIMATION_INTERVAL_MS); + } + + public void setCounter(String text) { + mCounterText.setText(text); + } + + public void setCounter(int i) { + setCounter(i < 0 ? "0" : String.valueOf(i)); + } + + @Override + public void onDetach() { + mAnimationTimer.cancel(); + super.onDetach(); + } +} diff --git a/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/SettingsFragment.java b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/SettingsFragment.java new file mode 100644 index 000000000..771abd3ea --- /dev/null +++ b/JumpingJack/Wearable/src/main/java/com/example/android/wearable/jumpingjack/fragments/SettingsFragment.java @@ -0,0 +1,48 @@ +/* + * 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.fragments; + +import com.example.android.wearable.jumpingjack.MainActivity; +import com.example.android.wearable.jumpingjack.R; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +/** + * A simple fragment that shows a button to reset the counter + */ +public class SettingsFragment extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.setting_layout, container, false); + Button button = (Button) view.findViewById(R.id.btn); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ((MainActivity) getActivity()).resetCounter(); + } + }); + return view; + } + +} diff --git a/JumpingJack/Wearable/src/main/res/drawable-hdpi/btn_reset_normal_200.png b/JumpingJack/Wearable/src/main/res/drawable-hdpi/btn_reset_normal_200.png new file mode 100644 index 000000000..e58520274 Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable-hdpi/btn_reset_normal_200.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable-hdpi/btn_reset_pressed_200.png b/JumpingJack/Wearable/src/main/res/drawable-hdpi/btn_reset_pressed_200.png new file mode 100644 index 000000000..0b83b6d66 Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable-hdpi/btn_reset_pressed_200.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable-hdpi/ic_launcher.png b/JumpingJack/Wearable/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..2d0c37d0e Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable-mdpi/ic_launcher.png b/JumpingJack/Wearable/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..3211c9e8b Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png b/JumpingJack/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..4ead8a29f Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png b/JumpingJack/Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..8b357e4d5 Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable-xxxhdpi/ic_launcher.png b/JumpingJack/Wearable/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..da3c00a9a Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable/empty_10.png b/JumpingJack/Wearable/src/main/res/drawable/empty_10.png new file mode 100644 index 000000000..78ee76bb1 Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable/empty_10.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable/full_10.png b/JumpingJack/Wearable/src/main/res/drawable/full_10.png new file mode 100644 index 000000000..53b799ebc Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable/full_10.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable/jump_down_50.png b/JumpingJack/Wearable/src/main/res/drawable/jump_down_50.png new file mode 100644 index 000000000..28980f808 Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable/jump_down_50.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable/jump_up_50.png b/JumpingJack/Wearable/src/main/res/drawable/jump_up_50.png new file mode 100644 index 000000000..86dcef593 Binary files /dev/null and b/JumpingJack/Wearable/src/main/res/drawable/jump_up_50.png differ diff --git a/JumpingJack/Wearable/src/main/res/drawable/submit_button.xml b/JumpingJack/Wearable/src/main/res/drawable/submit_button.xml new file mode 100644 index 000000000..2ab9ba565 --- /dev/null +++ b/JumpingJack/Wearable/src/main/res/drawable/submit_button.xml @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/JumpingJack/Wearable/src/main/res/layout/counter_layout.xml b/JumpingJack/Wearable/src/main/res/layout/counter_layout.xml new file mode 100644 index 000000000..e443e342b --- /dev/null +++ b/JumpingJack/Wearable/src/main/res/layout/counter_layout.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/JumpingJack/Wearable/src/main/res/layout/jumping_jack_layout.xml b/JumpingJack/Wearable/src/main/res/layout/jumping_jack_layout.xml new file mode 100644 index 000000000..0d0a67b8d --- /dev/null +++ b/JumpingJack/Wearable/src/main/res/layout/jumping_jack_layout.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + diff --git a/JumpingJack/Wearable/src/main/res/layout/setting_layout.xml b/JumpingJack/Wearable/src/main/res/layout/setting_layout.xml new file mode 100644 index 000000000..129840958 --- /dev/null +++ b/JumpingJack/Wearable/src/main/res/layout/setting_layout.xml @@ -0,0 +1,40 @@ + + + + + +