未验证 提交 efe4f716 编写于 作者: C Caren 提交者: GitHub

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: NMurat Yener <yenerm@google.com>
上级 1c8fc23b
...@@ -26,7 +26,7 @@ android { ...@@ -26,7 +26,7 @@ android {
useSupportLibrary true useSupportLibrary true
} }
// Switching to Renderscript support provided by framework. // Switching to Renderscript support provided by framework.
minSdkVersion 18 minSdkVersion build_versions.min_sdk
targetSdkVersion build_versions.target_sdk targetSdkVersion build_versions.target_sdk
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
......
...@@ -34,13 +34,18 @@ ...@@ -34,13 +34,18 @@
android:requestLegacyExternalStorage="true"> android:requestLegacyExternalStorage="true">
<provider <provider
android:name="androidx.work.impl.WorkManagerInitializer" android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.workmanager-init" android:authorities="${applicationId}.androidx-startup"
android:directBootAware="false" android:directBootAware="false"
android:exported="false" android:exported="false"
android:multiprocess="true" android:multiprocess="true"
tools:node="remove" tools:targetApi="n"
tools:targetApi="n" /> tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
<activity android:name=".SelectImageActivity"> <activity android:name=".SelectImageActivity">
<intent-filter> <intent-filter>
......
...@@ -26,7 +26,7 @@ android { ...@@ -26,7 +26,7 @@ android {
useSupportLibrary true useSupportLibrary true
} }
// Switching to Renderscript support provided by framework. // Switching to Renderscript support provided by framework.
minSdkVersion 18 minSdkVersion build_versions.min_sdk
targetSdkVersion build_versions.target_sdk targetSdkVersion build_versions.target_sdk
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
......
...@@ -24,6 +24,7 @@ import androidx.work.ExistingWorkPolicy ...@@ -24,6 +24,7 @@ import androidx.work.ExistingWorkPolicy
import androidx.work.ListenableWorker import androidx.work.ListenableWorker
import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequest
import androidx.work.OneTimeWorkRequestBuilder import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.OutOfQuotaPolicy
import androidx.work.WorkContinuation import androidx.work.WorkContinuation
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.workDataOf import androidx.work.workDataOf
...@@ -90,6 +91,7 @@ class ImageOperations( ...@@ -90,6 +91,7 @@ class ImageOperations(
) = ) =
OneTimeWorkRequestBuilder<T>().apply { OneTimeWorkRequestBuilder<T>().apply {
setInputData(inputData) setInputData(inputData)
setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
if (!tag.isNullOrEmpty()) { if (!tag.isNullOrEmpty()) {
addTag(tag) addTag(tag)
} }
......
/*
* 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)
}
}
...@@ -23,10 +23,12 @@ import android.net.Uri ...@@ -23,10 +23,12 @@ import android.net.Uri
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.MediaStore.Images.Media import android.provider.MediaStore.Images.Media
import android.util.Log import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.Data import androidx.work.Data
import androidx.work.Worker import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import com.example.background.Constants import com.example.background.Constants
import com.example.background.library.R
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
...@@ -35,9 +37,10 @@ import java.util.Locale ...@@ -35,9 +37,10 @@ import java.util.Locale
* Saves an output image to the [MediaStore]. * Saves an output image to the [MediaStore].
*/ */
class SaveImageToGalleryWorker(appContext: Context, workerParams: WorkerParameters) : 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 val resolver = applicationContext.contentResolver
return try { return try {
val input = Uri.parse(inputData.getString(Constants.KEY_IMAGE_URI)) val input = Uri.parse(inputData.getString(Constants.KEY_IMAGE_URI))
...@@ -62,9 +65,19 @@ class SaveImageToGalleryWorker(appContext: Context, workerParams: WorkerParamete ...@@ -62,9 +65,19 @@ class SaveImageToGalleryWorker(appContext: Context, workerParams: WorkerParamete
return Media.insertImage( return Media.insertImage(
resolver, bitmap, DATE_FORMATTER.format(Date()), TITLE 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 { 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 TAG = "SvImageToGalleryWrkr"
private const val TITLE = "Filtered Image" private const val TITLE = "Filtered Image"
private val DATE_FORMATTER = private val DATE_FORMATTER =
......
...@@ -16,28 +16,17 @@ ...@@ -16,28 +16,17 @@
package com.example.background.workers.filters 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.app.NotificationManager
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.util.Log import android.util.Log
import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.core.app.NotificationCompat.Builder import androidx.work.*
import androidx.work.ForegroundInfo
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import com.example.background.Constants import com.example.background.Constants
import com.example.background.library.R import com.example.background.library.R
import com.example.background.workers.createNotification
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.FileOutputStream import java.io.FileOutputStream
...@@ -46,16 +35,12 @@ import java.io.InputStream ...@@ -46,16 +35,12 @@ import java.io.InputStream
import java.util.UUID import java.util.UUID
abstract class BaseFilterWorker(context: Context, parameters: WorkerParameters) : abstract class BaseFilterWorker(context: Context, parameters: WorkerParameters) :
Worker(context, parameters) { CoroutineWorker(context, parameters) {
private val notificationManager = override suspend fun doWork(): Result {
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
override fun doWork(): Result {
val resourceUri = inputData.getString(Constants.KEY_IMAGE_URI) ?: val resourceUri = inputData.getString(Constants.KEY_IMAGE_URI) ?:
throw IllegalArgumentException("Invalid input uri") throw IllegalArgumentException("Invalid input uri")
return try { return try {
setForegroundAsync(createForegroundInfo())
val inputStream = inputStreamFor(applicationContext, resourceUri) val inputStream = inputStreamFor(applicationContext, resourceUri)
val bitmap = BitmapFactory.decodeStream(inputStream) val bitmap = BitmapFactory.decodeStream(inputStream)
val output = applyFilter(bitmap) val output = applyFilter(bitmap)
...@@ -109,58 +94,16 @@ abstract class BaseFilterWorker(context: Context, parameters: WorkerParameters) ...@@ -109,58 +94,16 @@ abstract class BaseFilterWorker(context: Context, parameters: WorkerParameters)
/** /**
* Create ForegroundInfo required to run a Worker in a foreground service. * Create ForegroundInfo required to run a Worker in a foreground service.
*/ */
private fun createForegroundInfo(): ForegroundInfo { override suspend fun getForegroundInfo(): ForegroundInfo {
// For a real world app you might want to use a different id for each Notification. return ForegroundInfo(NOTIFICATION_ID, createNotification(applicationContext, id,
val notificationId = 1 applicationContext.getString(R.string.notification_title_filtering_image)))
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)
}
} }
companion object { companion object {
const val TAG = "BaseFilterWorker" const val TAG = "BaseFilterWorker"
const val ASSET_PREFIX = "file:///android_asset/" 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`. * Creates an input stream which can be used to read the given `resourceUri`.
......
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
<resources> <resources>
<string name="notification_channel_id">WorkManagerSample</string> <string name="notification_channel_id">WorkManagerSample</string>
<string name="notification_title">WorkManager Sample</string> <string name="notification_title_filtering_image">WorkManager Sample: Filtering Image</string>
<string name="notification_title_saving_image">WorkManager Sample: Saving Filtered Image</string>
<string name="cancel_processing">Cancel processing</string> <string name="cancel_processing">Cancel processing</string>
<string name="channel_name">WorkManager Sample</string> <string name="channel_name">WorkManager Sample</string>
</resources> </resources>
\ No newline at end of file
...@@ -62,12 +62,12 @@ versions.rxjava2 = "2.1.3" ...@@ -62,12 +62,12 @@ versions.rxjava2 = "2.1.3"
versions.timber = "4.7.1" versions.timber = "4.7.1"
versions.transition = "1.3.0" versions.transition = "1.3.0"
versions.truth = "1.0.1" versions.truth = "1.0.1"
versions.work = "2.6.0" versions.work = "2.7.0-rc01"
ext.versions = versions ext.versions = versions
def build_versions = [:] def build_versions = [:]
build_versions.min_sdk = 14 build_versions.min_sdk = 21
build_versions.compile_sdk = 29 build_versions.compile_sdk = 31
build_versions.target_sdk = 29 build_versions.target_sdk = 29
build_versions.build_tools = "29.0.3" build_versions.build_tools = "29.0.3"
ext.build_versions = build_versions ext.build_versions = build_versions
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册