summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Camera2Tests/CameraToo/Android.mk23
-rw-r--r--tests/Camera2Tests/CameraToo/AndroidManifest.xml33
-rw-r--r--tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml23
-rw-r--r--tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java437
-rw-r--r--tests/Camera2Tests/CameraToo/tests/Android.mk25
-rw-r--r--tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml29
-rw-r--r--tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java189
-rw-r--r--tests/JobSchedulerTestApp/Android.mk15
-rw-r--r--tests/JobSchedulerTestApp/AndroidManifest.xml32
-rw-r--r--tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.pngbin0 -> 5473 bytes
-rw-r--r--tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.pngbin0 -> 3298 bytes
-rw-r--r--tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.pngbin0 -> 856 bytes
-rw-r--r--tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.pngbin0 -> 7401 bytes
-rw-r--r--tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 12074 bytes
-rw-r--r--tests/JobSchedulerTestApp/res/layout/activity_main.xml125
-rw-r--r--tests/JobSchedulerTestApp/res/values-v11/styles.xml28
-rw-r--r--tests/JobSchedulerTestApp/res/values-v14/styles.xml29
-rw-r--r--tests/JobSchedulerTestApp/res/values/color.xml21
-rw-r--r--tests/JobSchedulerTestApp/res/values/strings.xml33
-rw-r--r--tests/JobSchedulerTestApp/res/values/styles.xml37
-rw-r--r--tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java169
-rw-r--r--tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java119
-rw-r--r--tests/VoiceEnrollment/Android.mk12
-rw-r--r--tests/VoiceEnrollment/AndroidManifest.xml16
-rw-r--r--tests/VoiceEnrollment/res/xml/enrollment_application.xml23
-rw-r--r--tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java23
-rw-r--r--tests/VoiceInteraction/AndroidManifest.xml4
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java5
28 files changed, 1448 insertions, 2 deletions
diff --git a/tests/Camera2Tests/CameraToo/Android.mk b/tests/Camera2Tests/CameraToo/Android.mk
new file mode 100644
index 0000000..7e5911d
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/Android.mk
@@ -0,0 +1,23 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := CameraToo
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Camera2Tests/CameraToo/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
new file mode 100644
index 0000000..a92b5d8
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.camera2.cameratoo">
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application android:label="CameraToo">
+ <activity
+ android:name=".CameraTooActivity"
+ android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml
new file mode 100644
index 0000000..f93f177
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.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.
+-->
+
+<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/mainSurfaceView"
+ android:layout_height="fill_parent"
+ android:layout_width="fill_parent"
+ android:onClick="onClickOnSurfaceView" />
diff --git a/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java
new file mode 100644
index 0000000..c630bad
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java
@@ -0,0 +1,437 @@
+/*
+ * 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.
+ */
+
+package com.example.android.camera2.cameratoo;
+
+import android.app.Activity;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Size;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * A basic demonstration of how to write a point-and-shoot camera app against the new
+ * android.hardware.camera2 API.
+ */
+public class CameraTooActivity extends Activity {
+ /** Output files will be saved as /sdcard/Pictures/cameratoo*.jpg */
+ static final String CAPTURE_FILENAME_PREFIX = "cameratoo";
+ /** Tag to distinguish log prints. */
+ static final String TAG = "CameraToo";
+
+ /** An additional thread for running tasks that shouldn't block the UI. */
+ HandlerThread mBackgroundThread;
+ /** Handler for running tasks in the background. */
+ Handler mBackgroundHandler;
+ /** Handler for running tasks on the UI thread. */
+ Handler mForegroundHandler;
+ /** View for displaying the camera preview. */
+ SurfaceView mSurfaceView;
+ /** Used to retrieve the captured image when the user takes a snapshot. */
+ ImageReader mCaptureBuffer;
+ /** Handle to the Android camera services. */
+ CameraManager mCameraManager;
+ /** The specific camera device that we're using. */
+ CameraDevice mCamera;
+ /** Our image capture session. */
+ CameraCaptureSession mCaptureSession;
+
+ /**
+ * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
+ * width and height are at least as large as the respective requested values.
+ * @param choices The list of sizes that the camera supports for the intended output class
+ * @param width The minimum desired width
+ * @param height The minimum desired height
+ * @return The optimal {@code Size}, or an arbitrary one if none were big enough
+ */
+ static Size chooseBigEnoughSize(Size[] choices, int width, int height) {
+ // Collect the supported resolutions that are at least as big as the preview Surface
+ List<Size> bigEnough = new ArrayList<Size>();
+ for (Size option : choices) {
+ if (option.getWidth() >= width && option.getHeight() >= height) {
+ bigEnough.add(option);
+ }
+ }
+
+ // Pick the smallest of those, assuming we found any
+ if (bigEnough.size() > 0) {
+ return Collections.min(bigEnough, new CompareSizesByArea());
+ } else {
+ Log.e(TAG, "Couldn't find any suitable preview size");
+ return choices[0];
+ }
+ }
+
+ /**
+ * Compares two {@code Size}s based on their areas.
+ */
+ static class CompareSizesByArea implements Comparator<Size> {
+ @Override
+ public int compare(Size lhs, Size rhs) {
+ // We cast here to ensure the multiplications won't overflow
+ return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
+ (long) rhs.getWidth() * rhs.getHeight());
+ }
+ }
+
+ /**
+ * Called when our {@code Activity} gains focus. <p>Starts initializing the camera.</p>
+ */
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // Start a background thread to manage camera requests
+ mBackgroundThread = new HandlerThread("background");
+ mBackgroundThread.start();
+ mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+ mForegroundHandler = new Handler(getMainLooper());
+
+ mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
+
+ // Inflate the SurfaceView, set it as the main layout, and attach a listener
+ View layout = getLayoutInflater().inflate(R.layout.mainactivity, null);
+ mSurfaceView = (SurfaceView) layout.findViewById(R.id.mainSurfaceView);
+ mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
+ setContentView(mSurfaceView);
+
+ // Control flow continues in mSurfaceHolderCallback.surfaceChanged()
+ }
+
+ /**
+ * Called when our {@code Activity} loses focus. <p>Tears everything back down.</p>
+ */
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ try {
+ // Ensure SurfaceHolderCallback#surfaceChanged() will run again if the user returns
+ mSurfaceView.getHolder().setFixedSize(/*width*/0, /*height*/0);
+
+ // Cancel any stale preview jobs
+ if (mCaptureSession != null) {
+ mCaptureSession.close();
+ mCaptureSession = null;
+ }
+ } finally {
+ if (mCamera != null) {
+ mCamera.close();
+ mCamera = null;
+ }
+ }
+
+ // Finish processing posted messages, then join on the handling thread
+ mBackgroundThread.quitSafely();
+ try {
+ mBackgroundThread.join();
+ } catch (InterruptedException ex) {
+ Log.e(TAG, "Background worker thread was interrupted while joined", ex);
+ }
+
+ // Close the ImageReader now that the background thread has stopped
+ if (mCaptureBuffer != null) mCaptureBuffer.close();
+ }
+
+ /**
+ * Called when the user clicks on our {@code SurfaceView}, which has ID {@code mainSurfaceView}
+ * as defined in the {@code mainactivity.xml} layout file. <p>Captures a full-resolution image
+ * and saves it to permanent storage.</p>
+ */
+ public void onClickOnSurfaceView(View v) {
+ if (mCaptureSession != null) {
+ try {
+ CaptureRequest.Builder requester =
+ mCamera.createCaptureRequest(mCamera.TEMPLATE_STILL_CAPTURE);
+ requester.addTarget(mCaptureBuffer.getSurface());
+ try {
+ // This handler can be null because we aren't actually attaching any callback
+ mCaptureSession.capture(requester.build(), /*listener*/null, /*handler*/null);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to file actual capture request", ex);
+ }
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to build actual capture request", ex);
+ }
+ } else {
+ Log.e(TAG, "User attempted to perform a capture outside our session");
+ }
+
+ // Control flow continues in mImageCaptureListener.onImageAvailable()
+ }
+
+ /**
+ * Callbacks invoked upon state changes in our {@code SurfaceView}.
+ */
+ final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+ /** The camera device to use, or null if we haven't yet set a fixed surface size. */
+ private String mCameraId;
+
+ /** Whether we received a change callback after setting our fixed surface size. */
+ private boolean mGotSecondCallback;
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ // This is called every time the surface returns to the foreground
+ Log.i(TAG, "Surface created");
+ mCameraId = null;
+ mGotSecondCallback = false;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.i(TAG, "Surface destroyed");
+ holder.removeCallback(this);
+ // We don't stop receiving callbacks forever because onResume() will reattach us
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ // On the first invocation, width and height were automatically set to the view's size
+ if (mCameraId == null) {
+ // Find the device's back-facing camera and set the destination buffer sizes
+ try {
+ for (String cameraId : mCameraManager.getCameraIdList()) {
+ CameraCharacteristics cameraCharacteristics =
+ mCameraManager.getCameraCharacteristics(cameraId);
+ if (cameraCharacteristics.get(cameraCharacteristics.LENS_FACING) ==
+ CameraCharacteristics.LENS_FACING_BACK) {
+ Log.i(TAG, "Found a back-facing camera");
+ StreamConfigurationMap info = cameraCharacteristics
+ .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ // Bigger is better when it comes to saving our image
+ Size largestSize = Collections.max(
+ Arrays.asList(info.getOutputSizes(ImageFormat.JPEG)),
+ new CompareSizesByArea());
+
+ // Prepare an ImageReader in case the user wants to capture images
+ Log.i(TAG, "Capture size: " + largestSize);
+ mCaptureBuffer = ImageReader.newInstance(largestSize.getWidth(),
+ largestSize.getHeight(), ImageFormat.JPEG, /*maxImages*/2);
+ mCaptureBuffer.setOnImageAvailableListener(
+ mImageCaptureListener, mBackgroundHandler);
+
+ // Danger, W.R.! Attempting to use too large a preview size could
+ // exceed the camera bus' bandwidth limitation, resulting in
+ // gorgeous previews but the storage of garbage capture data.
+ Log.i(TAG, "SurfaceView size: " +
+ mSurfaceView.getWidth() + 'x' + mSurfaceView.getHeight());
+ Size optimalSize = chooseBigEnoughSize(
+ info.getOutputSizes(SurfaceHolder.class), width, height);
+
+ // Set the SurfaceHolder to use the camera's largest supported size
+ Log.i(TAG, "Preview size: " + optimalSize);
+ SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
+ surfaceHolder.setFixedSize(optimalSize.getWidth(),
+ optimalSize.getHeight());
+
+ mCameraId = cameraId;
+ return;
+
+ // Control flow continues with this method one more time
+ // (since we just changed our own size)
+ }
+ }
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Unable to list cameras", ex);
+ }
+
+ Log.e(TAG, "Didn't find any back-facing cameras");
+ // This is the second time the method is being invoked: our size change is complete
+ } else if (!mGotSecondCallback) {
+ if (mCamera != null) {
+ Log.e(TAG, "Aborting camera open because it hadn't been closed");
+ return;
+ }
+
+ // Open the camera device
+ try {
+ mCameraManager.openCamera(mCameraId, mCameraStateListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to configure output surface", ex);
+ }
+ mGotSecondCallback = true;
+
+ // Control flow continues in mCameraStateListener.onOpened()
+ }
+ }};
+
+ /**
+ * Calledbacks invoked upon state changes in our {@code CameraDevice}. <p>These are run on
+ * {@code mBackgroundThread}.</p>
+ */
+ final CameraDevice.StateListener mCameraStateListener =
+ new CameraDevice.StateListener() {
+ @Override
+ public void onOpened(CameraDevice camera) {
+ Log.i(TAG, "Successfully opened camera");
+ mCamera = camera;
+ try {
+ List<Surface> outputs = Arrays.asList(
+ mSurfaceView.getHolder().getSurface(), mCaptureBuffer.getSurface());
+ camera.createCaptureSession(outputs, mCaptureSessionListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to create a capture session", ex);
+ }
+
+ // Control flow continues in mCaptureSessionListener.onConfigured()
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice camera) {
+ Log.e(TAG, "Camera was disconnected");
+ }
+
+ @Override
+ public void onError(CameraDevice camera, int error) {
+ Log.e(TAG, "State error on device '" + camera.getId() + "': code " + error);
+ }};
+
+ /**
+ * Callbacks invoked upon state changes in our {@code CameraCaptureSession}. <p>These are run on
+ * {@code mBackgroundThread}.</p>
+ */
+ final CameraCaptureSession.StateListener mCaptureSessionListener =
+ new CameraCaptureSession.StateListener() {
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ Log.i(TAG, "Finished configuring camera outputs");
+ mCaptureSession = session;
+
+ SurfaceHolder holder = mSurfaceView.getHolder();
+ if (holder != null) {
+ try {
+ // Build a request for preview footage
+ CaptureRequest.Builder requestBuilder =
+ mCamera.createCaptureRequest(mCamera.TEMPLATE_PREVIEW);
+ requestBuilder.addTarget(holder.getSurface());
+ CaptureRequest previewRequest = requestBuilder.build();
+
+ // Start displaying preview images
+ try {
+ session.setRepeatingRequest(previewRequest, /*listener*/null,
+ /*handler*/null);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to make repeating preview request", ex);
+ }
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to build preview request", ex);
+ }
+ }
+ else {
+ Log.e(TAG, "Holder didn't exist when trying to formulate preview request");
+ }
+ }
+
+ @Override
+ public void onClosed(CameraCaptureSession session) {
+ mCaptureSession = null;
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ Log.e(TAG, "Configuration error on device '" + mCamera.getId());
+ }};
+
+ /**
+ * Callback invoked when we've received a JPEG image from the camera.
+ */
+ final ImageReader.OnImageAvailableListener mImageCaptureListener =
+ new ImageReader.OnImageAvailableListener() {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ // Save the image once we get a chance
+ mBackgroundHandler.post(new CapturedImageSaver(reader.acquireNextImage()));
+
+ // Control flow continues in CapturedImageSaver#run()
+ }};
+
+ /**
+ * Deferred processor responsible for saving snapshots to disk. <p>This is run on
+ * {@code mBackgroundThread}.</p>
+ */
+ static class CapturedImageSaver implements Runnable {
+ /** The image to save. */
+ private Image mCapture;
+
+ public CapturedImageSaver(Image capture) {
+ mCapture = capture;
+ }
+
+ @Override
+ public void run() {
+ try {
+ // Choose an unused filename under the Pictures/ directory
+ File file = File.createTempFile(CAPTURE_FILENAME_PREFIX, ".jpg",
+ Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES));
+ try (FileOutputStream ostream = new FileOutputStream(file)) {
+ Log.i(TAG, "Retrieved image is" +
+ (mCapture.getFormat() == ImageFormat.JPEG ? "" : "n't") + " a JPEG");
+ ByteBuffer buffer = mCapture.getPlanes()[0].getBuffer();
+ Log.i(TAG, "Captured image size: " +
+ mCapture.getWidth() + 'x' + mCapture.getHeight());
+
+ // Write the image out to the chosen file
+ byte[] jpeg = new byte[buffer.remaining()];
+ buffer.get(jpeg);
+ ostream.write(jpeg);
+ } catch (FileNotFoundException ex) {
+ Log.e(TAG, "Unable to open output file for writing", ex);
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to write the image to the output file", ex);
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "Unable to create a new output file", ex);
+ } finally {
+ mCapture.close();
+ }
+ }
+ }
+}
diff --git a/tests/Camera2Tests/CameraToo/tests/Android.mk b/tests/Camera2Tests/CameraToo/tests/Android.mk
new file mode 100644
index 0000000..0b58243
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/Android.mk
@@ -0,0 +1,25 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := CameraTooTests
+LOCAL_INSTRUMENTATION_FOR := CameraToo
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml
new file mode 100644
index 0000000..30210ba
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.camera2.cameratoo.tests">
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application android:label="CameraToo">
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.example.android.camera2.cameratoo"
+ android:label="CameraToo tests" />
+</manifest>
diff --git a/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java
new file mode 100644
index 0000000..3acca5a
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+package com.example.android.camera2.cameratoo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.media.Image;
+import android.os.Environment;
+import android.util.Size;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.example.android.camera2.cameratoo.CameraTooActivity;
+import org.junit.Test;
+
+public class CameraTooTest {
+ private <T> void assertComparatorEq(T lhs, T rhs, Comparator<T> rel) {
+ assertEquals(String.format("%s should be equal to %s", lhs, rhs), rel.compare(lhs, rhs), 0);
+ assertEquals(String.format("%s should be equal to %s (reverse check)", lhs, rhs),
+ rel.compare(rhs, lhs), 0);
+ }
+
+ private <T> void assertComparatorLt(T lhs, T rhs, Comparator<T> rel) {
+ assertTrue(String.format("%s should be less than %s", lhs, rhs), rel.compare(lhs, rhs) < 0);
+ assertTrue(String.format("%s should be less than %s (reverse check)", lhs, rhs),
+ rel.compare(rhs, lhs) > 0);
+ }
+
+ @Test
+ public void compareSizesByArea() {
+ Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
+ Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
+ Size largeSquare = new Size(5, 5);
+ Comparator<Size> rel = new CameraTooActivity.CompareSizesByArea();
+
+ assertComparatorEq(empty, fatAndFlat, rel);
+ assertComparatorEq(empty, tallAndThin, rel);
+ assertComparatorEq(fatAndFlat, empty, rel);
+ assertComparatorEq(fatAndFlat, tallAndThin, rel);
+ assertComparatorEq(tallAndThin, empty, rel);
+ assertComparatorEq(tallAndThin, fatAndFlat, rel);
+
+ assertComparatorEq(smallSquare, horizRect, rel);
+ assertComparatorEq(smallSquare, vertRect, rel);
+ assertComparatorEq(horizRect, smallSquare, rel);
+ assertComparatorEq(horizRect, vertRect, rel);
+ assertComparatorEq(vertRect, smallSquare, rel);
+ assertComparatorEq(vertRect, horizRect, rel);
+
+ assertComparatorLt(empty, smallSquare, rel);
+ assertComparatorLt(empty, horizRect, rel);
+ assertComparatorLt(empty, vertRect, rel);
+
+ assertComparatorLt(fatAndFlat, smallSquare, rel);
+ assertComparatorLt(fatAndFlat, horizRect, rel);
+ assertComparatorLt(fatAndFlat, vertRect, rel);
+
+ assertComparatorLt(tallAndThin, smallSquare, rel);
+ assertComparatorLt(tallAndThin, horizRect, rel);
+ assertComparatorLt(tallAndThin, vertRect, rel);
+
+ assertComparatorLt(empty, largeSquare, rel);
+ assertComparatorLt(fatAndFlat, largeSquare, rel);
+ assertComparatorLt(tallAndThin, largeSquare, rel);
+ assertComparatorLt(smallSquare, largeSquare, rel);
+ assertComparatorLt(horizRect, largeSquare, rel);
+ assertComparatorLt(vertRect, largeSquare, rel);
+ }
+
+ private void assertOptimalSize(Size[] options, int minWidth, int minHeight, Size expected) {
+ Size verdict = CameraTooActivity.chooseBigEnoughSize(options, minWidth, minHeight);
+ assertEquals(String.format("Expected optimal size %s but got %s", expected, verdict),
+ verdict, expected);
+ }
+
+ @Test
+ public void chooseBigEnoughSize() {
+ Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
+ Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
+ Size largeSquare = new Size(5, 5);
+ Size[] siz =
+ { empty, fatAndFlat, tallAndThin, smallSquare, horizRect, vertRect, largeSquare };
+
+ assertOptimalSize(siz, 0, 0, empty);
+
+ assertOptimalSize(siz, 1, 0, fatAndFlat);
+ assertOptimalSize(siz, 0, 1, tallAndThin);
+
+ assertOptimalSize(siz, 4, 4, smallSquare);
+ assertOptimalSize(siz, 1, 1, smallSquare);
+ assertOptimalSize(siz, 2, 1, smallSquare);
+ assertOptimalSize(siz, 1, 2, smallSquare);
+ assertOptimalSize(siz, 3, 4, smallSquare);
+ assertOptimalSize(siz, 4, 3, smallSquare);
+
+ assertOptimalSize(siz, 8, 2, horizRect);
+ assertOptimalSize(siz, 5, 1, horizRect);
+ assertOptimalSize(siz, 5, 2, horizRect);
+
+ assertOptimalSize(siz, 2, 8, vertRect);
+ assertOptimalSize(siz, 1, 5, vertRect);
+ assertOptimalSize(siz, 2, 5, vertRect);
+
+ assertOptimalSize(siz, 5, 5, largeSquare);
+ assertOptimalSize(siz, 3, 5, largeSquare);
+ assertOptimalSize(siz, 5, 3, largeSquare);
+ }
+
+ private static final FilenameFilter OUTPUT_FILE_DECIDER = new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String filename) {
+ return filename.indexOf("cameratoo") == 0 &&
+ filename.indexOf(".jpg") == filename.length() - ".jpg".length();
+ }};
+
+ private static <T> Set<T> newlyAddedElements(Set<T> before, Set<T> after) {
+ Set<T> result = new HashSet<T>(after);
+ result.removeAll(before);
+ return result;
+ }
+
+ @Test
+ public void capturedImageSaver() throws FileNotFoundException, IOException {
+ ByteBuffer buf = ByteBuffer.allocate(25);
+ for(int index = 0; index < buf.capacity(); ++index)
+ buf.put(index, (byte) index);
+
+ Image.Plane plane = mock(Image.Plane.class);
+ when(plane.getBuffer()).thenReturn(buf);
+ when(plane.getPixelStride()).thenReturn(1);
+ when(plane.getRowStride()).thenReturn(5);
+
+ Image.Plane[] onlyPlaneThatMatters = { plane };
+ Image image = mock(Image.class);
+ when(image.getPlanes()).thenReturn(onlyPlaneThatMatters);
+ when(image.getWidth()).thenReturn(5);
+ when(image.getHeight()).thenReturn(5);
+
+ File picturesFolder =
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+ Set<File> preListing =
+ new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
+
+ CameraTooActivity.CapturedImageSaver saver =
+ new CameraTooActivity.CapturedImageSaver(image);
+ saver.run();
+
+ Set<File> postListing =
+ new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
+ Set<File> newFiles = newlyAddedElements(preListing, postListing);
+
+ assertEquals(newFiles.size(), 1);
+
+ File picture = newFiles.iterator().next();
+ FileInputStream istream = new FileInputStream(picture);
+
+ for(int count = 0; count < buf.capacity(); ++count) {
+ assertEquals(istream.read(), buf.get(count));
+ }
+ assertEquals(istream.read(), -1);
+ assertTrue(picture.delete());
+ }
+}
diff --git a/tests/JobSchedulerTestApp/Android.mk b/tests/JobSchedulerTestApp/Android.mk
new file mode 100644
index 0000000..7336d8c
--- /dev/null
+++ b/tests/JobSchedulerTestApp/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := JobSchedulerTestApp
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/JobSchedulerTestApp/AndroidManifest.xml b/tests/JobSchedulerTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..9654197
--- /dev/null
+++ b/tests/JobSchedulerTestApp/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.demo.jobSchedulerApp" >
+
+ <uses-sdk
+ android:minSdkVersion="18"
+ android:targetSdkVersion="18" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name="com.android.demo.jobSchedulerApp.MainActivity"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <service
+ android:name=".service.TestJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="true"/>
+ </application>
+
+</manifest>
diff --git a/tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a0f7005
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a085462
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.png b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.png
new file mode 100644
index 0000000..4f5d255
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..4f78eb8
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b198ee3
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/layout/activity_main.xml b/tests/JobSchedulerTestApp/res/layout/activity_main.xml
new file mode 100644
index 0000000..7f4961b
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/layout/activity_main.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="100dp">
+ <TextView
+ android:id="@+id/onstart_textview"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@color/none_received"
+ android:gravity="center"
+ android:text="@string/onstarttask"/>
+ <TextView
+ android:id="@+id/onstop_textview"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@color/none_received"
+ android:gravity="center"
+ android:text="@string/onstoptask"/>
+ </LinearLayout>
+ <Button
+ android:id="@+id/finished_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="20dp"
+ android:layout_marginBottom="5dp"
+ android:onClick="finishJob"
+ android:text="@string/finish_job_button_text"/>
+
+ <TextView
+ android:id="@+id/task_params"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/defaultparamtext"
+ android:gravity="center"
+ android:textSize="20dp"
+
+ android:padding="15dp"
+ android:layout_marginBottom="10dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/constraints"
+ android:textSize="18dp"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginLeft="10dp">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/connectivity"
+ android:layout_marginRight="10dp"/>
+ <RadioGroup
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <RadioButton android:id="@+id/checkbox_any"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/any"/>
+ <RadioButton android:id="@+id/checkbox_unmetered"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/unmetered"/>
+ </RadioGroup>
+
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/timing"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="15dp"
+ android:textSize="17dp"
+ android:text="@string/delay"/>
+ <EditText
+ android:id="@+id/delay_time"
+ android:layout_width="60dp"
+ android:layout_height="wrap_content"
+ android:inputType="number"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/deadline"
+ android:textSize="17dp"/>
+ <EditText
+ android:id="@+id/deadline_time"
+ android:layout_width="60dp"
+ android:layout_height="wrap_content"
+ android:inputType="number"/>
+ </LinearLayout>
+
+ </LinearLayout>
+ <Button
+ android:id="@+id/schedule_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="40dp"
+ android:onClick="scheduleJob"
+ android:text="@string/schedule_job_button_text"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/JobSchedulerTestApp/res/values-v11/styles.xml b/tests/JobSchedulerTestApp/res/values-v11/styles.xml
new file mode 100644
index 0000000..ff65301
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/values-v11/styles.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/tests/JobSchedulerTestApp/res/values-v14/styles.xml b/tests/JobSchedulerTestApp/res/values-v14/styles.xml
new file mode 100644
index 0000000..a4a443a
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/values-v14/styles.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/tests/JobSchedulerTestApp/res/values/color.xml b/tests/JobSchedulerTestApp/res/values/color.xml
new file mode 100644
index 0000000..7bd3a91
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/values/color.xml
@@ -0,0 +1,21 @@
+<?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="none_received">#999999</color>
+ <color name="start_received">#00FF00</color>
+ <color name="stop_received">#FF0000</color>
+</resources> \ No newline at end of file
diff --git a/tests/JobSchedulerTestApp/res/values/strings.xml b/tests/JobSchedulerTestApp/res/values/strings.xml
new file mode 100644
index 0000000..824d4b1
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<resources>
+ <string name="onstoptask">onStopTask</string>
+ <string name="onstarttask">onStartTask</string>
+ <string name="defaultparamtext">task params will show up here.</string>
+ <string name="schedule_job_button_text">Schedule Job</string>
+ <string name="app_name">Job Scheduler Test</string>
+ <string name="finish_job_button_text">taskFinished</string>
+ <string name="manual_sync_text">Manual Sync</string>
+ <string name="constraints">Constraints</string>
+ <string name="connectivity">Connectivity:</string>
+ <string name="any">Any</string>
+ <string name="unmetered">WiFi</string>
+ <string name="timing">Timing:</string>
+ <string name="delay">Delay:</string>
+ <string name="deadline">Deadline:</string>
+</resources>
diff --git a/tests/JobSchedulerTestApp/res/values/styles.xml b/tests/JobSchedulerTestApp/res/values/styles.xml
new file mode 100644
index 0000000..43a8f2b
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/values/styles.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
new file mode 100644
index 0000000..15050ef
--- /dev/null
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+package com.android.demo.jobSchedulerApp;
+
+import android.app.Activity;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.RadioButton;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.demo.jobSchedulerApp.service.TestJobService;
+
+public class MainActivity extends Activity {
+
+ private static final String TAG = "MainActivity";
+
+ public static final int MSG_UNCOLOUR_START = 0;
+ public static final int MSG_UNCOLOUR_STOP = 1;
+ public static final int MSG_SERVICE_OBJ = 2;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ Resources res = getResources();
+ defaultColor = res.getColor(R.color.none_received);
+ startJobColor = res.getColor(R.color.start_received);
+ stopJobColor = res.getColor(R.color.stop_received);
+
+ // Set up UI.
+ mShowStartView = (TextView) findViewById(R.id.onstart_textview);
+ mShowStopView = (TextView) findViewById(R.id.onstop_textview);
+ mParamsTextView = (TextView) findViewById(R.id.task_params);
+ mDelayEditText = (EditText) findViewById(R.id.delay_time);
+ mDeadlineEditText = (EditText) findViewById(R.id.deadline_time);
+ mWiFiConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_unmetered);
+ mAnyConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_any);
+
+ mServiceComponent = new ComponentName(this, TestJobService.class);
+ // Start service and provide it a way to communicate with us.
+ Intent startServiceIntent = new Intent(this, TestJobService.class);
+ startServiceIntent.putExtra("messenger", new Messenger(mHandler));
+ startService(startServiceIntent);
+ }
+ // UI fields.
+ int defaultColor;
+ int startJobColor;
+ int stopJobColor;
+
+ TextView mShowStartView;
+ TextView mShowStopView;
+ TextView mParamsTextView;
+ EditText mDelayEditText;
+ EditText mDeadlineEditText;
+ RadioButton mWiFiConnectivityRadioButton;
+ RadioButton mAnyConnectivityRadioButton;
+ ComponentName mServiceComponent;
+ /** Service object to interact scheduled jobs. */
+ TestJobService mTestService;
+
+ private static int kJobId = 0;
+
+ Handler mHandler = new Handler(/* default looper */) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UNCOLOUR_START:
+ mShowStartView.setBackgroundColor(defaultColor);
+ break;
+ case MSG_UNCOLOUR_STOP:
+ mShowStopView.setBackgroundColor(defaultColor);
+ break;
+ case MSG_SERVICE_OBJ:
+ mTestService = (TestJobService) msg.obj;
+ mTestService.setUiCallback(MainActivity.this);
+ }
+ }
+ };
+
+ private boolean ensureTestService() {
+ if (mTestService == null) {
+ Toast.makeText(MainActivity.this, "Service null, never got callback?",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * UI onclick listener to schedule a job. What this job is is defined in
+ * TestJobService#scheduleJob()
+ */
+ public void scheduleJob(View v) {
+ if (!ensureTestService()) {
+ return;
+ }
+
+ JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent);
+
+ String delay = mDelayEditText.getText().toString();
+ if (delay != null && !TextUtils.isEmpty(delay)) {
+ builder.setMinimumLatency(Long.valueOf(delay));
+ }
+ String deadline = mDeadlineEditText.getText().toString();
+ if (deadline != null && !TextUtils.isEmpty(deadline)) {
+ builder.setOverrideDeadline(Long.valueOf(deadline));
+ }
+ boolean requiresUnmetered = mWiFiConnectivityRadioButton.isSelected();
+ boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isSelected();
+ if (requiresUnmetered) {
+ builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED);
+ } else if (requiresAnyConnectivity) {
+ builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY);
+ }
+
+ mTestService.scheduleJob(builder.build());
+
+ }
+
+ /**
+ * UI onclick listener to call jobFinished() in our service.
+ */
+ public void finishJob(View v) {
+ if (!ensureTestService()) {
+ return;
+ }
+ mTestService.callJobFinished();
+ mParamsTextView.setText("");
+ }
+
+ public void onReceivedStartJob(JobParameters params) {
+ mShowStartView.setBackgroundColor(startJobColor);
+ Message m = Message.obtain(mHandler, MSG_UNCOLOUR_START);
+ mHandler.sendMessageDelayed(m, 1000L); // uncolour in 1 second.
+ mParamsTextView.setText("Executing: " + params.getJobId() + " " + params.getExtras());
+ }
+
+ public void onReceivedStopJob() {
+ mShowStopView.setBackgroundColor(stopJobColor);
+ Message m = Message.obtain(mHandler, MSG_UNCOLOUR_STOP);
+ mHandler.sendMessageDelayed(m, 2000L); // uncolour in 1 second.
+ mParamsTextView.setText("");
+ }
+}
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
new file mode 100644
index 0000000..bf8e887
--- /dev/null
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * 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.android.demo.jobSchedulerApp.service;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.demo.jobSchedulerApp.MainActivity;
+
+import java.util.LinkedList;
+
+
+/**
+ * Service to handle sync requests.
+ * <p>
+ * This service is invoked in response to Intents with action android.content.SyncAdapter, and
+ * returns a Binder connection to SyncAdapter.
+ * <p>
+ * For performance, only one sync adapter will be initialized within this application's context.
+ * <p>
+ * Note: The SyncService itself is not notified when a new sync occurs. It's role is to manage the
+ * lifecycle of our and provide a handle to said SyncAdapter to the OS on
+ * request.
+ */
+public class TestJobService extends JobService {
+ private static final String TAG = "SyncService";
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i(TAG, "Service created");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.i(TAG, "Service destroyed");
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Messenger callback = intent.getParcelableExtra("messenger");
+ Message m = Message.obtain();
+ m.what = MainActivity.MSG_SERVICE_OBJ;
+ m.obj = this;
+ try {
+ callback.send(m);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error passing service object back to activity.");
+ }
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ jobParamsMap.add(params);
+ if (mActivity != null) {
+ mActivity.onReceivedStartJob(params);
+ }
+ Log.i(TAG, "on start job: " + params.getJobId());
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ jobParamsMap.remove(params);
+ mActivity.onReceivedStopJob();
+ Log.i(TAG, "on stop job: " + params.getJobId());
+ return true;
+ }
+
+ MainActivity mActivity;
+ private final LinkedList<JobParameters> jobParamsMap = new LinkedList<JobParameters>();
+
+ public void setUiCallback(MainActivity activity) {
+ mActivity = activity;
+ }
+
+ /** Send job to the JobScheduler. */
+ public void scheduleJob(JobInfo t) {
+ Log.d(TAG, "Scheduling job");
+ JobScheduler tm =
+ (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ tm.schedule(t);
+ }
+
+ public boolean callJobFinished() {
+ JobParameters params = jobParamsMap.poll();
+ if (params == null) {
+ return false;
+ } else {
+ jobFinished(params, false);
+ return true;
+ }
+ }
+
+}
diff --git a/tests/VoiceEnrollment/Android.mk b/tests/VoiceEnrollment/Android.mk
new file mode 100644
index 0000000..2ab3d02
--- /dev/null
+++ b/tests/VoiceEnrollment/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := VoiceEnrollment
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
diff --git a/tests/VoiceEnrollment/AndroidManifest.xml b/tests/VoiceEnrollment/AndroidManifest.xml
new file mode 100644
index 0000000..6321222
--- /dev/null
+++ b/tests/VoiceEnrollment/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.voiceenrollment">
+
+ <application
+ android:permission="android.permission.MANAGE_VOICE_KEYPHRASES">
+ <activity android:name="TestEnrollmentActivity" android:label="Voice Enrollment Application"
+ android:theme="@android:style/Theme.Material.Light.Voice">
+ <intent-filter>
+ <action android:name="com.android.intent.action.MANAGE_VOICE_KEYPHRASES" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <meta-data android:name="android.voice_enrollment"
+ android:resource="@xml/enrollment_application"/>
+ </application>
+</manifest>
diff --git a/tests/VoiceEnrollment/res/xml/enrollment_application.xml b/tests/VoiceEnrollment/res/xml/enrollment_application.xml
new file mode 100644
index 0000000..710a0ac
--- /dev/null
+++ b/tests/VoiceEnrollment/res/xml/enrollment_application.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.
+ */
+-->
+
+<voice-enrollment-application xmlns:android="http://schemas.android.com/apk/res/android"
+ android:searchKeyphraseId="101"
+ android:searchKeyphrase="Hello There"
+ android:searchKeyphraseSupportedLocales="en-US,en-GB,fr-FR,de-DE" />
diff --git a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
new file mode 100644
index 0000000..7fbd965
--- /dev/null
+++ b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package com.android.test.voiceenrollment;
+
+import android.app.Activity;
+
+public class TestEnrollmentActivity extends Activity {
+ // TODO(sansid): Add a test enrollment flow here.
+}
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index e1a5854..33f000d 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -3,7 +3,7 @@
<application>
<activity android:name="VoiceInteractionMain" android:label="Voice Interaction"
- android:theme="@android:style/Theme.Quantum">
+ android:theme="@android:style/Theme.Material">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -24,7 +24,7 @@
android:process=":session">
</service>
<activity android:name="TestInteractionActivity" android:label="Voice Interaction Target"
- android:theme="@android:style/Theme.Quantum.Light.Voice">
+ android:theme="@android:style/Theme.Material.Light.Voice">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index d40b05f..00c2c64 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -21,6 +21,8 @@ import android.os.Bundle;
import android.service.voice.VoiceInteractionService;
import android.util.Log;
+import java.util.Arrays;
+
public class MainInteractionService extends VoiceInteractionService {
static final String TAG = "MainInteractionService";
@@ -28,6 +30,9 @@ public class MainInteractionService extends VoiceInteractionService {
public void onCreate() {
super.onCreate();
Log.i(TAG, "Creating " + this);
+ Log.i(TAG, "Keyphrase enrollment error? " + getKeyphraseEnrollmentInfo().getParseError());
+ Log.i(TAG, "Keyphrase enrollment meta-data: "
+ + Arrays.toString(getKeyphraseEnrollmentInfo().getKeyphrases()));
}
@Override