Merge "Add test app for JobScheduler" into lmp-preview-dev

This commit is contained in:
Matthew Williams
2014-06-09 20:23:10 +00:00
committed by Android (Google) Code Review
17 changed files with 618 additions and 5 deletions

View File

@@ -374,7 +374,7 @@ public class TaskManagerService extends com.android.server.SystemService
public void onTaskCompleted(TaskStatus taskStatus, boolean needsReschedule) {
if (!stopTrackingTask(taskStatus)) {
if (DEBUG) {
Slog.e(TAG, "Error removing task: could not find task to remove. Was task" +
Slog.e(TAG, "Error removing task: could not find task to remove. Was task " +
"removed while executing?");
}
return;

View File

@@ -466,16 +466,14 @@ public class TaskServiceContext extends ITaskCallback.Stub implements ServiceCon
removeMessages(MSG_TIMEOUT);
mWakeLock.release();
mContext.unbindService(TaskServiceContext.this);
mWakeLock = null;
mCompletedListener.onTaskCompleted(mRunningTask, reschedule);
mWakeLock = null;
mRunningTask = null;
mParams = null;
mVerb = -1;
mCancelled.set(false);
service = null;
mCompletedListener.onTaskCompleted(mRunningTask, reschedule);
synchronized (mAvailableLock) {
mAvailable = true;
}

View File

@@ -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)

View File

@@ -0,0 +1,31 @@
<?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:exported="true"/>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 856 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.task.Task;
import android.app.task.TaskParams;
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 tasks. */
TestJobService mTestService;
private static int kTaskId = 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 task. What this task is is defined in
* TestJobService#scheduleJob()
*/
public void scheduleJob(View v) {
if (!ensureTestService()) {
return;
}
Task.Builder builder = new Task.Builder(kTaskId++, 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(Task.NetworkType.UNMETERED);
} else if (requiresAnyConnectivity) {
builder.setRequiredNetworkCapabilities(Task.NetworkType.ANY);
}
mTestService.scheduleJob(builder.build());
}
/**
* UI onclick listener to call taskFinished() in our service.
*/
public void finishJob(View v) {
if (!ensureTestService()) {
return;
}
mTestService.callTaskFinished();
mParamsTextView.setText("");
}
public void onReceivedStartTask(TaskParams params) {
mShowStartView.setBackgroundColor(startJobColor);
Message m = Message.obtain(mHandler, MSG_UNCOLOUR_START);
mHandler.sendMessageDelayed(m, 1000L); // uncolour in 1 second.
mParamsTextView.setText("Executing: " + params.getTaskId() + " " + params.getExtras());
}
public void onReceivedStopTask() {
mShowStopView.setBackgroundColor(stopJobColor);
Message m = Message.obtain(mHandler, MSG_UNCOLOUR_STOP);
mHandler.sendMessageDelayed(m, 2000L); // uncolour in 1 second.
mParamsTextView.setText("");
}
}

View File

@@ -0,0 +1,127 @@
/*
* 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.Service;
import android.app.task.Task;
import android.app.task.TaskManager;
import android.app.task.TaskParams;
import android.app.task.TaskService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.util.Log;
import com.android.demo.jobSchedulerApp.MainActivity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
* 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 TaskService {
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 onStartTask(TaskParams params) {
taskParamsMap.add(params);
if (mActivity != null) {
mActivity.onReceivedStartTask(params);
}
Log.i(TAG, "on start task: " + params.getTaskId());
return true;
}
@Override
public boolean onStopTask(TaskParams params) {
taskParamsMap.remove(params);
mActivity.onReceivedStopTask();
Log.i(TAG, "on stop task: " + params.getTaskId());
return true;
}
MainActivity mActivity;
private final LinkedList<TaskParams> taskParamsMap = new LinkedList<TaskParams>();
public void setUiCallback(MainActivity activity) {
mActivity = activity;
}
/** Send job to the JobScheduler. */
public void scheduleJob(Task t) {
Log.d(TAG, "Scheduling job");
TaskManager tm =
(TaskManager) getSystemService(Context.TASK_SERVICE);
tm.schedule(t);
}
public boolean callTaskFinished() {
TaskParams params = taskParamsMap.poll();
if (params == null) {
return false;
} else {
taskFinished(params, false);
return true;
}
}
}