From efe4f716c8670f5c3ce5dd9eb252b80d9d4241db Mon Sep 17 00:00:00 2001 From: Caren Date: Mon, 11 Oct 2021 15:12:43 -0700 Subject: [PATCH] Update WorkManager sample to 2.7-rc (#1025) * WorkManager library updated to 2.7.0-alpha01 * Upgrade workmanager to 2.7-beta01 (#1017) * Upgrade workmanager to 2.7-beta01 * Remove extra equal sign * Fix rebase errors * Update SaveImageToGalleryWorker to be CoroutineWorker * Add NotificationUtils class * Update WorkManager version to 2.7.0-rc01 * Move notification ID to companion object and use 31 as compile_sdk version * Remove wildcard imports and implement more descriptive variable names in NotificationUtils * Make notificationImportance an argument with default value when creating notification channel Co-authored-by: Murat Yener --- WorkManagerSample/app/build.gradle | 2 +- .../app/src/main/AndroidManifest.xml | 13 +++- WorkManagerSample/lib/build.gradle | 2 +- .../com/example/background/ImageOperations.kt | 2 + .../background/workers/NotificationUtils.kt | 73 ++++++++++++++++++ .../workers/SaveImageToGalleryWorker.kt | 19 ++++- .../workers/filters/BaseFilterWorker.kt | 75 +++---------------- .../lib/src/main/res/values/strings.xml | 3 +- WorkManagerSample/versions.gradle | 6 +- 9 files changed, 116 insertions(+), 79 deletions(-) create mode 100644 WorkManagerSample/lib/src/main/java/com/example/background/workers/NotificationUtils.kt diff --git a/WorkManagerSample/app/build.gradle b/WorkManagerSample/app/build.gradle index 1152d22..c1ad6ab 100644 --- a/WorkManagerSample/app/build.gradle +++ b/WorkManagerSample/app/build.gradle @@ -26,7 +26,7 @@ android { useSupportLibrary true } // Switching to Renderscript support provided by framework. - minSdkVersion 18 + minSdkVersion build_versions.min_sdk targetSdkVersion build_versions.target_sdk versionCode 1 versionName "1.0" diff --git a/WorkManagerSample/app/src/main/AndroidManifest.xml b/WorkManagerSample/app/src/main/AndroidManifest.xml index 15ac76a..3296584 100644 --- a/WorkManagerSample/app/src/main/AndroidManifest.xml +++ b/WorkManagerSample/app/src/main/AndroidManifest.xml @@ -34,13 +34,18 @@ android:requestLegacyExternalStorage="true"> + tools:targetApi="n" + tools:node="merge"> + + diff --git a/WorkManagerSample/lib/build.gradle b/WorkManagerSample/lib/build.gradle index 9cfdcf9..25f9b78 100644 --- a/WorkManagerSample/lib/build.gradle +++ b/WorkManagerSample/lib/build.gradle @@ -26,7 +26,7 @@ android { useSupportLibrary true } // Switching to Renderscript support provided by framework. - minSdkVersion 18 + minSdkVersion build_versions.min_sdk targetSdkVersion build_versions.target_sdk versionCode 1 versionName "1.0" diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/ImageOperations.kt b/WorkManagerSample/lib/src/main/java/com/example/background/ImageOperations.kt index 4e3fc48..e500346 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/ImageOperations.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/ImageOperations.kt @@ -24,6 +24,7 @@ import androidx.work.ExistingWorkPolicy import androidx.work.ListenableWorker import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.OutOfQuotaPolicy import androidx.work.WorkContinuation import androidx.work.WorkManager import androidx.work.workDataOf @@ -90,6 +91,7 @@ class ImageOperations( ) = OneTimeWorkRequestBuilder().apply { setInputData(inputData) + setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) if (!tag.isNullOrEmpty()) { addTag(tag) } diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/NotificationUtils.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/NotificationUtils.kt new file mode 100644 index 0000000..41eed8d --- /dev/null +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/NotificationUtils.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 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("NotificationUtils") + +package com.example.background.workers + +import android.annotation.TargetApi +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import android.os.Build +import androidx.core.app.NotificationCompat +import androidx.work.WorkManager +import com.example.background.library.R +import java.util.UUID + +/** + * Create the notification and required channel (O+) for running work in a foreground service. + */ +fun createNotification(context: Context, workRequestId: UUID, notificationTitle: String): Notification { + val channelId = context.getString(R.string.notification_channel_id) + val cancelText = context.getString(R.string.cancel_processing) + val name = context.getString(R.string.channel_name) + // This PendingIntent can be used to cancel the Worker. + val cancelIntent = WorkManager.getInstance(context).createCancelPendingIntent(workRequestId) + + val builder = NotificationCompat.Builder(context, channelId) + .setContentTitle(notificationTitle) + .setTicker(notificationTitle) + .setSmallIcon(R.drawable.baseline_gradient) + .setOngoing(true) + .addAction(android.R.drawable.ic_delete, cancelText, cancelIntent) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createNotificationChannel(context, channelId, name).also { + builder.setChannelId(it.id) + } + } + return builder.build() +} + +/** + * Create the required notification channel for O+ devices. + */ +@TargetApi(Build.VERSION_CODES.O) +fun createNotificationChannel( + context: Context, + channelId: String, + name: String, + notificationImportance: Int = NotificationManager.IMPORTANCE_HIGH +): NotificationChannel { + val notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + return NotificationChannel( + channelId, name, notificationImportance + ).also { channel -> + notificationManager.createNotificationChannel(channel) + } +} diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/SaveImageToGalleryWorker.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/SaveImageToGalleryWorker.kt index 8917042..681755d 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/workers/SaveImageToGalleryWorker.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/SaveImageToGalleryWorker.kt @@ -23,10 +23,12 @@ import android.net.Uri import android.provider.MediaStore import android.provider.MediaStore.Images.Media import android.util.Log +import androidx.work.CoroutineWorker import androidx.work.Data -import androidx.work.Worker +import androidx.work.ForegroundInfo import androidx.work.WorkerParameters import com.example.background.Constants +import com.example.background.library.R import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -35,9 +37,10 @@ import java.util.Locale * Saves an output image to the [MediaStore]. */ class SaveImageToGalleryWorker(appContext: Context, workerParams: WorkerParameters) : - Worker(appContext, workerParams) { + CoroutineWorker(appContext, workerParams) { + + override suspend fun doWork(): Result { - override fun doWork(): Result { val resolver = applicationContext.contentResolver return try { val input = Uri.parse(inputData.getString(Constants.KEY_IMAGE_URI)) @@ -62,9 +65,19 @@ class SaveImageToGalleryWorker(appContext: Context, workerParams: WorkerParamete return Media.insertImage( resolver, bitmap, DATE_FORMATTER.format(Date()), TITLE ) + + } + + override suspend fun getForegroundInfo(): ForegroundInfo { + return ForegroundInfo( + NOTIFICATION_ID, createNotification(applicationContext, id, + applicationContext.getString(R.string.notification_title_saving_image))) } companion object { + // Use same notification id as BaseFilter worker to update existing notification. For a real + // world app you might consider using a different id for each notification. + private const val NOTIFICATION_ID = 1 private const val TAG = "SvImageToGalleryWrkr" private const val TITLE = "Filtered Image" private val DATE_FORMATTER = diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BaseFilterWorker.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BaseFilterWorker.kt index 0a77325..3ba6755 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BaseFilterWorker.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BaseFilterWorker.kt @@ -16,28 +16,17 @@ package com.example.background.workers.filters -import android.R.drawable -import android.annotation.TargetApi -import android.app.Notification -import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri -import android.os.Build.VERSION -import android.os.Build.VERSION_CODES import android.util.Log -import androidx.annotation.StringRes import androidx.annotation.VisibleForTesting -import androidx.core.app.NotificationCompat.Builder -import androidx.work.ForegroundInfo -import androidx.work.WorkManager -import androidx.work.Worker -import androidx.work.WorkerParameters -import androidx.work.workDataOf +import androidx.work.* import com.example.background.Constants import com.example.background.library.R +import com.example.background.workers.createNotification import java.io.File import java.io.FileNotFoundException import java.io.FileOutputStream @@ -46,16 +35,12 @@ import java.io.InputStream import java.util.UUID abstract class BaseFilterWorker(context: Context, parameters: WorkerParameters) : - Worker(context, parameters) { + CoroutineWorker(context, parameters) { - private val notificationManager = - context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - - override fun doWork(): Result { + override suspend fun doWork(): Result { val resourceUri = inputData.getString(Constants.KEY_IMAGE_URI) ?: throw IllegalArgumentException("Invalid input uri") return try { - setForegroundAsync(createForegroundInfo()) val inputStream = inputStreamFor(applicationContext, resourceUri) val bitmap = BitmapFactory.decodeStream(inputStream) val output = applyFilter(bitmap) @@ -109,58 +94,16 @@ abstract class BaseFilterWorker(context: Context, parameters: WorkerParameters) /** * Create ForegroundInfo required to run a Worker in a foreground service. */ - private fun createForegroundInfo(): ForegroundInfo { - // For a real world app you might want to use a different id for each Notification. - val notificationId = 1 - return ForegroundInfo(notificationId, createNotification()) - } - - /** - * Create the notification and required channel (O+) for running work in a foreground service. - */ - private fun createNotification(): Notification { - val channelId = getString(R.string.notification_channel_id) - val title = getString(R.string.notification_title) - val cancel = getString(R.string.cancel_processing) - val name = getString(R.string.channel_name) - // This PendingIntent can be used to cancel the Worker. - val intent = WorkManager.getInstance(applicationContext).createCancelPendingIntent(id) - - val builder = Builder(applicationContext, channelId) - .setContentTitle(title) - .setTicker(title) - .setSmallIcon(R.drawable.baseline_gradient) - .setOngoing(true) - .addAction(drawable.ic_delete, cancel, intent) - if (VERSION.SDK_INT >= VERSION_CODES.O) { - createNotificationChannel(channelId, name).also { - builder.setChannelId(it.id) - } - } - return builder.build() - } - - - private fun getString(@StringRes id: Int) = applicationContext.getString(id) - - /** - * Create the required notification channel for O+ devices. - */ - @TargetApi(VERSION_CODES.O) - private fun createNotificationChannel( - channelId: String, - name: String - ): NotificationChannel { - return NotificationChannel( - channelId, name, NotificationManager.IMPORTANCE_LOW - ).also { channel -> - notificationManager.createNotificationChannel(channel) - } + override suspend fun getForegroundInfo(): ForegroundInfo { + return ForegroundInfo(NOTIFICATION_ID, createNotification(applicationContext, id, + applicationContext.getString(R.string.notification_title_filtering_image))) } companion object { const val TAG = "BaseFilterWorker" const val ASSET_PREFIX = "file:///android_asset/" + // For a real world app you might want to use a different id for each Notification. + const val NOTIFICATION_ID = 1 /** * Creates an input stream which can be used to read the given `resourceUri`. diff --git a/WorkManagerSample/lib/src/main/res/values/strings.xml b/WorkManagerSample/lib/src/main/res/values/strings.xml index cbeaccd..61d2b40 100644 --- a/WorkManagerSample/lib/src/main/res/values/strings.xml +++ b/WorkManagerSample/lib/src/main/res/values/strings.xml @@ -17,7 +17,8 @@ WorkManagerSample - WorkManager Sample + WorkManager Sample: Filtering Image + WorkManager Sample: Saving Filtered Image Cancel processing WorkManager Sample \ No newline at end of file diff --git a/WorkManagerSample/versions.gradle b/WorkManagerSample/versions.gradle index 5dc8792..e5cd59f 100644 --- a/WorkManagerSample/versions.gradle +++ b/WorkManagerSample/versions.gradle @@ -62,12 +62,12 @@ versions.rxjava2 = "2.1.3" versions.timber = "4.7.1" versions.transition = "1.3.0" versions.truth = "1.0.1" -versions.work = "2.6.0" +versions.work = "2.7.0-rc01" ext.versions = versions def build_versions = [:] -build_versions.min_sdk = 14 -build_versions.compile_sdk = 29 +build_versions.min_sdk = 21 +build_versions.compile_sdk = 31 build_versions.target_sdk = 29 build_versions.build_tools = "29.0.3" ext.build_versions = build_versions -- GitLab