merge in lmp-release history after reset to d165d7b010232a85ca66a9c0550b259eb8d95b3d
diff --git a/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java b/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
index 19ec587..a97da80 100644
--- a/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
+++ b/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
@@ -160,9 +160,9 @@
private Size mPreviewSize;
/**
- * {@link CameraDevice.StateListener} is called when {@link CameraDevice} changes its state.
+ * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
*/
- private final CameraDevice.StateListener mStateListener = new CameraDevice.StateListener() {
+ private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice cameraDevice) {
@@ -236,15 +236,15 @@
/**
* The current state of camera state for taking pictures.
*
- * @see #mCaptureListener
+ * @see #mCaptureCallback
*/
private int mState = STATE_PREVIEW;
/**
- * A {@link CameraCaptureSession.CaptureListener} that handles events related to JPEG capture.
+ * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
*/
- private CameraCaptureSession.CaptureListener mCaptureListener
- = new CameraCaptureSession.CaptureListener() {
+ private CameraCaptureSession.CaptureCallback mCaptureCallback
+ = new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch (mState) {
@@ -449,7 +449,7 @@
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
- manager.openCamera(mCameraId, mStateListener, mBackgroundHandler);
+ manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -517,7 +517,7 @@
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
- new CameraCaptureSession.StateListener() {
+ new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
@@ -534,7 +534,7 @@
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
- mCaptureListener, mBackgroundHandler);
+ mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -600,9 +600,9 @@
// This is how to tell the camera to lock focus.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_START);
- // Tell #mCaptureListener to wait for the lock.
+ // Tell #mCaptureCallback to wait for the lock.
mState = STATE_WAITING_LOCK;
- mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureListener,
+ mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
@@ -611,16 +611,16 @@
/**
* Run the precapture sequence for capturing a still image. This method should be called when we
- * get a response in {@link #mCaptureListener} from {@link #lockFocus()}.
+ * get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
*/
private void runPrecaptureSequence() {
try {
// This is how to tell the camera to trigger.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
- // Tell #mCaptureListener to wait for the precapture sequence to be set.
+ // Tell #mCaptureCallback to wait for the precapture sequence to be set.
mState = STATE_WAITING_PRECAPTURE;
- mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureListener,
+ mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
@@ -629,7 +629,7 @@
/**
* Capture a still picture. This method should be called when we get a response in
- * {@link #mCaptureListener} from both {@link #lockFocus()}.
+ * {@link #mCaptureCallback} from both {@link #lockFocus()}.
*/
private void captureStillPicture() {
try {
@@ -652,8 +652,8 @@
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
- CameraCaptureSession.CaptureListener captureListener
- = new CameraCaptureSession.CaptureListener() {
+ CameraCaptureSession.CaptureCallback CaptureCallback
+ = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
@@ -664,7 +664,7 @@
};
mCaptureSession.stopRepeating();
- mCaptureSession.capture(captureBuilder.build(), captureListener, null);
+ mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
@@ -680,11 +680,11 @@
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
- mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureListener,
+ mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
// After this, the camera will go back to the normal state of preview.
mState = STATE_PREVIEW;
- mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureListener,
+ mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
diff --git a/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java b/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java
index 2f3fe91..903dd18 100644
--- a/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java
+++ b/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java
@@ -144,9 +144,9 @@
private boolean mOpeningCamera;
/**
- * {@link CameraDevice.StateListener} is called when {@link CameraDevice} changes its status.
+ * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its status.
*/
- private CameraDevice.StateListener mStateListener = new CameraDevice.StateListener() {
+ private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice cameraDevice) {
@@ -239,7 +239,7 @@
}
/**
- * Tries to open a {@link CameraDevice}. The result is listened by `mStateListener`.
+ * Tries to open a {@link CameraDevice}. The result is listened by `mStateCallback`.
*/
private void openCamera() {
final Activity activity = getActivity();
@@ -260,7 +260,7 @@
} else {
mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
}
- manager.openCamera(cameraId, mStateListener, null);
+ manager.openCamera(cameraId, mStateCallback, null);
} catch (CameraAccessException e) {
Toast.makeText(activity, "Cannot access the camera.", Toast.LENGTH_SHORT).show();
activity.finish();
@@ -287,7 +287,7 @@
List<Surface> surfaces = new ArrayList<Surface>();
surfaces.add(surface);
mPreviewBuilder.addTarget(surface);
- mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateListener() {
+ mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
@@ -394,7 +394,7 @@
Surface previewSurface = new Surface(mTextureView.getSurfaceTexture());
builder.addTarget(previewSurface);
mCameraDevice.createCaptureSession(Arrays.asList(surface, previewSurface),
- new CameraCaptureSession.StateListener() {
+ new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
// Start recording
diff --git a/ui/views/Clipping/ClippingBasic/Application/README-fragmentview.txt b/ui/views/Clipping/ClippingBasic/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ Copyright 2013 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/views/Clipping/ClippingBasic/Application/src/main/java/com/example/android/clippingbasic/ClippingBasicFragment.java b/ui/views/Clipping/ClippingBasic/Application/src/main/java/com/example/android/clippingbasic/ClippingBasicFragment.java
index ef14be1..295a474 100644
--- a/ui/views/Clipping/ClippingBasic/Application/src/main/java/com/example/android/clippingbasic/ClippingBasicFragment.java
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/java/com/example/android/clippingbasic/ClippingBasicFragment.java
@@ -23,6 +23,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
import android.widget.Button;
import android.widget.TextView;
@@ -37,7 +38,7 @@
private int mClickCount = 0;
/* The {@Link Outline} used to clip the image with. */
- private Outline mClip;
+ private ViewOutlineProvider mOutlineProvider;
/* An array of texts. */
private String[] mSampleTexts;
@@ -49,7 +50,7 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
- mClip = new Outline();
+ mOutlineProvider = new ClipOutlineProvider();
mSampleTexts = getResources().getStringArray(R.array.sample_texts);
}
@@ -67,35 +68,28 @@
mTextView = (TextView) view.findViewById(R.id.text_view);
changeText();
+
+ final View clippedView = view.findViewById(R.id.frame);
+
+ /* Sets the OutlineProvider for the View. */
+ clippedView.setOutlineProvider(mOutlineProvider);
+
/* When the button is clicked, the text is clipped or un-clipped. */
view.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View bt) {
-
- View clippedView = view.findViewById(R.id.frame);
-
- /* The view is already clipped if {Link View#getClipToOutline()} returns true. */
+ // Toggle whether the View is clipped to the outline
if (clippedView.getClipToOutline()) {
/* The Outline is set for the View, but disable clipping. */
clippedView.setClipToOutline(false);
- Log.d(TAG, String.format("Clipping was removed."));
+ Log.d(TAG, String.format("Clipping to outline is disabled"));
((Button) bt).setText(R.string.clip_button);
-
} else {
- /*
- Sets the dimensions and shape of the {@Link Outline}. A rounded rectangle
- with a margin determined by the width or height.
- */
- int margin = Math.min(clippedView.getWidth(), clippedView.getHeight()) / 10;
- mClip.setRoundRect(margin, margin, clippedView.getWidth() - margin,
- clippedView.getHeight() - margin, margin / 2);
- /* Sets the Outline of the View. */
- clippedView.setOutline(mClip);
/* Enables clipping on the View. */
clippedView.setClipToOutline(true);
- Log.d(TAG, String.format("View was clipped."));
+ Log.d(TAG, String.format("Clipping to outline is enabled"));
((Button) bt).setText(R.string.unclip_button);
}
}
@@ -106,20 +100,40 @@
@Override
public void onClick(View view) {
mClickCount++;
+
+ // Update the text in the TextView
changeText();
+
+ // Invalidate the outline just in case the TextView changed size
+ clippedView.invalidateOutline();
}
});
}
private void changeText() {
- /*
- Compute the position of the string in the array using the number of strings
- and the number of clicks.
- */
+ // Compute the position of the string in the array using the number of strings
+ // and the number of clicks.
String newText = mSampleTexts[mClickCount % mSampleTexts.length];
/* Once the text is selected, change the TextView */
mTextView.setText(newText);
Log.d(TAG, String.format("Text was changed."));
+
+
+ }
+
+ /**
+ * A {@link ViewOutlineProvider} which clips the view with a rounded rectangle which is inset
+ * by 10%
+ */
+ private class ClipOutlineProvider extends ViewOutlineProvider {
+
+ @Override
+ public void getOutline(View view, Outline outline) {
+ final int margin = Math.min(view.getWidth(), view.getHeight()) / 10;
+ outline.setRoundRect(margin, margin, view.getWidth() - margin,
+ view.getHeight() - margin, margin / 2);
+ }
+
}
}
\ No newline at end of file
diff --git a/ui/views/Clipping/ClippingBasic/Application/src/main/res/values/strings.xml b/ui/views/Clipping/ClippingBasic/Application/src/main/res/values/strings.xml
index e9cc40d..b01a168 100644
--- a/ui/views/Clipping/ClippingBasic/Application/src/main/res/values/strings.xml
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/res/values/strings.xml
@@ -21,6 +21,6 @@
<item>De finibus bonorum et malorum.</item>
</string-array>
- <string name="clip_button">Clip</string>
- <string name="unclip_button">Remove Clipping</string>
+ <string name="clip_button">Enabled outline clipping</string>
+ <string name="unclip_button">Disable outline clipping</string>
</resources>
\ No newline at end of file
diff --git a/ui/views/Clipping/ClippingBasic/template-params.xml b/ui/views/Clipping/ClippingBasic/template-params.xml
index 7e3a14d..957a591 100644
--- a/ui/views/Clipping/ClippingBasic/template-params.xml
+++ b/ui/views/Clipping/ClippingBasic/template-params.xml
@@ -23,7 +23,7 @@
<package>com.example.android.clippingbasic</package>
- <minSdk>19</minSdk>
+ <minSdk>21</minSdk>
<compileSdkVersion>21</compileSdkVersion>
diff --git a/ui/views/Elevation/ElevationBasic/template-params.xml b/ui/views/Elevation/ElevationBasic/template-params.xml
index a393299..3ef4ec2 100644
--- a/ui/views/Elevation/ElevationBasic/template-params.xml
+++ b/ui/views/Elevation/ElevationBasic/template-params.xml
@@ -19,13 +19,13 @@
<sample>
<name>ElevationBasic</name>
- <group>NoGroup</group>
+ <group>UI</group>
<package>com.example.android.elevationbasic</package>
<!-- change minSdk if needed-->
- <minSdk>19</minSdk>
+ <minSdk>21</minSdk>
<compileSdkVersion>21</compileSdkVersion>
diff --git a/ui/views/Elevation/ElevationDrag/Application/README-fragmentview.txt b/ui/views/Elevation/ElevationDrag/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ Copyright 2013 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/java/com/example/android/elevationdrag/ElevationDragFragment.java b/ui/views/Elevation/ElevationDrag/Application/src/main/java/com/example/android/elevationdrag/ElevationDragFragment.java
index 4c5fc6a..9d14206 100644
--- a/ui/views/Elevation/ElevationDrag/Application/src/main/java/com/example/android/elevationdrag/ElevationDragFragment.java
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/java/com/example/android/elevationdrag/ElevationDragFragment.java
@@ -16,51 +16,48 @@
package com.example.android.elevationdrag;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
+import com.example.android.common.logger.Log;
+
import android.graphics.Outline;
-import android.graphics.Path;
-import android.support.v4.app.Fragment;
import android.os.Bundle;
+import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Spinner;
-import android.widget.Toast;
-
-import com.example.android.common.logger.Log;
+import android.view.ViewOutlineProvider;
public class ElevationDragFragment extends Fragment {
public static final String TAG = "ElevationDragFragment";
- /* How much to translate each time the Z+ and Z- buttons are clicked. */
- private static final int ELEVATION_STEP = 40;
-
- /* Different outlines: */
-
- private Outline mOutlineCircle;
-
- private Outline mOutlineRect;
+ /* The circular outline provider */
+ private ViewOutlineProvider mOutlineProviderCircle;
/* The current elevation of the floating view. */
private float mElevation = 0;
+ /* The step in elevation when changing the Z value */
+ private int mElevationStep;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mOutlineProviderCircle = new CircleOutlineProvider();
+
+ mElevationStep = getResources().getDimensionPixelSize(R.dimen.elevation_step);
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.ztranslation, container, false);
- /* Create different outlines. */
- createOutlines();
-
/* Find the {@link View} to apply z-translation to. */
final View floatingShape = rootView.findViewById(R.id.circle);
/* Define the shape of the {@link View}'s shadow by setting one of the {@link Outline}s. */
- floatingShape.setOutline(mOutlineCircle);
+ floatingShape.setOutlineProvider(mOutlineProviderCircle);
/* Clip the {@link View} with its outline. */
floatingShape.setClipToOutline(true);
@@ -76,7 +73,7 @@
floatingShape.animate()
.translationZ(captured ? 50 : 0)
.setDuration(100);
- Log.d(TAG, captured ? "drag" : "drop");
+ Log.d(TAG, captured ? "Drag" : "Drop");
}
});
@@ -84,10 +81,9 @@
/* Raise the circle in z when the "z+" button is clicked. */
rootView.findViewById(R.id.raise_bt).setOnClickListener(new View.OnClickListener() {
-
@Override
public void onClick(View v) {
- mElevation += ELEVATION_STEP;
+ mElevation += mElevationStep;
Log.d(TAG, String.format("Elevation: %.1f", mElevation));
floatingShape.setElevation(mElevation);
}
@@ -95,10 +91,9 @@
/* Lower the circle in z when the "z-" button is clicked. */
rootView.findViewById(R.id.lower_bt).setOnClickListener(new View.OnClickListener() {
-
@Override
public void onClick(View v) {
- mElevation -= ELEVATION_STEP;
+ mElevation -= mElevationStep;
// Don't allow for negative values of Z.
if (mElevation < 0) {
mElevation = 0;
@@ -108,57 +103,17 @@
}
});
- /* Create a spinner with options to change the shape of the object. */
- Spinner spinner = (Spinner) rootView.findViewById(R.id.shapes_spinner);
- spinner.setAdapter(new ArrayAdapter<String>(
- getActivity(),
- android.R.layout.simple_spinner_dropdown_item,
- getResources().getStringArray(R.array.shapes)));
-
- /* Set the appropriate outline when an item is selected. */
- spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- /* Set the corresponding Outline to the shape. */
- switch (position) {
- case 0:
- floatingShape.setOutline(mOutlineCircle);
- floatingShape.setClipToOutline(true);
- break;
- case 1:
- floatingShape.setOutline(mOutlineRect);
- floatingShape.setClipToOutline(true);
- break;
- default:
- floatingShape.setOutline(mOutlineCircle);
- /* Don't clip the view to the outline in the last case. */
- floatingShape.setClipToOutline(false);
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- floatingShape.setOutline(mOutlineCircle);
- }
- });
-
return rootView;
-
}
- private void createOutlines() {
- /* Outlines define the shape that's used for clipping the View and its shadow. */
-
- /* Get the size of the shape from resources. */
- int shapeSize = getResources().getDimensionPixelSize(R.dimen.shape_size);
-
- /* Create a circular outline. */
- mOutlineCircle = new Outline();
- mOutlineCircle.setRoundRect(0, 0, shapeSize, shapeSize, shapeSize / 2);
-
- /* Create a rectangular outline. */
- mOutlineRect = new Outline();
- mOutlineRect.setRoundRect(0, 0, shapeSize, shapeSize, shapeSize / 10);
+ /**
+ * ViewOutlineProvider which sets the outline to be an oval which fits the view bounds.
+ */
+ private class CircleOutlineProvider extends ViewOutlineProvider {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setOval(0, 0, view.getWidth(), view.getHeight());
+ }
}
+
}
\ No newline at end of file
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable/shape.xml b/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable/shape.xml
deleted file mode 100644
index 5392e00..0000000
--- a/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable/shape.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2013 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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@color/color_1"/>
-</shape>
\ No newline at end of file
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/res/layout/ztranslation.xml b/ui/views/Elevation/ElevationDrag/Application/src/main/res/layout/ztranslation.xml
index 9989fc4..2ae3926 100644
--- a/ui/views/Elevation/ElevationDrag/Application/src/main/res/layout/ztranslation.xml
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/res/layout/ztranslation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2013 The Android Open Source Project
+ Copyright 2014 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.
@@ -22,24 +22,12 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
- <Spinner
- android:id="@+id/shapes_spinner"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="30dp"
- android:layout_marginRight="30dp"
- android:layout_marginLeft="30dp"
- android:layout_marginBottom="0dp"
- android:layout_gravity="center_horizontal"/>
-
<View
android:id="@+id/circle"
android:layout_width="@dimen/shape_size"
android:layout_height="@dimen/shape_size"
- android:layout_marginTop="80dp"
- android:layout_marginBottom="60dp"
- android:layout_gravity="center_horizontal"
- android:background="@drawable/shape"/>
+ android:layout_gravity="center"
+ android:background="@color/color_1"/>
<LinearLayout
android:layout_margin="16dp"
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/dimens.xml b/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/dimens.xml
index e169867..778d8de 100644
--- a/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/dimens.xml
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/dimens.xml
@@ -15,5 +15,6 @@
limitations under the License.
-->
<resources>
- <dimen name="shape_size">64dp</dimen>
+ <dimen name="shape_size">96dp</dimen>
+ <dimen name="elevation_step">8dp</dimen>
</resources>
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/shapes.xml b/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/shapes.xml
deleted file mode 100644
index 95beb32..0000000
--- a/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/shapes.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2014 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.
--->
-<resources>
- <string-array name="shapes">
- <item>Circle</item>
- <item>Rounded rectangle</item>
- <item>Rectangle, circular shadow</item>
- </string-array>
-</resources>
\ No newline at end of file
diff --git a/ui/views/Elevation/ElevationDrag/template-params.xml b/ui/views/Elevation/ElevationDrag/template-params.xml
index e51209a..2c62cb2 100644
--- a/ui/views/Elevation/ElevationDrag/template-params.xml
+++ b/ui/views/Elevation/ElevationDrag/template-params.xml
@@ -24,7 +24,7 @@
<!-- change minSdk if needed-->
- <minSdk>19</minSdk>
+ <minSdk>21</minSdk>
<compileSdkVersion>21</compileSdkVersion>
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/README-fragmentview.txt b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ Copyright 2013 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/com/example/android/floatingactionbuttonbasic/FloatingActionButton.java b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/com/example/android/floatingactionbuttonbasic/FloatingActionButton.java
index 1a27cfc..12fdd1c 100644
--- a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/com/example/android/floatingactionbuttonbasic/FloatingActionButton.java
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/com/example/android/floatingactionbuttonbasic/FloatingActionButton.java
@@ -16,20 +16,11 @@
package com.example.android.floatingactionbuttonbasic;
-import com.example.android.common.logger.Log;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Outline;
-import android.graphics.Point;
import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewAnimationUtils;
-import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
import android.widget.Checkable;
import android.widget.FrameLayout;
@@ -40,37 +31,33 @@
public class FloatingActionButton extends FrameLayout implements Checkable {
/**
+ * Interface definition for a callback to be invoked when the checked state
+ * of a compound button changes.
+ */
+ public static interface OnCheckedChangeListener {
+
+ /**
+ * Called when the checked state of a FAB has changed.
+ *
+ * @param fabView The FAB view whose state has changed.
+ * @param isChecked The new checked state of buttonView.
+ */
+ void onCheckedChanged(FloatingActionButton fabView, boolean isChecked);
+ }
+
+ /**
* An array of states.
*/
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
};
- private static String TAG = "FloatingActionButton";
+ private static final String TAG = "FloatingActionButton";
- /**
- * A boolean that tells if the FAB is checked or not.
- */
- protected boolean mChecked;
+ // A boolean that tells if the FAB is checked or not.
+ private boolean mChecked;
- /*/
- * The {@link View} that is revealed.
- */
- protected View mRevealView;
-
- /**
- * The coordinates of a touch action.
- */
- protected Point mTouchPoint;
-
- /**
- * A {@link android.view.GestureDetector} to detect touch actions.
- */
- private GestureDetector mGestureDetector;
-
- /**
- * A listener to communicate that the FAB has changed its state.
- */
+ // A listener to communicate that the FAB has changed it's state
private OnCheckedChangeListener mOnCheckedChangeListener;
public FloatingActionButton(Context context) {
@@ -89,26 +76,20 @@
int defStyleRes) {
super(context, attrs, defStyleAttr);
- // When a view is clickable it will change its state to "pressed" on every click.
setClickable(true);
- // Create a {@link GestureDetector} to detect single taps.
- mGestureDetector = new GestureDetector(context,
- new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
- mTouchPoint = new Point((int) e.getX(), (int) e.getY());
- Log.d(TAG, "Single tap captured.");
- toggle();
- return true;
- }
- }
- );
+ // Set the outline provider for this view. The provider is given the outline which it can
+ // then modify as needed. In this case we set the outline to be an oval fitting the height
+ // and width.
+ setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setOval(0, 0, getWidth(), getHeight());
+ }
+ });
- // A new {@link View} is created
- mRevealView = new View(context);
- addView(mRevealView, ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
+ // Finally, enable clipping to the outline, using the provider we set above
+ setClipToOutline(true);
}
/**
@@ -122,78 +103,22 @@
}
mChecked = checked;
- // Create and start the {@link ValueAnimator} that shows the new state.
- ValueAnimator anim = createAnimator();
- anim.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));
- anim.start();
-
- // Set the new background color of the {@link View} to be revealed.
- mRevealView.setBackgroundColor(
- mChecked ? getResources().getColor(R.color.fab_color_2)
- : getResources().getColor(R.color.fab_color_1)
- );
-
- // Show the {@link View} to be revealed. Note that the animation has started already.
- mRevealView.setVisibility(View.VISIBLE);
+ // Now refresh the drawable state (so the icon changes)
+ refreshDrawableState();
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, checked);
}
}
+ /**
+ * Register a callback to be invoked when the checked state of this button
+ * changes.
+ *
+ * @param listener the callback to call on checked state change
+ */
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
- setClickable(listener != null);
- }
-
- /**
- * Interface definition for a callback to be invoked when the checked state
- * of a compound button changes.
- */
- public static interface OnCheckedChangeListener {
-
- /**
- * Called when the checked state of a FAB has changed.
- *
- * @param fabView The FAB view whose state has changed.
- * @param isChecked The new checked state of buttonView.
- */
- void onCheckedChanged(FloatingActionButton fabView, boolean isChecked);
- }
-
- protected ValueAnimator createAnimator() {
-
- // Calculate the longest distance from the hot spot to the edge of the circle.
- int endRadius = getWidth() / 2 +
- (int) Math.hypot(getWidth() / 2 - mTouchPoint.y, getWidth() / 2 - mTouchPoint.x);
-
- // Make sure the touch point is defined or set it to the middle of the view.
- if (mTouchPoint == null) {
- mTouchPoint = new Point(getWidth() / 2, getHeight() / 2);
- }
- ValueAnimator anim = ViewAnimationUtils.createCircularReveal(
- mRevealView, mTouchPoint.x, mTouchPoint.y, 0, endRadius);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Now we can refresh the drawable state
- refreshDrawableState();
-
- mRevealView.setVisibility(View.GONE);
- // Reset the touch point as the next call to {@link setChecked} might not come
- // from a tap.
- mTouchPoint = null;
- }
- });
- return anim;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mGestureDetector.onTouchEvent(event)) {
- return true;
- }
- return super.onTouchEvent(event);
}
@Override
@@ -206,14 +131,22 @@
setChecked(!mChecked);
}
+ /**
+ * Override performClick() so that we can toggle the checked state when the view is clicked
+ */
+ @Override
+ public boolean performClick() {
+ toggle();
+ return super.performClick();
+ }
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- Outline outline = new Outline();
- outline.setOval(0, 0, w, h);
- setOutline(outline);
- setClipToOutline(true);
+ // As we have changed size, we should invalidate the outline so that is the the
+ // correct size
+ invalidateOutline();
}
@Override
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable/fab_icons.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable/fab_icons.xml
index 0e64385..daf1d24 100644
--- a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable/fab_icons.xml
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable/fab_icons.xml
@@ -15,7 +15,8 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:enterFadeDuration="@android:integer/config_shortAnimTime">
<item android:state_checked="true">
<bitmap android:src="@drawable/ic_tick" android:tint="@android:color/white" />
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.jar b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..0087cd3
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.properties b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..893a63e
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Oct 15 14:12:11 BST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew.bat b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/template-params.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/template-params.xml
index f1d147d..0e97b7a 100644
--- a/ui/views/FloatingActionButton/FloatingActionButtonBasic/template-params.xml
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/template-params.xml
@@ -23,7 +23,7 @@
<package>com.example.android.floatingactionbuttonbasic</package>
<!-- change minSdk if needed-->
- <minSdk>19</minSdk>
+ <minSdk>21</minSdk>
<compileSdkVersion>21</compileSdkVersion>
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/java/com/example/android/revealeffectbasic/RevealEffectBasicFragment.java b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/java/com/example/android/revealeffectbasic/RevealEffectBasicFragment.java
index 39d5fb0..1520619 100644
--- a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/java/com/example/android/revealeffectbasic/RevealEffectBasicFragment.java
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/java/com/example/android/revealeffectbasic/RevealEffectBasicFragment.java
@@ -15,6 +15,9 @@
*/
package com.example.android.revealeffectbasic;
+import com.example.android.common.logger.Log;
+
+import android.animation.Animator;
import android.animation.ValueAnimator;
import android.support.v4.app.Fragment;
import android.os.Bundle;
@@ -39,35 +42,34 @@
}
@Override
- public View onCreateView(
- LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.reveal_effect_basic, container, false);
View button = rootView.findViewById(R.id.button);
- /* Set a listener to reveal the view on ACTION_DOWN. */
- button.setOnTouchListener(new View.OnTouchListener() {
+ // Set a listener to reveal the view when clicked.
+ button.setOnClickListener(new View.OnClickListener() {
@Override
- public boolean onTouch(View view, MotionEvent motionEvent) {
- if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
- View shape = rootView.findViewById(R.id.circle);
- /* Create a reveal {@Link ValueAnimator} that starts clipping the view from
- * the top left corner until the whole view is covered. */
- ValueAnimator animator = ViewAnimationUtils.createCircularReveal(
- shape,
- 0,
- 0,
- 0,
- (float) Math.hypot(shape.getWidth(), shape.getHeight()));
+ public void onClick(View view) {
+ View shape = rootView.findViewById(R.id.circle);
- /* Set a natural ease-in/ease-out interpolator. */
- animator.setInterpolator(new AccelerateDecelerateInterpolator());
+ // Create a reveal {@link Animator} that starts clipping the view from
+ // the top left corner until the whole view is covered.
+ Animator animator = ViewAnimationUtils.createCircularReveal(
+ shape,
+ 0,
+ 0,
+ 0,
+ (float) Math.hypot(shape.getWidth(), shape.getHeight()));
- animator.start();
- return false;
- }
- return false;
+ // Set a natural ease-in/ease-out interpolator.
+ animator.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // Finally start the animation
+ animator.start();
+
+ Log.d(TAG, "Starting Reveal animation");
}
});
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/layout/reveal_effect_basic.xml b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/layout/reveal_effect_basic.xml
index 07b6943..f7f6923 100644
--- a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/layout/reveal_effect_basic.xml
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/layout/reveal_effect_basic.xml
@@ -23,7 +23,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
- android:background="@color/color_2"
+ android:background="@color/color"
android:layout_above="@+id/button"
android:layout_marginTop="@dimen/margin_medium"
android:layout_marginRight="@dimen/margin_medium"
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/values/colors.xml b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/values/colors.xml
index 195adf8..52150b0 100644
--- a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/values/colors.xml
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/values/colors.xml
@@ -15,6 +15,5 @@
limitations under the License.
-->
<resources>
- <color name="color_1">#E91E63</color>
- <color name="color_2">#673AB7</color>
+ <color name="color">#673AB7</color>
</resources>
diff --git a/ui/views/RevealEffect/RevealEffectBasic/CONTRIB.md b/ui/views/RevealEffect/RevealEffectBasic/CONTRIB.md
new file mode 100644
index 0000000..14a4fcf
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/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/ui/views/RevealEffect/RevealEffectBasic/LICENSE b/ui/views/RevealEffect/RevealEffectBasic/LICENSE
new file mode 100644
index 0000000..1af981f
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/LICENSE
@@ -0,0 +1,201 @@
+ 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 2014 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/ui/views/RevealEffect/RevealEffectBasic/template-params.xml b/ui/views/RevealEffect/RevealEffectBasic/template-params.xml
index a01c006..dea5695 100644
--- a/ui/views/RevealEffect/RevealEffectBasic/template-params.xml
+++ b/ui/views/RevealEffect/RevealEffectBasic/template-params.xml
@@ -24,7 +24,7 @@
- <minSdk>19</minSdk>
+ <minSdk>21</minSdk>
<compileSdkVersion>21</compileSdkVersion>
diff --git a/wearable/wear/SpeedTracker/Application/proguard-rules.pro b/wearable/wear/SpeedTracker/Application/proguard-rules.pro
new file mode 100644
index 0000000..0661c7b
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${SDK_DIR}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/wearable/wear/SpeedTracker/Application/src/main/AndroidManifest.xml b/wearable/wear/SpeedTracker/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..3361a44
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.wearable.speedtracker" >
+
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+
+ <uses-feature
+ android:glEsVersion="0x00020000" android:required="true"/>
+ <uses-sdk
+ android:minSdkVersion="18"
+ android:targetSdkVersion="19" />
+
+ <application
+ android:name=".PhoneApplication"
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <meta-data
+ android:name="com.google.android.maps.v2.API_KEY"
+ android:value="@string/map_v2_api_key"/>
+ <meta-data android:name="com.google.android.gms.version"
+ android:value="@integer/google_play_services_version"/>
+ <activity
+ android:name=".PhoneMainActivity"
+ android:label="@string/app_name"
+ android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <service android:name=".db.UpdateService">
+ <intent-filter>
+ <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
+ </intent-filter>
+ </service>
+ </application>
+
+</manifest>
diff --git a/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/LocationDataManager.java b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/LocationDataManager.java
new file mode 100644
index 0000000..9a3bf23
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/LocationDataManager.java
@@ -0,0 +1,95 @@
+/*
+ * 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.speedtracker;
+
+import com.example.android.wearable.speedtracker.common.LocationEntry;
+import com.example.android.wearable.speedtracker.common.Utils;
+import com.example.android.wearable.speedtracker.db.LocationDbHelper;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A class that wraps database access and provides a cache for various GPS data.
+ */
+public class LocationDataManager {
+
+ private final Map<String, List<LocationEntry>> mPointsMap =
+ new HashMap<String, List<LocationEntry>>();
+
+ private LocationDbHelper mDbHelper;
+
+ public LocationDataManager(LocationDbHelper dbHelper) {
+ mDbHelper = dbHelper;
+ }
+
+ /**
+ * Returns a list of {@link com.example.android.wearable.speedtracker.common.LocationEntry}
+ * objects for the day that the {@link java.util.Calendar} object points at. Internally it uses
+ * a cache to speed up subsequent calls. If there is no cached value, it gets the result from
+ * the database.
+ */
+ public final List<LocationEntry> getPoints(Calendar calendar) {
+ String day = Utils.getHashedDay(calendar);
+ synchronized (mPointsMap) {
+ if (mPointsMap.get(day) == null) {
+ // there is no cache for this day, so lets get it from DB
+ List<LocationEntry> points = mDbHelper.read(calendar);
+ mPointsMap.put(day, points);
+ }
+ }
+ return mPointsMap.get(day);
+ }
+
+ /**
+ * Clears the data for the day that the {@link java.util.Calendar} object falls on. This method
+ * removes the entries from the database and updates the cache accordingly.
+ */
+ public final int clearPoints(Calendar calendar) {
+ synchronized (mPointsMap) {
+ String day = Utils.getHashedDay(calendar);
+ mPointsMap.remove(day);
+ return mDbHelper.delete(day);
+ }
+ }
+
+ /**
+ * Adds a {@link com.example.android.wearable.speedtracker.common.LocationEntry} point to the
+ * database and cache if it is a new point.
+ */
+ public final void addPoint(LocationEntry entry) {
+ synchronized (mPointsMap) {
+ List<LocationEntry> points = getPoints(entry.calendar);
+ if (points == null || points.isEmpty()) {
+ mDbHelper.insert(entry);
+ if (points == null) {
+ points = new ArrayList<LocationEntry>();
+ }
+ points.add(entry);
+ mPointsMap.put(entry.day, points);
+ } else {
+ if (!points.contains(entry)) {
+ mDbHelper.insert(entry);
+ points.add(entry);
+ }
+ }
+ }
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/PhoneApplication.java b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/PhoneApplication.java
new file mode 100644
index 0000000..d74d81f
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/PhoneApplication.java
@@ -0,0 +1,43 @@
+/*
+ * 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.speedtracker;
+
+import android.app.Application;
+
+import com.example.android.wearable.speedtracker.db.LocationDbHelper;
+
+/**
+ * The {@link android.app.Application} class for the handset app.
+ */
+public class PhoneApplication extends Application {
+
+ private LocationDataManager mDataManager;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ LocationDbHelper dbHelper = new LocationDbHelper(getApplicationContext());
+ mDataManager = new LocationDataManager(dbHelper);
+ }
+
+ /**
+ * Returns an instance of {@link com.example.android.wearable.speedtracker.LocationDataManager}.
+ */
+ public final LocationDataManager getDataManager() {
+ return mDataManager;
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/PhoneMainActivity.java b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/PhoneMainActivity.java
new file mode 100644
index 0000000..76f609b
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/PhoneMainActivity.java
@@ -0,0 +1,134 @@
+/*
+ * 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.speedtracker;
+
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.MapFragment;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
+import com.google.android.gms.maps.model.PolylineOptions;
+
+import android.app.Activity;
+import android.app.DatePickerDialog;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.DatePicker;
+import android.widget.TextView;
+
+import com.example.android.wearable.speedtracker.common.LocationEntry;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+/**
+ * The main activity for the handset application. When a watch device reconnects to the handset
+ * app, the collected GPS data on the watch, if any, is synced up and user can see his/her track on
+ * a map. This data is then saved into an internal database and the corresponding data items are
+ * deleted.
+ */
+public class PhoneMainActivity extends Activity implements DatePickerDialog.OnDateSetListener {
+
+ private static final String TAG = "PhoneMainActivity";
+ private static final int BOUNDING_BOX_PADDING_PX = 50;
+ private TextView mSelectedDateText;
+ private GoogleMap mMap;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main_activity);
+ mSelectedDateText = (TextView) findViewById(R.id.selected_date);
+ mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
+ }
+
+ public void onClick(View view) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(System.currentTimeMillis());
+ new DatePickerDialog(PhoneMainActivity.this, PhoneMainActivity.this,
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)).show();
+ }
+
+ @Override
+ public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
+ // the following if-clause is to get around a bug that causes this callback to be called
+ // twice
+ if (view.isShown()) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(System.currentTimeMillis());
+ calendar.set(Calendar.YEAR, year);
+ calendar.set(Calendar.MONTH, monthOfYear);
+ calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
+ String date = DateUtils.formatDateTime(this, calendar.getTimeInMillis(),
+ DateUtils.FORMAT_SHOW_DATE);
+ mSelectedDateText.setText(getString(R.string.showing_for_date, date));
+ showTrack(calendar);
+ }
+ }
+
+ /**
+ * An {@link android.os.AsyncTask} that is responsible for getting a list of {@link
+ * com.example.android.wearable.speedtracker.common.LocationEntry} objects for a given day and
+ * building a track from those points. In addition, it sets the smallest bounding box for the
+ * map that covers all the points on the track.
+ */
+ private void showTrack(Calendar calendar) {
+ new AsyncTask<Calendar, Void, Void>() {
+
+ private List<LatLng> coordinates;
+ private LatLngBounds bounds;
+
+ @Override
+ protected Void doInBackground(Calendar... params) {
+ LocationDataManager dataManager = ((PhoneApplication) getApplicationContext())
+ .getDataManager();
+ List<LocationEntry> entries = dataManager.getPoints(params[0]);
+ if (entries != null && !entries.isEmpty()) {
+ coordinates = new ArrayList<LatLng>();
+ LatLngBounds.Builder builder = new LatLngBounds.Builder();
+ for (LocationEntry entry : entries) {
+ LatLng latLng = new LatLng(entry.latitude, entry.longitude);
+ builder.include(latLng);
+ coordinates.add(latLng);
+ }
+ bounds = builder.build();
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ mMap.clear();
+ if (coordinates == null || coordinates.isEmpty()) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "No Entries found for that date");
+ }
+ } else {
+ mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds,
+ BOUNDING_BOX_PADDING_PX));
+ mMap.addPolyline(new PolylineOptions().geodesic(true).addAll(coordinates));
+ }
+ }
+
+ }.execute(calendar);
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/db/LocationDbHelper.java b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/db/LocationDbHelper.java
new file mode 100644
index 0000000..3397eaa
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/db/LocationDbHelper.java
@@ -0,0 +1,165 @@
+/*
+ * 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.speedtracker.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.provider.BaseColumns;
+import android.util.Log;
+
+import com.example.android.wearable.speedtracker.common.LocationEntry;
+import com.example.android.wearable.speedtracker.common.Utils;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+/**
+ * A helper class to set up the database that holds the GPS location information
+ */
+public class LocationDbHelper extends SQLiteOpenHelper {
+
+ private static final String TAG = "LocationDbHelper";
+
+ public static final String TABLE_NAME = "location";
+ public static final String COLUMN_NAME_DAY = "day";
+ public static final String COLUMN_NAME_LATITUDE = "lat";
+ public static final String COLUMN_NAME_LONGITUDE = "lon";
+ public static final String COLUMN_NAME_TIME = "time";
+
+ private static final String TEXT_TYPE = " TEXT";
+ private static final String INTEGER_TYPE = " INTEGER";
+ private static final String REAL_TYPE = " REAL";
+ private static final String COMMA_SEP = ",";
+ private static final String SQL_CREATE_ENTRIES =
+ "CREATE TABLE " + TABLE_NAME + " ("
+ + BaseColumns._ID + " INTEGER PRIMARY KEY,"
+ + COLUMN_NAME_DAY + TEXT_TYPE + COMMA_SEP
+ + COLUMN_NAME_LATITUDE + REAL_TYPE + COMMA_SEP
+ + COLUMN_NAME_LONGITUDE + REAL_TYPE + COMMA_SEP
+ + COLUMN_NAME_TIME + INTEGER_TYPE
+ + " )";
+ private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + TABLE_NAME;
+
+ public static final int DATABASE_VERSION = 1;
+ public static final String DATABASE_NAME = "Location.db";
+
+ public LocationDbHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(SQL_CREATE_ENTRIES);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL(SQL_DELETE_ENTRIES);
+ onCreate(db);
+ }
+
+ /**
+ * Inserts a {@link com.example.android.wearable.speedtracker.common.LocationEntry} item to the
+ * database.
+ */
+ public final long insert(LocationEntry entry) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Inserting a LocationEntry");
+ }
+ // Gets the data repository in write mode
+ SQLiteDatabase db = getWritableDatabase();
+
+ // Create a new map of values, where column names are the keys
+ ContentValues values = new ContentValues();
+ values.put(COLUMN_NAME_DAY, entry.day);
+ values.put(COLUMN_NAME_LONGITUDE, entry.longitude);
+ values.put(COLUMN_NAME_LATITUDE, entry.latitude);
+ values.put(COLUMN_NAME_TIME, entry.calendar.getTimeInMillis());
+
+ // Insert the new row, returning the primary key value of the new row
+ return db.insert(TABLE_NAME, "null", values);
+ }
+
+ /**
+ * Returns a list of {@link com.example.android.wearable.speedtracker.common.LocationEntry}
+ * objects from the database for a given day. The list can be empty (but not {@code null}) if
+ * there are no such items. This method looks at the day that the calendar argument points at.
+ */
+ public final List<LocationEntry> read(Calendar calendar) {
+ SQLiteDatabase db = getReadableDatabase();
+ String[] projection = {
+ COLUMN_NAME_LONGITUDE,
+ COLUMN_NAME_LATITUDE,
+ COLUMN_NAME_TIME
+ };
+ String day = Utils.getHashedDay(calendar);
+
+ // sort ASC based on the time of the entry
+ String sortOrder = COLUMN_NAME_TIME + " ASC";
+ String selection = COLUMN_NAME_DAY + " LIKE ?";
+
+ Cursor cursor = db.query(
+ TABLE_NAME, // The table to query
+ projection, // The columns to return
+ selection, // The columns for the WHERE clause
+ new String[]{day}, // The values for the WHERE clause
+ null, // don't group the rows
+ null, // don't filter by row groups
+ sortOrder // The sort order
+ );
+
+ List<LocationEntry> result = new ArrayList<LocationEntry>();
+ int count = cursor.getCount();
+ if (count > 0) {
+ cursor.moveToFirst();
+ while (!cursor.isAfterLast()) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(cursor.getLong(2));
+ LocationEntry entry = new LocationEntry(cal, cursor.getDouble(1),
+ cursor.getDouble(0));
+ result.add(entry);
+ cursor.moveToNext();
+ }
+ }
+ cursor.close();
+ return result;
+ }
+
+ /**
+ * Deletes all the entries in the database for the given day. The argument {@code day} should
+ * match the format provided by {@link getHashedDay()}
+ */
+ public final int delete(String day) {
+ SQLiteDatabase db = getWritableDatabase();
+ // Define 'where' part of the query.
+ String selection = COLUMN_NAME_DAY + " LIKE ?";
+ String[] selectionArgs = {day};
+ return db.delete(TABLE_NAME, selection, selectionArgs);
+ }
+
+ /**
+ * Deletes all the entries in the database for the day that the {@link java.util.Calendar}
+ * argument points at.
+ */
+ public final int delete(Calendar calendar) {
+ return delete(Utils.getHashedDay(calendar));
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/db/UpdateService.java b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/db/UpdateService.java
new file mode 100644
index 0000000..8fe5951
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/java/com/example/android/wearable/speedtracker/db/UpdateService.java
@@ -0,0 +1,135 @@
+/*
+ * 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.speedtracker.db;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.wearable.DataApi;
+import com.google.android.gms.wearable.DataEvent;
+import com.google.android.gms.wearable.DataEventBuffer;
+import com.google.android.gms.wearable.DataMap;
+import com.google.android.gms.wearable.DataMapItem;
+import com.google.android.gms.wearable.Wearable;
+import com.google.android.gms.wearable.WearableListenerService;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.example.android.wearable.speedtracker.LocationDataManager;
+import com.example.android.wearable.speedtracker.PhoneApplication;
+import com.example.android.wearable.speedtracker.common.Constants;
+import com.example.android.wearable.speedtracker.common.LocationEntry;
+
+import java.util.Calendar;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A {@link com.google.android.gms.wearable.WearableListenerService} that is responsible for
+ * reading location data that gets added to the Data Layer storage.
+ */
+public class UpdateService extends WearableListenerService
+ implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
+ ResultCallback<DataApi.DeleteDataItemsResult> {
+
+ private static final String TAG = "UpdateService";
+ private LocationDataManager mDataManager;
+ private GoogleApiClient mGoogleApiClient;
+ private final Set<Uri> mToBeDeletedUris = new HashSet<Uri>();
+ public static final String ACTION_NOTIFY = "com.example.android.wearable.speedtracker.Message";
+ public static final String EXTRA_ENTRY = "entry";
+ public static final String EXTRA_LOG = "log";
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mGoogleApiClient = new GoogleApiClient.Builder(this)
+ .addApi(Wearable.API)
+ .addConnectionCallbacks(this)
+ .addOnConnectionFailedListener(this)
+ .build();
+ mGoogleApiClient.connect();
+ mDataManager = ((PhoneApplication) getApplicationContext()).getDataManager();
+ }
+
+ @Override
+ public void onDataChanged(DataEventBuffer dataEvents) {
+ for (DataEvent dataEvent : dataEvents) {
+ if (dataEvent.getType() == DataEvent.TYPE_CHANGED) {
+ Uri dataItemUri = dataEvent.getDataItem().getUri();
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Received a data item with uri: " + dataItemUri.getPath());
+ }
+ if (dataItemUri.getPath().startsWith(Constants.PATH)) {
+ DataMap dataMap = DataMapItem.fromDataItem(dataEvent.getDataItem())
+ .getDataMap();
+ double longitude = dataMap.getDouble(Constants.KEY_LONGITUDE);
+ double latitude = dataMap.getDouble(Constants.KEY_LATITUDE);
+ long time = dataMap.getLong(Constants.KEY_TIME);
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(time);
+ mDataManager.addPoint(
+ new LocationEntry(calendar, latitude, longitude));
+ if (mGoogleApiClient.isConnected()) {
+ Wearable.DataApi.deleteDataItems(
+ mGoogleApiClient, dataItemUri).setResultCallback(this);
+ } else {
+ synchronized (mToBeDeletedUris) {
+ mToBeDeletedUris.add(dataItemUri);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Override // ConnectionCallbacks
+ public void onConnected(Bundle bundle) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "onConnected(): api client is connected now");
+ }
+ synchronized (mToBeDeletedUris) {
+ if (!mToBeDeletedUris.isEmpty()) {
+ for (Uri dataItemUri : mToBeDeletedUris) {
+ Wearable.DataApi.deleteDataItems(
+ mGoogleApiClient, dataItemUri).setResultCallback(this);
+ }
+ }
+ }
+ }
+
+ @Override // ConnectionCallbacks
+ public void onConnectionSuspended(int i) {
+ }
+
+ @Override // OnConnectionFailedListener
+ public void onConnectionFailed(ConnectionResult connectionResult) {
+ Log.e(TAG, "Failed to connect to the Google API client");
+ }
+
+ @Override // ResultCallback
+ public void onResult(DataApi.DeleteDataItemsResult deleteDataItemsResult) {
+ if (!deleteDataItemsResult.getStatus().isSuccess()) {
+ Log.e(TAG,
+ "Failed to delete a dataItem, status code: " + deleteDataItemsResult.getStatus()
+ .getStatusCode() + deleteDataItemsResult.getStatus()
+ .getStatusMessage());
+ }
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Application/src/main/res/drawable-hdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..2275b45
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Application/src/main/res/drawable-mdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..25015af
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..8aee870
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..7008a2f
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..c31ab73
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Application/src/main/res/layout/main_activity.xml b/wearable/wear/SpeedTracker/Application/src/main/res/layout/main_activity.xml
new file mode 100644
index 0000000..a18c644
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/res/layout/main_activity.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <RelativeLayout
+ android:id="@+id/top_container"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <Button
+ android:id="@+id/date_picker"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:onClick="onClick"
+ android:layout_centerHorizontal="true"
+ android:text="@string/show_my_track"
+ />
+ <TextView
+ android:id="@+id/selected_date"
+ android:layout_below="@+id/date_picker"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="5dp"
+ android:layout_marginTop="5dp"
+ android:textStyle="italic"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ </RelativeLayout>
+
+ <fragment
+ android:id="@+id/map"
+ android:layout_below="@+id/top_container"
+ android:layout_width="fill_parent"
+ android:layout_height="match_parent"
+ android:name="com.google.android.gms.maps.MapFragment"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Application/src/main/res/values/strings.xml b/wearable/wear/SpeedTracker/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..cdb6f7c
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Application/src/main/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources>
+
+ <string name="map_v2_api_key">YOUR_MAP_V2_API_KEY</string>
+ <string name="action_settings">Settings</string>
+
+ <string name="showing_for_date">Track for %1$s</string>
+ <string name="no_date">No data for the selected date</string>
+ <string name="show_my_track">Show My Track</string>
+
+</resources>
diff --git a/wearable/wear/SpeedTracker/CONTRIB.md b/wearable/wear/SpeedTracker/CONTRIB.md
new file mode 100644
index 0000000..14a4fcf
--- /dev/null
+++ b/wearable/wear/SpeedTracker/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/wearable/wear/SpeedTracker/LICENSE b/wearable/wear/SpeedTracker/LICENSE
new file mode 100644
index 0000000..1af981f
--- /dev/null
+++ b/wearable/wear/SpeedTracker/LICENSE
@@ -0,0 +1,201 @@
+ 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 2014 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/wearable/wear/SpeedTracker/README b/wearable/wear/SpeedTracker/README
new file mode 100644
index 0000000..7d6d5ec
--- /dev/null
+++ b/wearable/wear/SpeedTracker/README
@@ -0,0 +1,12 @@
+In order to run this application, you need to install the
+wearable apk on a device that has GPS capabilities in
+hardware. In addition, you need to obtain an API key for
+using Map v2 APIs, see the following link for the details:
+https://developers.google.com/maps/documentation/android/start#get_an_android_certificate_and_the_google_maps_api_key
+After getting the key, find the following line in
+Application/src/main/res/values/strings.xml:
+
+<string name="map_v2_api_key">YOUR_MAP_V2_API_KEY</string>
+
+and replace YOUR_MAP_V2_API_KEY with your own key.
+
diff --git a/wearable/wear/SpeedTracker/Shared/proguard-rules.pro b/wearable/wear/SpeedTracker/Shared/proguard-rules.pro
new file mode 100644
index 0000000..0661c7b
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Shared/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${SDK_DIR}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/wearable/wear/SpeedTracker/Shared/src/main/AndroidManifest.xml b/wearable/wear/SpeedTracker/Shared/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..50d0339
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Shared/src/main/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.wearable.speedtracker.common">
+
+ <application android:allowBackup="true"/>
+
+</manifest>
diff --git a/wearable/wear/SpeedTracker/Shared/src/main/java/com/example/android/wearable/speedtracker/common/Constants.java b/wearable/wear/SpeedTracker/Shared/src/main/java/com/example/android/wearable/speedtracker/common/Constants.java
new file mode 100644
index 0000000..ac761eb
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Shared/src/main/java/com/example/android/wearable/speedtracker/common/Constants.java
@@ -0,0 +1,30 @@
+/*
+ * 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.speedtracker.common;
+
+/**
+ * A collection of constants that is shared between teh wearable and handset apps.
+ */
+public class Constants {
+
+ public static final String PATH = "/location";
+ public static final String KEY_LONGITUDE = "lng";
+ public static final String KEY_LATITUDE = "lat";
+ public static final String KEY_TIME = "time";
+
+ private Constants() {}
+}
diff --git a/wearable/wear/SpeedTracker/Shared/src/main/java/com/example/android/wearable/speedtracker/common/LocationEntry.java b/wearable/wear/SpeedTracker/Shared/src/main/java/com/example/android/wearable/speedtracker/common/LocationEntry.java
new file mode 100644
index 0000000..2a8676a
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Shared/src/main/java/com/example/android/wearable/speedtracker/common/LocationEntry.java
@@ -0,0 +1,61 @@
+/*
+ * 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.speedtracker.common;
+
+import java.util.Calendar;
+
+/**
+ * A class that models a GPS location point with additional information about the time that the data
+ * was obtained.
+ */
+public class LocationEntry {
+
+ public double latitude;
+ public double longitude;
+ public Calendar calendar;
+ public String day;
+
+ public LocationEntry(Calendar calendar, double latitude, double longitude) {
+ this.calendar = calendar;
+ this.latitude = latitude;
+ this.longitude = longitude;
+ this.day = Utils.getHashedDay(calendar);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ LocationEntry that = (LocationEntry) o;
+
+ if (calendar.getTimeInMillis() != that.calendar.getTimeInMillis()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return calendar.hashCode();
+ }
+}
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Shared/src/main/java/com/example/android/wearable/speedtracker/common/Utils.java b/wearable/wear/SpeedTracker/Shared/src/main/java/com/example/android/wearable/speedtracker/common/Utils.java
new file mode 100644
index 0000000..a2f300f
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Shared/src/main/java/com/example/android/wearable/speedtracker/common/Utils.java
@@ -0,0 +1,37 @@
+/*
+ * 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.speedtracker.common;
+
+import java.util.Calendar;
+
+/**
+ * A utility class that is used in both the handset and wearable apps.
+ */
+public class Utils {
+
+ /**
+ * Builds a simple hash for a day by concatenating year and day of year together. Note that two
+ * {@link java.util.Calendar} inputs that fall on the same day will be hashed to the same
+ * string.
+ */
+ public static String getHashedDay(Calendar day) {
+ return day.get(Calendar.YEAR) + "-" + day.get(Calendar.DAY_OF_YEAR);
+ }
+
+ private Utils() {
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Wearable/proguard-rules.pro b/wearable/wear/SpeedTracker/Wearable/proguard-rules.pro
new file mode 100644
index 0000000..0661c7b
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${SDK_DIR}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/AndroidManifest.xml b/wearable/wear/SpeedTracker/Wearable/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..750f052
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.wearable.speedtracker">
+
+ <uses-feature android:name="android.hardware.type.watch"/>
+ <uses-feature android:name="android.hardware.location.gps" android:required="true" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>\
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+
+ <uses-sdk
+ android:minSdkVersion="20"
+ android:targetSdkVersion="20" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.DeviceDefault">
+ <meta-data android:name="com.google.android.gms.version"
+ android:value="@integer/google_play_services_version"/>
+ <activity
+ android:name=".WearableMainActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="com.example.android.wearable.speedtracker.SpeedPickerActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".ui.LocationSettingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/SpeedPickerActivity.java b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/SpeedPickerActivity.java
new file mode 100644
index 0000000..d55d7df
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/SpeedPickerActivity.java
@@ -0,0 +1,87 @@
+/*
+ * 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.speedtracker;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.wearable.view.WearableListView;
+import android.widget.TextView;
+
+import com.example.android.wearable.speedtracker.ui.SpeedPickerListAdapter;
+
+/**
+ * An activity that presents a list of speeds to user and allows user to pick one, to be used as
+ * the current speed limit.
+ */
+public class SpeedPickerActivity extends Activity implements WearableListView.ClickListener {
+
+ /* Speeds, in mph, that will be shown on the list */
+ private int[] speeds = {25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75};
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.speed_picker_activity);
+
+ final TextView header = (TextView) findViewById(R.id.header);
+
+ // Get the list component from the layout of the activity
+ WearableListView listView = (WearableListView) findViewById(R.id.wearable_list);
+
+ // Assign an adapter to the list
+ listView.setAdapter(new SpeedPickerListAdapter(this, speeds));
+
+ // Set a click listener
+ listView.setClickListener(this);
+
+ listView.addOnScrollListener(new WearableListView.OnScrollListener() {
+ @Override
+ public void onScroll(int i) {
+ }
+
+ @Override
+ public void onAbsoluteScrollChange(int i) {
+ // only scroll the header up from the base position, not down...
+ if (i > 0) {
+ header.setY(-i);
+ }
+ }
+
+ @Override
+ public void onScrollStateChanged(int i) {
+ }
+
+ @Override
+ public void onCentralPositionChanged(int i) {
+ }
+ });
+ }
+
+ @Override
+ public void onClick(WearableListView.ViewHolder viewHolder) {
+ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
+ pref.edit().putInt(WearableMainActivity.PREFS_SPEED_LIMIT_KEY,
+ speeds[viewHolder.getPosition()]).apply();
+ finish();
+ }
+
+ @Override
+ public void onTopEmptyRegionClick() {
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/WearableMainActivity.java b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/WearableMainActivity.java
new file mode 100644
index 0000000..9610f22
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/WearableMainActivity.java
@@ -0,0 +1,349 @@
+/*
+ * 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.speedtracker;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.common.api.Status;
+import com.google.android.gms.location.LocationListener;
+import com.google.android.gms.location.LocationRequest;
+import com.google.android.gms.location.LocationServices;
+import com.google.android.gms.wearable.DataApi;
+import com.google.android.gms.wearable.PutDataMapRequest;
+import com.google.android.gms.wearable.PutDataRequest;
+import com.google.android.gms.wearable.Wearable;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.location.Location;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.example.android.wearable.speedtracker.common.Constants;
+import com.example.android.wearable.speedtracker.common.LocationEntry;
+import com.example.android.wearable.speedtracker.ui.LocationSettingActivity;
+
+import java.util.Calendar;
+
+/**
+ * The main activity for the wearable app. User can pick a speed limit, and after this activity
+ * obtains a fix on the GPS, it starts reporting the speed. In addition to showing the current
+ * speed, if user's speed gets close to the selected speed limit, the color of speed turns yellow
+ * and if the user exceeds the speed limit, it will turn red. In order to show the user that GPS
+ * location data is coming in, a small green dot keeps on blinking while GPS data is available.
+ */
+public class WearableMainActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,
+ GoogleApiClient.OnConnectionFailedListener, LocationListener {
+
+ private static final String TAG = "WearableActivity";
+
+ private static final long UPDATE_INTERVAL_MS = 5 * 1000;
+ private static final long FASTEST_INTERVAL_MS = 5 * 1000;
+
+ public static final float MPH_IN_METERS_PER_SECOND = 2.23694f;
+
+ public static final String PREFS_SPEED_LIMIT_KEY = "speed_limit";
+ public static final int SPEED_LIMIT_DEFAULT_MPH = 45;
+ private static final long INDICATOR_DOT_FADE_AWAY_MS = 500L;
+
+ private GoogleApiClient mGoogleApiClient;
+ private TextView mSpeedLimitText;
+ private TextView mCurrentSpeedText;
+ private ImageView mSaveImageView;
+ private TextView mAcquiringGps;
+ private TextView mCurrentSpeedMphText;
+
+ private int mCurrentSpeedLimit;
+ private float mCurrentSpeed;
+ private View mDot;
+ private Handler mHandler = new Handler();
+ private Calendar mCalendar;
+ private boolean mSaveGpsLocation;
+
+ private enum SpeedState {
+ BELOW(R.color.speed_below), CLOSE(R.color.speed_close), ABOVE(R.color.speed_above);
+
+ private int mColor;
+
+ SpeedState(int color) {
+ mColor = color;
+ }
+
+ int getColor() {
+ return mColor;
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.main_activity);
+ if (!hasGps()) {
+ // If this hardware doesn't support GPS, we prefer to exit.
+ // Note that when such device is connected to a phone with GPS capabilities, the
+ // framework automatically routes the location requests to the phone. For this
+ // application, this would not be desirable so we exit the app but for some other
+ // applications, that might be a valid scenario.
+ Log.w(TAG, "This hardware doesn't have GPS, so we exit");
+ new AlertDialog.Builder(this)
+ .setMessage(getString(R.string.gps_not_available))
+ .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ finish();
+ dialog.cancel();
+ }
+ })
+ .setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ dialog.cancel();
+ finish();
+ }
+ })
+ .setCancelable(false)
+ .create()
+ .show();
+ }
+
+ setupViews();
+ updateSpeedVisibility(false);
+ setSpeedLimit();
+ mGoogleApiClient = new GoogleApiClient.Builder(this)
+ .addApi(LocationServices.API)
+ .addApi(Wearable.API)
+ .addConnectionCallbacks(this)
+ .addOnConnectionFailedListener(this)
+ .build();
+ mGoogleApiClient.connect();
+ }
+
+ private void setupViews() {
+ mSpeedLimitText = (TextView) findViewById(R.id.max_speed_text);
+ mCurrentSpeedText = (TextView) findViewById(R.id.current_speed_text);
+ mSaveImageView = (ImageView) findViewById(R.id.saving);
+ ImageButton settingButton = (ImageButton) findViewById(R.id.settings);
+ mAcquiringGps = (TextView) findViewById(R.id.acquiring_gps);
+ mCurrentSpeedMphText = (TextView) findViewById(R.id.current_speed_mph);
+ mDot = findViewById(R.id.dot);
+
+ settingButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent speedIntent = new Intent(WearableMainActivity.this,
+ SpeedPickerActivity.class);
+ startActivity(speedIntent);
+ }
+ });
+
+ mSaveImageView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent savingIntent = new Intent(WearableMainActivity.this,
+ LocationSettingActivity.class);
+ startActivity(savingIntent);
+ }
+ });
+ }
+
+ private void setSpeedLimit(int speedLimit) {
+ mSpeedLimitText.setText(getString(R.string.speed_limit, speedLimit));
+ }
+
+ private void setSpeedLimit() {
+ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
+ mCurrentSpeedLimit = pref.getInt(PREFS_SPEED_LIMIT_KEY, SPEED_LIMIT_DEFAULT_MPH);
+ setSpeedLimit(mCurrentSpeedLimit);
+ }
+
+ private void setCurrentSpeed(float speed) {
+ mCurrentSpeed = speed;
+ mCurrentSpeedText.setText(String.format(getString(R.string.speed_format), speed));
+ adjustColor();
+ }
+
+ /**
+ * Adjusts the color of the speed based on its value relative to the speed limit.
+ */
+ private void adjustColor() {
+ SpeedState state = SpeedState.ABOVE;
+ if (mCurrentSpeed <= mCurrentSpeedLimit - 5) {
+ state = SpeedState.BELOW;
+ } else if (mCurrentSpeed <= mCurrentSpeedLimit) {
+ state = SpeedState.CLOSE;
+ }
+
+ mCurrentSpeedText.setTextColor(getResources().getColor(state.getColor()));
+ }
+
+ @Override
+ public void onConnected(Bundle bundle) {
+ LocationRequest locationRequest = LocationRequest.create()
+ .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
+ .setInterval(UPDATE_INTERVAL_MS)
+ .setFastestInterval(FASTEST_INTERVAL_MS);
+
+ LocationServices.FusedLocationApi
+ .requestLocationUpdates(mGoogleApiClient, locationRequest, this)
+ .setResultCallback(new ResultCallback<Status>() {
+
+ @Override
+ public void onResult(Status status) {
+ if (status.getStatus().isSuccess()) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Successfully requested location updates");
+ }
+ } else {
+ Log.e(TAG,
+ "Failed in requesting location updates, "
+ + "status code: "
+ + status.getStatusCode() + ", message: " + status
+ .getStatusMessage());
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onConnectionSuspended(int i) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "onConnectionSuspended(): connection to location client suspended");
+ }
+ LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
+ }
+
+ @Override
+ public void onConnectionFailed(ConnectionResult connectionResult) {
+ Log.e(TAG, "onConnectionFailed(): connection to location client failed");
+ }
+
+ @Override
+ public void onLocationChanged(Location location) {
+ updateSpeedVisibility(true);
+ setCurrentSpeed(location.getSpeed() * MPH_IN_METERS_PER_SECOND);
+ flashDot();
+ addLocationEntry(location.getLatitude(), location.getLongitude());
+ }
+
+ /**
+ * Causes the (green) dot blinks when new GPS location data is acquired.
+ */
+ private void flashDot() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mDot.setVisibility(View.VISIBLE);
+ }
+ });
+ mDot.setVisibility(View.VISIBLE);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mDot.setVisibility(View.INVISIBLE);
+ }
+ }, INDICATOR_DOT_FADE_AWAY_MS);
+ }
+
+ /**
+ * Adjusts the visibility of speed indicator based on the arrival of GPS data.
+ */
+ private void updateSpeedVisibility(boolean speedVisible) {
+ if (speedVisible) {
+ mAcquiringGps.setVisibility(View.GONE);
+ mCurrentSpeedText.setVisibility(View.VISIBLE);
+ mCurrentSpeedMphText.setVisibility(View.VISIBLE);
+ } else {
+ mAcquiringGps.setVisibility(View.VISIBLE);
+ mCurrentSpeedText.setVisibility(View.GONE);
+ mCurrentSpeedMphText.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Adds a data item to the data Layer storage
+ */
+ private void addLocationEntry(double latitude, double longitude) {
+ if (!mSaveGpsLocation || !mGoogleApiClient.isConnected()) {
+ return;
+ }
+ mCalendar.setTimeInMillis(System.currentTimeMillis());
+ LocationEntry entry = new LocationEntry(mCalendar, latitude, longitude);
+ String path = Constants.PATH + "/" + mCalendar.getTimeInMillis();
+ PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(path);
+ putDataMapRequest.getDataMap().putDouble(Constants.KEY_LATITUDE, entry.latitude);
+ putDataMapRequest.getDataMap().putDouble(Constants.KEY_LONGITUDE, entry.longitude);
+ putDataMapRequest.getDataMap()
+ .putLong(Constants.KEY_TIME, entry.calendar.getTimeInMillis());
+ PutDataRequest request = putDataMapRequest.asPutDataRequest();
+ Wearable.DataApi.putDataItem(mGoogleApiClient, request)
+ .setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
+ @Override
+ public void onResult(DataApi.DataItemResult dataItemResult) {
+ if (!dataItemResult.getStatus().isSuccess()) {
+ Log.e(TAG, "AddPoint:onClick(): Failed to set the data, "
+ + "status: " + dataItemResult.getStatus()
+ .getStatusCode());
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (mGoogleApiClient.isConnected()) {
+ LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
+ }
+ mGoogleApiClient.disconnect();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ mCalendar = Calendar.getInstance();
+ setSpeedLimit();
+ adjustColor();
+ updateRecordingIcon();
+ }
+
+ private void updateRecordingIcon() {
+ mSaveGpsLocation = LocationSettingActivity.getGpsRecordingStatusFromPreferences(this);
+ mSaveImageView.setImageResource(mSaveGpsLocation ? R.drawable.ic_file_download_googblue_24dp
+ : R.drawable.ic_file_download_grey600_24dp);
+ }
+
+ /**
+ * Returns {@code true} if this device has the GPS capabilities.
+ */
+ private boolean hasGps() {
+ return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS);
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/LocationSettingActivity.java b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/LocationSettingActivity.java
new file mode 100644
index 0000000..1f8be71
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/LocationSettingActivity.java
@@ -0,0 +1,75 @@
+/*
+ * 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.speedtracker.ui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.View;
+import android.widget.TextView;
+
+import com.example.android.wearable.speedtracker.R;
+
+/**
+ * A simple activity that allows the user to start or stop recording of GPS location data.
+ */
+public class LocationSettingActivity extends Activity {
+
+ private static final String PREFS_KEY_SAVE_GPS = "save-gps";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.saving_activity);
+ TextView textView = (TextView) findViewById(R.id.textView);
+ textView.setText(getGpsRecordingStatusFromPreferences(this) ? R.string.stop_saving_gps
+ : R.string.start_saving_gps);
+
+ }
+
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.submitBtn:
+ saveGpsRecordingStatusToPreferences(LocationSettingActivity.this,
+ !getGpsRecordingStatusFromPreferences(this));
+ break;
+ case R.id.cancelBtn:
+ break;
+ }
+ finish();
+ }
+
+ /**
+ * Get the persisted value for whether the app should record the GPS location data or not. If
+ * there is no prior value persisted, it returns {@code false}.
+ */
+ public static boolean getGpsRecordingStatusFromPreferences(Context context) {
+ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
+ return pref.getBoolean(PREFS_KEY_SAVE_GPS, false);
+ }
+
+ /**
+ * Persists the user selection to whether save the GPS location data or not.
+ */
+ public static void saveGpsRecordingStatusToPreferences(Context context, boolean value) {
+ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
+ pref.edit().putBoolean(PREFS_KEY_SAVE_GPS, value).apply();
+
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerLayout.java b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerLayout.java
new file mode 100644
index 0000000..9fd882d
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerLayout.java
@@ -0,0 +1,104 @@
+/*
+ * 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.speedtracker.ui;
+
+import android.content.Context;
+import android.graphics.drawable.GradientDrawable;
+import android.support.wearable.view.WearableListView;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.example.android.wearable.speedtracker.R;
+
+/**
+ * A simple extension of the {@link android.widget.LinearLayout} to represent a single item in a
+ * {@link android.support.wearable.view.WearableListView}.
+ */
+public class SpeedPickerLayout extends LinearLayout implements WearableListView.Item {
+
+ private final float mFadedTextAlpha;
+ private final int mFadedCircleColor;
+ private final int mChosenCircleColor;
+ private ImageView mCircle;
+ private float mScale;
+ private TextView mName;
+
+ public SpeedPickerLayout(Context context) {
+ this(context, null);
+ }
+
+ public SpeedPickerLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SpeedPickerLayout(Context context, AttributeSet attrs,
+ int defStyle) {
+ super(context, attrs, defStyle);
+ mFadedTextAlpha = getResources()
+ .getInteger(R.integer.action_text_faded_alpha) / 100f;
+ mFadedCircleColor = getResources().getColor(R.color.grey);
+ mChosenCircleColor = getResources().getColor(R.color.blue);
+ }
+
+ // Get references to the icon and text in the item layout definiton
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mCircle = (ImageView) findViewById(R.id.circle);
+ mName = (TextView) findViewById(R.id.name);
+ }
+
+ // Provide scaling values for WearableListView animations
+ @Override
+ public float getProximityMinValue() {
+ return 1f;
+ }
+
+ @Override
+ public float getProximityMaxValue() {
+ return 1.6f;
+ }
+
+ @Override
+ public float getCurrentProximityValue() {
+ return mScale;
+ }
+
+ // Scale the icon for WearableListView animations
+ @Override
+ public void setScalingAnimatorValue(float scale) {
+ mScale = scale;
+ mCircle.setScaleX(scale);
+ mCircle.setScaleY(scale);
+ }
+
+ // Change color of the icon, remove fading from the text
+ @Override
+ public void onScaleUpStart() {
+ mName.setAlpha(1f);
+ ((GradientDrawable) mCircle.getDrawable()).setColor(mChosenCircleColor);
+ }
+
+ // Change the color of the icon, fade the text
+ @Override
+ public void onScaleDownStart() {
+ ((GradientDrawable) mCircle.getDrawable()).setColor(mFadedCircleColor);
+ mName.setAlpha(mFadedTextAlpha);
+ }
+}
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerListAdapter.java b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerListAdapter.java
new file mode 100644
index 0000000..e3b284b
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/java/com/example/android/wearable/speedtracker/ui/SpeedPickerListAdapter.java
@@ -0,0 +1,89 @@
+/*
+ * 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.speedtracker.ui;
+
+import android.content.Context;
+import android.support.wearable.view.WearableListView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.example.android.wearable.speedtracker.R;
+
+/**
+ * A {@link android.support.wearable.view.WearableListView.Adapter} that is used to populate the
+ * list of speeds.
+ */
+public class SpeedPickerListAdapter extends WearableListView.Adapter {
+
+ private int[] mDataSet;
+ private final Context mContext;
+ private final LayoutInflater mInflater;
+
+ public SpeedPickerListAdapter(Context context, int[] dataset) {
+ mContext = context;
+ mInflater = LayoutInflater.from(context);
+ mDataSet = dataset;
+ }
+
+ public static class ItemViewHolder extends WearableListView.ViewHolder {
+
+ private TextView mTextView;
+
+ public ItemViewHolder(View itemView) {
+ super(itemView);
+ // find the text view within the custom item's layout
+ mTextView = (TextView) itemView.findViewById(R.id.name);
+ }
+ }
+
+ /**
+ * Create new views for list items (invoked by the WearableListView's layout manager)
+ */
+ @Override
+ public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent,
+ int viewType) {
+ // Inflate our custom layout for list items
+ return new ItemViewHolder(mInflater.inflate(R.layout.speed_picker_item_layout, null));
+ }
+
+ /**
+ * Replaces the contents of a list item. Instead of creating new views, the list tries to
+ * recycle existing ones. This is invoked by the WearableListView's layout manager.
+ */
+ @Override
+ public void onBindViewHolder(WearableListView.ViewHolder holder,
+ int position) {
+ // retrieve the text view
+ ItemViewHolder itemHolder = (ItemViewHolder) holder;
+ TextView view = itemHolder.mTextView;
+ // replace text contents
+ view.setText(mContext.getString(R.string.speed_for_list, mDataSet[position]));
+ // replace list item's metadata
+ holder.itemView.setTag(position);
+ }
+
+ /**
+ * Return the size of the data set (invoked by the WearableListView's layout manager).
+ */
+ @Override
+ public int getItemCount() {
+ return mDataSet.length;
+ }
+
+}
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-hdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..2275b45
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-mdpi/ic_boot_cancel.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-mdpi/ic_boot_cancel.png
new file mode 100644
index 0000000..9b44979
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-mdpi/ic_boot_cancel.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-mdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..25015af
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-nodpi/dot.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-nodpi/dot.png
new file mode 100644
index 0000000..37cfba6
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-nodpi/dot.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_cancel_80.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_cancel_80.png
new file mode 100644
index 0000000..46de043
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_cancel_80.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_confirmation.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_confirmation.png
new file mode 100755
index 0000000..aba4b3e
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_confirmation.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_confirmation_80.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_confirmation_80.png
new file mode 100644
index 0000000..faeb9e4
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_confirmation_80.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..8aee870
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_black_24dp.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_black_24dp.png
new file mode 100644
index 0000000..0ec94b2
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_black_24dp.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_googblue_24dp.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_googblue_24dp.png
new file mode 100644
index 0000000..00b3e05
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_googblue_24dp.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_grey600_24dp.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_grey600_24dp.png
new file mode 100644
index 0000000..c7e86f9
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_grey600_24dp.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_white_24dp.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_white_24dp.png
new file mode 100644
index 0000000..a57e72f
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_file_download_white_24dp.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..7008a2f
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png
new file mode 100644
index 0000000..bce161d
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_googblue_24dp.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_googblue_24dp.png
new file mode 100644
index 0000000..c1b1725
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_googblue_24dp.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_grey600_24dp.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_grey600_24dp.png
new file mode 100644
index 0000000..5eba9e8
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_grey600_24dp.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png
new file mode 100644
index 0000000..97e9ca9
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxxhdpi/ic_launcher.png b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..c31ab73
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable/settings.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable/settings.xml
new file mode 100644
index 0000000..7af58c6
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable/settings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_settings_googblue_24dp" android:state_pressed="true" />
+ <item android:drawable="@drawable/ic_settings_grey600_24dp" android:state_focused="true" />
+ <item android:drawable="@drawable/ic_settings_grey600_24dp" />
+</selector>
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable/wl_circle.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable/wl_circle.xml
new file mode 100644
index 0000000..a06c53a
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/drawable/wl_circle.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="@color/wl_gray"/>
+</shape>
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/main_activity.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/main_activity.xml
new file mode 100644
index 0000000..21f809e
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/main_activity.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#111">
+
+ <View
+ android:id="@+id/center"
+ android:layout_width="1px"
+ android:layout_height="1px"
+ android:layout_centerInParent="true"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:fontFamily="sans-serif-light"
+ android:textSize="17sp"
+ android:textStyle="italic"
+ android:id="@+id/acquiring_gps"
+ android:text="@string/acquiring_gps"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textSize="50sp"
+ android:fontFamily="sans-serif-light"
+ android:id="@+id/current_speed_text"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@+id/center"
+ android:textColor="@color/green"
+ android:layout_marginRight="-10dp"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textSize="18sp"
+ android:text="@string/mph"
+ android:layout_marginLeft="15dp"
+ android:layout_alignBaseline="@+id/current_speed_text"
+ android:id="@+id/current_speed_mph"
+ android:fontFamily="sans-serif-thin"
+ android:layout_toRightOf="@+id/current_speed_text"/>
+
+ <ImageView
+ android:id="@+id/dot"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/current_speed_mph"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="5dp"
+ android:visibility="invisible"
+ android:src="@drawable/dot"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:id="@+id/max_speed_text"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:fontFamily="sans-serif-thin"
+ android:textSize="17sp"
+ android:layout_marginTop="33dp" />
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_file_download_grey600_24dp"
+ android:id="@+id/saving"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:layout_marginBottom="20dp"
+ android:layout_marginLeft="60dp" />
+
+ <ImageButton
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/settings"
+ android:background="@drawable/settings"
+ android:layout_alignParentRight="true"
+ android:layout_alignBottom="@+id/saving"
+ android:layout_marginRight="60dp"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/saving_activity.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/saving_activity.xml
new file mode 100644
index 0000000..c37d959
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/saving_activity.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent" android:layout_height="match_parent">
+ <View
+ android:id="@+id/center"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_centerInParent="true"/>
+ <TextView
+ android:id="@+id/textView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_above="@id/center"
+ android:layout_marginBottom="18dp"
+ android:fontFamily="sans-serif-light"
+ android:textSize="18sp"
+ android:text="@string/start_saving_gps"/>
+ <android.support.wearable.view.CircledImageView
+ android:id="@+id/cancelBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_below="@id/center"
+ android:layout_toLeftOf="@id/center"
+ android:layout_marginEnd="10dp"
+ android:src="@drawable/ic_cancel_80"
+ app:circle_color="@color/grey"
+ android:onClick="onClick"
+ app:circle_padding="@dimen/circle_padding"
+ app:circle_radius="@dimen/circle_radius"
+ app:circle_radius_pressed="@dimen/circle_radius_pressed" />
+ <android.support.wearable.view.CircledImageView
+ android:id="@+id/submitBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_below="@id/center"
+ android:layout_toRightOf="@id/center"
+ android:layout_marginStart="10dp"
+ android:src="@drawable/ic_confirmation_80"
+ app:circle_color="@color/blue"
+ android:onClick="onClick"
+ app:circle_padding="@dimen/circle_padding"
+ app:circle_radius="@dimen/circle_radius"
+ app:circle_radius_pressed="@dimen/circle_radius_pressed" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/speed_picker_activity.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/speed_picker_activity.xml
new file mode 100644
index 0000000..663988f
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/speed_picker_activity.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<android.support.wearable.view.BoxInsetLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:background="@android:color/black"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ >
+
+ <RelativeLayout
+ android:id="@+id/frame_layout"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ app:layout_box="left|bottom|right">
+
+
+ <android.support.wearable.view.WearableListView
+ android:id="@+id/wearable_list"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+ </android.support.wearable.view.WearableListView>
+ <TextView
+ android:id="@+id/header"
+ android:layout_width="wrap_content"
+ android:layout_height="60dp"
+ android:gravity="bottom"
+ android:textSize="20sp"
+ android:fontFamily="sans-serif-light"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:text="@string/speed_limit_header"/>
+ </RelativeLayout>
+</android.support.wearable.view.BoxInsetLayout>
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/speed_picker_item_layout.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/speed_picker_item_layout.xml
new file mode 100644
index 0000000..7b68908
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/layout/speed_picker_item_layout.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<com.example.android.wearable.speedtracker.ui.SpeedPickerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:gravity="center_vertical"
+ android:layout_width="match_parent"
+ android:layout_height="80dp">
+ <ImageView
+ android:id="@+id/circle"
+ android:layout_height="20dp"
+ android:layout_margin="16dp"
+ android:layout_width="20dp"
+ android:src="@drawable/wl_circle"/>
+ <TextView
+ android:id="@+id/name"
+ android:gravity="center_vertical|left"
+ android:layout_width="wrap_content"
+ android:layout_marginRight="16dp"
+ android:layout_height="match_parent"
+ android:fontFamily="sans-serif-condensed-light"
+ android:lineSpacingExtra="-4sp"
+ android:textColor="@color/text_color"
+ android:textSize="20sp"/>
+</com.example.android.wearable.speedtracker.ui.SpeedPickerLayout>
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/values/colors.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/values/colors.xml
new file mode 100644
index 0000000..a833064
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/values/colors.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources>
+ <color name="wl_blue">#2878ff</color>
+ <color name="wl_gray">#c1c1c1</color>
+ <color name="text_color">#BBB</color>
+ <color name="yellow">#ced020</color>
+ <color name="speed_below">@color/green</color>
+ <color name="speed_close">@color/yellow</color>
+ <color name="speed_above">@color/red</color>
+
+ <color name="cancel">#c1c1c1</color>
+ <color name="cancel_pressed">#838383</color>
+ <color name="lightblue">#2878ff</color>
+</resources>
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/values/dimens.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..2f2eb2a
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/values/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources>
+ <dimen name="pair_button_diameter">40dp</dimen>
+ <dimen name="circle_border_normal_width">10dp</dimen>
+ <dimen name="circle_padding">5dp</dimen>
+ <dimen name="circle_radius">35dp</dimen>
+ <dimen name="circle_radius_pressed">40dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/values/integers.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/values/integers.xml
new file mode 100644
index 0000000..b58f083
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/values/integers.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources>
+ <integer name="action_text_faded_alpha">50</integer>
+</resources>
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/Wearable/src/main/res/values/strings.xml b/wearable/wear/SpeedTracker/Wearable/src/main/res/values/strings.xml
new file mode 100644
index 0000000..dda3ecd
--- /dev/null
+++ b/wearable/wear/SpeedTracker/Wearable/src/main/res/values/strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources>
+ <string name="app_name">Speed Tracker</string>
+ <string name="lat_label">Latitude:</string>
+ <string name="not_available">Not Available</string>
+ <string name="lon_label">Longitude:</string>
+ <string name="speed_label">Speed:</string>
+ <string name="activity_label">Activity:</string>
+ <string name="timestamp_label">Time:</string>
+ <string name="speed_limit">Limit: %1$d mph</string>
+ <string name="acquiring_gps">Acquiring GPS Fix ...</string>
+ <string name="speed_for_list">%1$d mph</string>
+ <string name="start_saving_gps">Start Recording GPS?</string>
+ <string name="stop_saving_gps">Stop Recording GPS?</string>
+ <string name="mph">mph</string>
+ <string name="speed_limit_header">Speed Limit</string>
+ <string name="gps_not_available">GPS not available.</string>
+ <string name="ok">OK</string>
+ <string name="speed_format">%.0f</string>
+</resources>
diff --git a/wearable/wear/SpeedTracker/build.gradle b/wearable/wear/SpeedTracker/build.gradle
new file mode 100644
index 0000000..be1fa82
--- /dev/null
+++ b/wearable/wear/SpeedTracker/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../build"
+ pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/wearable/wear/SpeedTracker/buildSrc/build.gradle b/wearable/wear/SpeedTracker/buildSrc/build.gradle
new file mode 100644
index 0000000..e344a8c
--- /dev/null
+++ b/wearable/wear/SpeedTracker/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/wearable/wear/SpeedTracker/gradle.properties b/wearable/wear/SpeedTracker/gradle.properties
new file mode 100644
index 0000000..5d08ba7
--- /dev/null
+++ b/wearable/wear/SpeedTracker/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Settings specified in this file will override any Gradle settings
+# configured through the IDE.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
\ No newline at end of file
diff --git a/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.jar b/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.properties b/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1e61d1f
--- /dev/null
+++ b/wearable/wear/SpeedTracker/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/wearable/wear/SpeedTracker/gradlew b/wearable/wear/SpeedTracker/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/wearable/wear/SpeedTracker/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/wearable/wear/SpeedTracker/gradlew.bat b/wearable/wear/SpeedTracker/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/wearable/wear/SpeedTracker/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/wearable/wear/SpeedTracker/settings.gradle b/wearable/wear/SpeedTracker/settings.gradle
new file mode 100644
index 0000000..8522c57
--- /dev/null
+++ b/wearable/wear/SpeedTracker/settings.gradle
@@ -0,0 +1 @@
+include ':Application', ':Wearable', ':Shared'
diff --git a/wearable/wear/SpeedTracker/template-params.xml b/wearable/wear/SpeedTracker/template-params.xml
new file mode 100644
index 0000000..704583d
--- /dev/null
+++ b/wearable/wear/SpeedTracker/template-params.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<sample>
+ <name>Speed Tracker</name>
+ <group>Wearable</group>
+ <package>com.example.android.wearable.speedtracker</package>
+
+`
+
+ <!-- change minSdk if needed-->
+ <minSdk>20</minSdk>
+
+
+ <strings>
+ <intro>
+ <![CDATA[
+This sample uses the FusedLocation APIs of GMS on those
+devices that have a hardware GPS built in. In those cases,
+this sample provides a simple screen that shows the current
+speed of the device on the watch. User can set a speed limit
+and if the speed approaches that limit, it changes the color
+to yellow and if it exceeds the limit, it turns red. User
+can also enable recording of coordinates and when it pairs
+back with the phone, this data will be synced with the phone
+component of the app and user can see a track made of those
+coordinates on a map on the phone.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+ <template src="Wear"/>
+ <common src="logger"/>
+ <common src="activities"/>
+
+</sample>