Skip to content

Commit

Permalink
Refactored to use JobIntentService for artwork download
Browse files Browse the repository at this point in the history
  • Loading branch information
banasiak committed Dec 27, 2020
1 parent 2df5dc1 commit 960d178
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 43 deletions.
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.banasiak.android.muzeisaver">

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application
android:name=".MuzeiSaverApp"
Expand Down Expand Up @@ -39,6 +39,7 @@

<service
android:name=".download.DownloadService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false" />

<service
Expand Down
22 changes: 9 additions & 13 deletions app/src/main/java/com/banasiak/android/muzeisaver/MuzeiSaverApp.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.banasiak.android.muzeisaver

import android.annotation.SuppressLint
import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
Expand All @@ -11,37 +10,34 @@ import com.banasiak.android.muzeisaver.download.DownloadService
import timber.log.Timber

class MuzeiSaverApp : Application() {

private val isAndroidM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
private val isAndroidO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O

@SuppressLint("NewApi")
override fun onCreate() {
super.onCreate()

if (isAndroidO) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = NotificationManagerCompat.from(this)
val notificationChannel = NotificationChannel(
DownloadService.NOTIFICATION_ID.toString(),
getString(R.string.download_service),
NotificationManager.IMPORTANCE_LOW)
DownloadService.DOWNLOAD_COMPLETE_ID.toString(),
getString(R.string.download_complete),
NotificationManager.IMPORTANCE_HIGH)
notificationManager.createNotificationChannels(listOf(notificationChannel))
}

if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectNetwork()
.also {
if (isAndroidM) it.detectResourceMismatches()
if (isAndroidO) it.detectUnbufferedIo()
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) detectResourceMismatches()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) detectUnbufferedIo()
}
.penaltyLog()
.penaltyDeath()
.build())

StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyDeath()
.build())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ class DownloadActivity : AppCompatActivity() {
showErrorAndFinish(R.string.unable_to_save)
return
}
Intent(this, DownloadService::class.java)
val intent = Intent()
.also {
it.flags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION
it.data = data?.data
startService(it)
}
DownloadService.enqueueWork(this, intent)
finish()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,50 +1,48 @@
package com.banasiak.android.muzeisaver.download

import android.app.IntentService
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import android.os.Build
import androidx.annotation.StringRes
import androidx.core.app.JobIntentService
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.res.ResourcesCompat
import com.banasiak.android.muzeisaver.R
import com.google.android.apps.muzei.api.MuzeiContract
import timber.log.Timber

class DownloadService : IntentService("DownloadService") {

class DownloadService : JobIntentService() {
companion object {
const val NOTIFICATION_ID = 62180
const val DOWNLOAD_COMPLETE_ID = 62181
private const val JOB_ID = 1000
private const val NOTIFICATION_TIMEOUT = 5 * 1000L //5 seconds

fun enqueueWork(context: Context, intent: Intent) {
enqueueWork(context, DownloadService::class.java, JOB_ID, intent)
}
}

override fun onHandleIntent(intent: Intent?) {
val data = requireNotNull(intent?.data) { "File URI must be provided" }
val notification = NotificationCompat.Builder(this, NOTIFICATION_ID.toString())
.setSmallIcon(R.drawable.ic_file_download)
.setColor(ResourcesCompat.getColor(resources, R.color.ic_launcher_background, null))
.setContentTitle(getString(R.string.downloading_artwork))
.setProgress(0, 0, true)
.build()
startForeground(NOTIFICATION_ID, notification)
override fun onHandleWork(intent: Intent) {
val data = requireNotNull(intent.data) { "Content URI must be provided" }
downloadArtwork(data)
stopForeground(true)
}

private fun downloadArtwork(fileUri: Uri) {
val bitmap: Bitmap? = contentResolver.openInputStream(MuzeiContract.Artwork.CONTENT_URI).use {
BitmapFactory.decodeStream(it)
}
if (bitmap == null) {
showToast(message = R.string.unable_to_save, isError = true)
notify(message = R.string.unable_to_save)
return
}
when (saveBitmapToFile(fileUri, bitmap)) {
true -> showToast(message = R.string.success)
false -> showToast(message = R.string.unable_to_save, isError = true)
true -> notify(message = R.string.success, uri = fileUri)
false -> notify(message = R.string.unable_to_save)
}
}

Expand All @@ -61,9 +59,25 @@ class DownloadService : IntentService("DownloadService") {
}
}

private fun showToast(@StringRes message: Int, isError: Boolean = false) {
if (isError) Timber.e(getString(message)) else Timber.i(getString(message))
Handler(Looper.getMainLooper()).post { Toast.makeText(this, message, Toast.LENGTH_SHORT).show() }
private fun notify(@StringRes message: Int, uri: Uri? = null) {
if (uri == null) Timber.e(getString(message)) else Timber.i(getString(message))
val notification = NotificationCompat.Builder(this, DOWNLOAD_COMPLETE_ID.toString())
.setSmallIcon(R.drawable.ic_file_download)
.setColor(ResourcesCompat.getColor(resources, R.color.ic_launcher_background, null))
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(message))
.setPriority(NotificationCompat.PRIORITY_MAX)
.setTimeoutAfter(NOTIFICATION_TIMEOUT)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && uri != null) {
setLargeIcon(ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, uri)))
}
}
.build()

NotificationManagerCompat.from(this).apply {
notify(DOWNLOAD_COMPLETE_ID, notification)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import androidx.appcompat.app.AppCompatDialogFragment
import com.banasiak.android.muzeisaver.R

class QuickSettingsDialog : AppCompatDialogFragment() {

interface DialogListener {
fun onPositiveClick()
fun onNegativeClick()
Expand All @@ -34,7 +33,6 @@ class QuickSettingsDialog : AppCompatDialogFragment() {
}

dialogView = LayoutInflater.from(_context).inflate(R.layout.dialog, null)

val alertBuilder = AlertDialog.Builder(_context).apply {
setView(dialogView)
setPositiveButton(R.string.show) { _, _ -> listener.onPositiveClick() }
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Muzei Saver</string>
<string name="downloading_artwork">Downloading Muzei Artwork</string>
<string name="download_service">Download Service</string>
<string name="download_complete">Download Complete</string>
<string name="hide">Hide</string>
<string name="instructions">Congrats on finding the quick settings tile! From now on tapping this tile will prompt you to save the current Muzei artwork.\n\nWould you like to remove the launcher icon from the app drawer? Long press this tile if you change your mind.\n\nNote: This may not work on all versions of Android and a device restart might be necessary for the change to take effect.</string>
<string name="launcher_disabled">Launcher Icon Disabled</string>
Expand Down

0 comments on commit 960d178

Please sign in to comment.