aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiem Song <tiem@google.com>2017-11-13 10:26:47 -0800
committerTiem Song <tiem@google.com>2017-11-16 21:05:12 -0800
commitd195545551ea7eed794e75c230bd739d1a486e55 (patch)
tree54013970b6fcc91e4f05128680930b47efe9e538
parentc150776af9983dc846b326cfa6998168f7054e3d (diff)
downloadandroid-d195545551ea7eed794e75c230bd739d1a486e55.tar.gz
Create Kotlin version of JobScheduler sample
Bug: 64766094 Test: Manual - verified no regression versus Java version. Change-Id: I2b23750032f1133e4010547e1dd9eb562d245af4
-rw-r--r--background/JobScheduler/kotlinApp/CONTRIB.md35
-rw-r--r--background/JobScheduler/kotlinApp/README.md60
-rw-r--r--background/JobScheduler/kotlinApp/app/build.gradle27
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/AndroidManifest.xml45
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/ActivityExtensions.kt27
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/Constants.kt28
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/IncomingMessageHandler.kt89
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MainActivity.kt162
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MyJobService.kt95
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/ic_launcher.pngbin0 -> 4623 bytes
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/drawable-mdpi/ic_launcher.pngbin0 -> 2782 bytes
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/drawable-xhdpi/ic_launcher.pngbin0 -> 6701 bytes
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 11995 bytes
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/layout/sample_main.xml244
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml25
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml26
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values-v11/styles.xml28
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values-v11/template-styles.xml23
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values-v14/styles.xml29
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml24
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values/base-strings.xml30
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values/color.xml22
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values/dimens.xml31
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values/strings.xml43
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values/styles.xml32
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values/template-dimens.xml33
-rw-r--r--background/JobScheduler/kotlinApp/app/src/main/res/values/template-styles.xml43
-rw-r--r--background/JobScheduler/kotlinApp/build.gradle22
-rw-r--r--background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.jarbin0 -> 49896 bytes
-rw-r--r--background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xbackground/JobScheduler/kotlinApp/gradlew164
-rw-r--r--background/JobScheduler/kotlinApp/gradlew.bat90
-rw-r--r--background/JobScheduler/kotlinApp/packaging.yaml15
-rw-r--r--background/JobScheduler/kotlinApp/settings.gradle1
35 files changed, 1499 insertions, 0 deletions
diff --git a/background/JobScheduler/kotlinApp/CONTRIB.md b/background/JobScheduler/kotlinApp/CONTRIB.md
new file mode 100644
index 00000000..14a4fcff
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/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/background/JobScheduler/kotlinApp/README.md b/background/JobScheduler/kotlinApp/README.md
new file mode 100644
index 00000000..319cf2d4
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/README.md
@@ -0,0 +1,60 @@
+
+Android JobScheduler Sample (Kotlin)
+====================================
+
+Demonstration of the JobScheduler API, which provides an interface for scheduling
+background tasks when certain tasks apply.
+
+To understand how this sample works, try these different scenarios:
+
+- Unplug device, schedule a task that requires the device to be plugged in. Job will start when the
+device is plugged in.
+- Set a delay of 10 seconds and press back. The activity and service are finished but the service is
+launched again in 10 seconds (logcat will show debug messages).
+- Set a delay of 5 seconds and a work duration of 10 seconds. Schedule job and press the
+back button. Open the activity again after 6 seconds. The activity will show the onStopTask even
+though both activity and service were shut down.
+
+Pre-requisites
+--------------
+
+- Android SDK 27
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-JobScheduler
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2017 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/background/JobScheduler/kotlinApp/app/build.gradle b/background/JobScheduler/kotlinApp/app/build.gradle
new file mode 100644
index 00000000..f3bd616c
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/build.gradle
@@ -0,0 +1,27 @@
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+android {
+ compileSdkVersion 27
+ defaultConfig {
+ applicationId "com.example.android.jobscheduler"
+ minSdkVersion 21
+ targetSdkVersion 27
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation "com.android.support:appcompat-v7:27.0.0"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+} \ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/AndroidManifest.xml b/background/JobScheduler/kotlinApp/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..5230d846
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 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.jobscheduler">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+ <application
+ android:allowBackup="false"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name=".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=".MyJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="true"/>
+ </application>
+
+</manifest>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/ActivityExtensions.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/ActivityExtensions.kt
new file mode 100644
index 00000000..39a9d7e1
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/ActivityExtensions.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 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.jobscheduler
+
+import android.app.Activity
+import android.widget.Toast
+
+/**
+ * Helper extension function for showing a [Toast]
+ */
+fun Activity.showToast(text: String) {
+ Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
+} \ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/Constants.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/Constants.kt
new file mode 100644
index 00000000..90fc00f8
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/Constants.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017 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.
+ */
+
+@file:JvmName("Constants")
+@file:Suppress("PropertyName")
+
+package com.example.android.jobscheduler
+
+@JvmField val MSG_UNCOLOR_START = 0
+@JvmField val MSG_UNCOLOR_STOP = 1
+@JvmField val MSG_COLOR_START = 2
+@JvmField val MSG_COLOR_STOP = 3
+
+@JvmField val MESSENGER_INTENT_KEY = "${BuildConfig.APPLICATION_ID}.MESSENGER_INTENT_KEY"
+@JvmField val WORK_DURATION_KEY = "${BuildConfig.APPLICATION_ID}.WORK_DURATION_KEY"
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/IncomingMessageHandler.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/IncomingMessageHandler.kt
new file mode 100644
index 00000000..9d5b1148
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/IncomingMessageHandler.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2017 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.jobscheduler
+
+import android.os.Handler
+import android.os.Message
+import android.os.Messenger
+import android.support.v4.content.ContextCompat.getColor
+import android.view.View
+import android.widget.TextView
+import java.lang.ref.WeakReference
+import java.util.concurrent.TimeUnit
+
+/**
+ * A [Handler] allows you to send messages associated with a thread. A [Messenger]
+ * uses this handler to communicate from [MyJobService]. It's also used to make
+ * the start and stop views blink for a short period of time.
+ */
+internal class IncomingMessageHandler(activity: MainActivity) : Handler() {
+
+ // Prevent possible leaks with a weak reference.
+ private val mainActivity: WeakReference<MainActivity> = WeakReference(activity)
+
+ override fun handleMessage(msg: Message) {
+ val mainActivity = mainActivity.get() ?: return
+ val showStartView = mainActivity.findViewById<View>(R.id.onstart_textview)
+ val showStopView = mainActivity.findViewById<View>(R.id.onstop_textview)
+ when (msg.what) {
+ /*
+ * Receives callback from the service when a job has landed
+ * on the app. Turns on indicator and sends a message to turn it off after
+ * a second.
+ */
+ MSG_COLOR_START -> {
+ // Start received, turn on the indicator and show text.
+ showStartView.setBackgroundColor(getColor(mainActivity, R.color.start_received))
+ updateParamsTextView(msg.obj, "started")
+ sendMessageDelayed(Message.obtain(this, MSG_UNCOLOR_START),
+ TimeUnit.SECONDS.toMillis(1))
+ }
+ /*
+ * Receives callback from the service when a job that previously landed on the
+ * app must stop executing. Turns on indicator and sends a message to turn it
+ * off after two seconds.
+ */
+ MSG_COLOR_STOP -> {
+ // Stop received, turn on the indicator and show text.
+ showStopView.setBackgroundColor(getColor(mainActivity, R.color.stop_received))
+ updateParamsTextView(msg.obj, "stopped")
+ sendMessageDelayed(obtainMessage(MSG_UNCOLOR_STOP), TimeUnit.SECONDS.toMillis(1))
+ }
+ MSG_UNCOLOR_START -> {
+ uncolorButtonAndClearText(showStartView, mainActivity)
+ }
+ MSG_UNCOLOR_STOP -> {
+ uncolorButtonAndClearText(showStopView, mainActivity)
+ }
+ }
+ }
+
+ private fun uncolorButtonAndClearText(textView: View, activity: MainActivity) {
+ textView.setBackgroundColor(getColor(activity, R.color.none_received))
+ updateParamsTextView()
+ }
+
+ private fun updateParamsTextView(jobId: Any? = null, action: String = "") {
+ val mainActivity = mainActivity.get() ?: return
+ val paramsTextView = mainActivity.findViewById<TextView>(R.id.task_params)
+ if (jobId == null) {
+ paramsTextView.text = ""
+ return
+ }
+ paramsTextView.text = mainActivity.getString(R.string.job_status, jobId.toString(), action)
+ }
+}
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MainActivity.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MainActivity.kt
new file mode 100644
index 00000000..b28d5c47
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MainActivity.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2017 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.jobscheduler
+
+import android.app.Activity
+import android.app.job.JobInfo
+import android.app.job.JobScheduler
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.Messenger
+import android.os.PersistableBundle
+import android.util.Log
+import android.widget.Button
+import android.widget.CheckBox
+import android.widget.EditText
+import android.widget.RadioButton
+import java.util.concurrent.TimeUnit
+
+/**
+ * Schedules and configures jobs to be executed by a [JobScheduler].
+ *
+ * [MyJobService] can send messages to this via a [Messenger]
+ * that is sent in the Intent that starts the Service.
+ */
+class MainActivity : Activity() {
+
+ lateinit private var anyConnectivityRadioButton: RadioButton
+ lateinit private var deadlineEditText: EditText
+ lateinit private var delayEditText: EditText
+ lateinit private var durationTimeEditText: EditText
+ lateinit private var requiresChargingCheckBox: CheckBox
+ lateinit private var requiresIdleCheckbox: CheckBox
+ lateinit private var wiFiConnectivityRadioButton: RadioButton
+
+ // Handler for incoming messages from the service.
+ lateinit private var handler: IncomingMessageHandler
+ lateinit private var serviceComponent: ComponentName
+ private var jobId = 0
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.sample_main)
+
+ anyConnectivityRadioButton = findViewById(R.id.checkbox_any)
+ deadlineEditText = findViewById(R.id.deadline_time)
+ delayEditText = findViewById(R.id.delay_time)
+ durationTimeEditText = findViewById(R.id.duration_time)
+ requiresChargingCheckBox = findViewById(R.id.checkbox_charging)
+ requiresIdleCheckbox = findViewById(R.id.checkbox_idle)
+ wiFiConnectivityRadioButton = findViewById(R.id.checkbox_unmetered)
+
+ handler = IncomingMessageHandler(this)
+ serviceComponent = ComponentName(this, MyJobService::class.java)
+
+ findViewById<Button>(R.id.cancel_button).setOnClickListener { cancelAllJobs() }
+ findViewById<Button>(R.id.finished_button).setOnClickListener { finishJob() }
+ findViewById<Button>(R.id.schedule_button).setOnClickListener { scheduleJob() }
+ }
+
+ override fun onStop() {
+ // A service can be "started" and/or "bound". In this case, it's "started" by this Activity
+ // and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
+ // to stopService() won't prevent scheduled jobs to be processed. However, failing
+ // to call stopService() would keep it alive indefinitely.
+ stopService(Intent(this, MyJobService::class.java))
+ super.onStop()
+ }
+
+ override fun onStart() {
+ super.onStart()
+ // Start service and provide it a way to communicate with this class.
+ val startServiceIntent = Intent(this, MyJobService::class.java)
+ val messengerIncoming = Messenger(handler)
+ startServiceIntent.putExtra(MESSENGER_INTENT_KEY, messengerIncoming)
+ startService(startServiceIntent)
+ }
+
+ /**
+ * Executed when user clicks on SCHEDULE JOB.
+ */
+ private fun scheduleJob() {
+ val builder = JobInfo.Builder(jobId++, serviceComponent)
+
+ val delay = delayEditText.text.toString()
+ if (delay.isNotEmpty()) {
+ builder.setMinimumLatency(delay.toLong() * TimeUnit.SECONDS.toMillis(1))
+ }
+
+ val deadline = deadlineEditText.text.toString()
+ if (deadline.isNotEmpty()) {
+ builder.setOverrideDeadline(deadline.toLong() * TimeUnit.SECONDS.toMillis(1))
+ }
+
+ if (wiFiConnectivityRadioButton.isChecked) {
+ builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
+ } else if (anyConnectivityRadioButton.isChecked) {
+ builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ }
+
+ // Extras, work duration.
+ val extras = PersistableBundle()
+ var workDuration = durationTimeEditText.text.toString()
+ if (workDuration.isEmpty()) workDuration = "1"
+ extras.putLong(WORK_DURATION_KEY, workDuration.toLong() * TimeUnit.SECONDS.toMillis(1))
+
+ // Finish configuring the builder
+ builder.run {
+ setRequiresDeviceIdle(requiresIdleCheckbox.isChecked)
+ setRequiresCharging(requiresChargingCheckBox.isChecked)
+ setExtras(extras)
+ }
+
+ // Schedule job
+ Log.d(TAG, "Scheduling job")
+ (getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler).schedule(builder.build())
+ }
+
+ /**
+ * Executed when user clicks on CANCEL ALL.
+ */
+ private fun cancelAllJobs() {
+ (getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler).cancelAll()
+ showToast(getString(R.string.all_jobs_cancelled))
+ }
+
+ /**
+ * Executed when user clicks on FINISH LAST TASK.
+ */
+ private fun finishJob() {
+ val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
+ val allPendingJobs = jobScheduler.allPendingJobs
+ if (allPendingJobs.size > 0) {
+ // Finish the last one.
+ // Example: If jobs a, b, and c are queued in that order, this method will cancel job c.
+ val id = allPendingJobs.first().id
+ jobScheduler.cancel(id)
+ showToast(getString(R.string.cancelled_job, id))
+ } else {
+ showToast(getString(R.string.no_jobs_to_cancel))
+ }
+ }
+
+ companion object {
+ private val TAG = "MainActivity"
+ }
+}
diff --git a/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MyJobService.kt b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MyJobService.kt
new file mode 100644
index 00000000..3c6cc54a
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/java/com/example/android/jobscheduler/MyJobService.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017 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.jobscheduler
+
+import android.app.Service
+import android.app.job.JobParameters
+import android.app.job.JobService
+import android.content.Intent
+import android.os.Handler
+import android.os.Message
+import android.os.Messenger
+import android.os.RemoteException
+import android.util.Log
+
+/**
+ * Service to handle callbacks from the JobScheduler. Requests scheduled with the JobScheduler
+ * ultimately land on this service's "onStartJob" method. It runs jobs for a specific amount of time
+ * and finishes them. It keeps the activity updated with changes via a Messenger.
+ */
+class MyJobService : JobService() {
+
+ private var activityMessenger: Messenger? = null
+
+ /**
+ * When the app's MainActivity is created, it starts this service. This is so that the
+ * activity and this service can communicate back and forth. See "setUiCallback()"
+ */
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ activityMessenger = intent.getParcelableExtra(MESSENGER_INTENT_KEY)
+ return Service.START_NOT_STICKY
+ }
+
+ override fun onStartJob(params: JobParameters): Boolean {
+ // The work that this service "does" is simply wait for a certain duration and finish
+ // the job (on another thread).
+ sendMessage(MSG_COLOR_START, params.jobId)
+
+ // Uses a Handler to delay the execution of jobFinished().
+ val duration = params.extras.getLong(WORK_DURATION_KEY)
+ Handler().postDelayed({
+ sendMessage(MSG_COLOR_STOP, params.jobId)
+ jobFinished(params, false)
+ }, duration)
+ Log.i(TAG, "on start job: ${params.jobId}")
+
+ // Return true as there's more work to be done with this job.
+ return true
+ }
+
+ override fun onStopJob(params: JobParameters): Boolean {
+ // Stop tracking these job parameters, as we've 'finished' executing.
+ sendMessage(MSG_COLOR_STOP, params.jobId)
+ Log.i(TAG, "on stop job: ${params.jobId}")
+
+ // Return false to drop the job.
+ return false
+ }
+
+ private fun sendMessage(messageID: Int, params: Any?) {
+ // If this service is launched by the JobScheduler, there's no callback Messenger. It
+ // only exists when the MainActivity calls startService() with the callback in the Intent.
+ if (activityMessenger == null) {
+ Log.d(TAG, "Service is bound, not started. There's no callback to send a message to.")
+ return
+ }
+ val message = Message.obtain()
+ message.run {
+ what = messageID
+ obj = params
+ }
+ try {
+ activityMessenger?.send(message)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Error passing service object back to activity.")
+ }
+ }
+
+ companion object {
+ private val TAG = "MyJobService"
+ }
+}
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/ic_launcher.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 00000000..9cb5f741
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.png
new file mode 100644
index 00000000..13586288
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-mdpi/ic_launcher.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 00000000..869355b5
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xhdpi/ic_launcher.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..679fc16f
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..1734fd35
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/layout/sample_main.xml b/background/JobScheduler/kotlinApp/app/src/main/res/layout/sample_main.xml
new file mode 100644
index 00000000..84a21943
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/layout/sample_main.xml
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 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.
+-->
+
+<ScrollView 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:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/layout_height">
+
+ <TextView
+ android:id="@+id/onstart_textview"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/textview_margin"
+ 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_margin="@dimen/textview_margin"
+ android:layout_weight="1"
+ android:background="@color/none_received"
+ android:gravity="center"
+ android:text="@string/onstoptask" />
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/task_params"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginBottom="@dimen/textview_bottom_margin"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:padding="@dimen/textview_margin"
+ android:textSize="@dimen/large_text_size" />
+
+ <Button
+ android:id="@+id/finished_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/button_padding"
+ android:layout_marginBottom="@dimen/button_bottom_margin"
+ android:layout_marginLeft="@dimen/button_horizontal_margins"
+ android:layout_marginRight="@dimen/button_horizontal_margins"
+ android:text="@string/finish_job_button_text" />
+
+ <TableLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/table_margin">
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/textview_margin"
+ android:labelFor="@id/duration_time"
+ android:gravity="end|center_vertical"
+ android:text="@string/work_duration"
+ android:textSize="@dimen/default_text_size" />
+
+ <EditText
+ android:id="@+id/duration_time"
+ android:layout_width="@dimen/edittext_width"
+ android:layout_height="wrap_content"
+ android:inputType="number"
+ android:text="@string/default_duration_time" />
+
+ </TableRow>
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/textview_margin"
+ android:gravity="end|center_vertical"
+ android:text="@string/connectivity"
+ android:textSize="@dimen/default_text_size" />
+
+ <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:checked="true"
+ 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>
+
+ </TableRow>
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/textview_margin"
+ android:gravity="end|center_vertical"
+ android:text="@string/delay"
+ android:textSize="@dimen/default_text_size" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:labelFor="@id/delay_time"
+ android:text="@string/timing" />
+
+ <EditText
+ android:id="@+id/delay_time"
+ android:layout_width="@dimen/edittext_width"
+ android:layout_height="wrap_content"
+ android:inputType="number"
+ android:text="@string/default_delay_time" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:labelFor="@id/deadline_time"
+ android:text="@string/deadline"
+ android:textSize="@dimen/default_text_size" />
+
+ <EditText
+ android:id="@+id/deadline_time"
+ android:layout_width="@dimen/edittext_width"
+ android:layout_height="wrap_content"
+ android:inputType="number"
+ android:text="@string/default_deadline_time" />
+
+ </LinearLayout>
+
+ </TableRow>
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/tablerow_margin_end"
+ android:gravity="end|center_vertical"
+ android:text="@string/charging_caption"
+ android:textSize="@dimen/default_text_size" />
+
+ <CheckBox
+ android:id="@+id/checkbox_charging"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/charging_text" />
+
+ </TableRow>
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/tablerow_margin_end"
+ android:gravity="end|center_vertical"
+ android:text="@string/idle_caption" />
+
+ <CheckBox
+ android:id="@+id/checkbox_idle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/idle_mode_text" />
+
+ </TableRow>
+
+ </TableLayout>
+
+ <Button
+ android:id="@+id/schedule_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/button_top_margin"
+ android:layout_marginLeft="@dimen/button_horizontal_margins"
+ android:layout_marginRight="@dimen/button_horizontal_margins"
+ android:text="@string/schedule_job_button_text" />
+ <Button
+ android:id="@+id/cancel_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/button_horizontal_margins"
+ android:layout_marginRight="@dimen/button_horizontal_margins"
+ android:text="@string/cancel_all_jobs_button_text" />
+
+ </LinearLayout>
+
+</ScrollView>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 00000000..21447966
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 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>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml
new file mode 100644
index 00000000..3dd911c7
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 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>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/styles.xml
new file mode 100644
index 00000000..19035468
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/styles.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 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/sample-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/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/template-styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/template-styles.xml
new file mode 100644
index 00000000..000ff51c
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-v11/template-styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values-v14/styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-v14/styles.xml
new file mode 100644
index 00000000..9c21dbed
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-v14/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 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/sample-styles.xml and
+ res/values-v11/sample-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/background/JobScheduler/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml
new file mode 100644
index 00000000..28215b70
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values-v21/base-template-styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light">
+ </style>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/base-strings.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/base-strings.xml
new file mode 100644
index 00000000..034a3bfe
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/base-strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 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">JobScheduler</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ Demonstration of the JobScheduler API, which provides an interface for scheduling
+ background tasks when certain tasks apply.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/color.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/color.xml
new file mode 100644
index 00000000..5431f76a
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 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/background/JobScheduler/kotlinApp/app/src/main/res/values/dimens.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..859937fe
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/dimens.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 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="default_text_size">14sp</dimen>
+ <dimen name="large_text_size">20sp</dimen>
+ <dimen name="button_horizontal_margins">40dp</dimen>
+ <dimen name="button_top_margin">20dp</dimen>
+ <dimen name="tablerow_margin_end">12dp</dimen>
+ <dimen name="edittext_width">48dp</dimen>
+ <dimen name="textview_margin">12dp</dimen>
+ <dimen name="textview_bottom_margin">10dp</dimen>
+ <dimen name="button_padding">20dp</dimen>
+ <dimen name="button_bottom_margin">5dp</dimen>
+ <dimen name="layout_height">100dp</dimen>
+ <dimen name="table_margin">8dp</dimen>
+</resources> \ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/strings.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..f0e26b74
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/strings.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 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="cancel_all_jobs_button_text">Cancel all</string>
+ <string name="finish_job_button_text">Finish last task</string>
+ <string name="idle_mode_text">Requires device in idle mode.</string>
+ <string name="charging_caption">Charging:</string>
+ <string name="charging_text">Requires device plugged in.</string>
+ <string name="idle_caption">Idle:</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>
+ <string name="work_duration">Work duration:</string>
+ <string name="cancelled_job">Cancelled job %d</string>
+ <string name="no_jobs_to_cancel">No jobs to cancel</string>
+ <string name="all_jobs_cancelled">All jobs cancelled</string>
+ <string name="job_status">Job ID %s %s</string>
+ <string name="default_duration_time">2</string>
+ <string name="default_delay_time">0</string>
+ <string name="default_deadline_time">15</string>
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..c174da46
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/styles.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2017 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>
+
+</resources> \ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/template-dimens.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/template-dimens.xml
new file mode 100644
index 00000000..30a0d8d5
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/template-dimens.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 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>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/app/src/main/res/values/template-styles.xml b/background/JobScheduler/kotlinApp/app/src/main/res/values/template-styles.xml
new file mode 100644
index 00000000..357da342
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/app/src/main/res/values/template-styles.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2017 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>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/background/JobScheduler/kotlinApp/build.gradle b/background/JobScheduler/kotlinApp/build.gradle
new file mode 100644
index 00000000..5dc45d16
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/build.gradle
@@ -0,0 +1,22 @@
+buildscript {
+ ext.kotlin_version = '1.1.60'
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.0.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+} \ No newline at end of file
diff --git a/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..8c0fb64a
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..32ed0311
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Nov 07 16:05:05 PST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/background/JobScheduler/kotlinApp/gradlew b/background/JobScheduler/kotlinApp/gradlew
new file mode 100755
index 00000000..91a7e269
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/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/background/JobScheduler/kotlinApp/gradlew.bat b/background/JobScheduler/kotlinApp/gradlew.bat
new file mode 100644
index 00000000..8a0b282a
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/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/background/JobScheduler/kotlinApp/packaging.yaml b/background/JobScheduler/kotlinApp/packaging.yaml
new file mode 100644
index 00000000..edef14fe
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [Background]
+languages: [Kotlin]
+solutions: [Mobile]
+github: googlesamples/android-JobScheduler
+level: BEGINNER
+icon: JobSchedulerSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/background/JobScheduler/kotlinApp/settings.gradle b/background/JobScheduler/kotlinApp/settings.gradle
new file mode 100644
index 00000000..4c90568a
--- /dev/null
+++ b/background/JobScheduler/kotlinApp/settings.gradle
@@ -0,0 +1 @@
+include 'app'