-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Upload Service * up * up * up * up * here is more things * Add an isPaused method * up * Here we are. now to make the notifs * log notified uploads * add ui strings * Now this is podracing * making progress. get it because its a progress notificatin * Ok that's all the notif logic * Hook in upload service * BackgroundUploadService -> UploadNotificationService * Now we got one * up * Ok BG uploads are there * Stop the service also * some horribleness encountered * Fixes some progress-reporting bugs * one last fix * better status notifs * improve * Done * update
- Loading branch information
1 parent
93a9b39
commit 96964b7
Showing
11 changed files
with
370 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
app/src/main/java/com/mux/video/vod/demo/UploadExampleApp.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,34 @@ | ||
package com.mux.video.vod.demo | ||
|
||
import android.annotation.TargetApi | ||
import android.app.Application | ||
import android.app.NotificationChannel | ||
import android.app.NotificationManager | ||
import android.os.Build | ||
import com.mux.video.upload.MuxUploadSdk | ||
import com.mux.video.upload.api.MuxUploadManager | ||
|
||
class UploadExampleApp : Application() { | ||
|
||
override fun onCreate() { | ||
super.onCreate() | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||
createNotificationChannel() | ||
} | ||
MuxUploadSdk.initialize(this) | ||
if (MuxUploadManager.allUploadJobs().isNotEmpty()) { | ||
UploadNotificationService.startCompat(this) | ||
} | ||
} | ||
|
||
@TargetApi(Build.VERSION_CODES.O) | ||
private fun createNotificationChannel() { | ||
val channel = NotificationChannel( | ||
UploadNotificationService.CHANNEL_UPLOAD_PROGRESS, | ||
getString(R.string.notif_channel_name), | ||
NotificationManager.IMPORTANCE_LOW | ||
) | ||
channel.description = getString(R.string.notif_channel_desc) | ||
getSystemService(NotificationManager::class.java).createNotificationChannel(channel) | ||
} | ||
} |
221 changes: 221 additions & 0 deletions
221
app/src/main/java/com/mux/video/vod/demo/UploadNotificationService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
package com.mux.video.vod.demo | ||
|
||
import android.annotation.SuppressLint | ||
import android.annotation.TargetApi | ||
import android.app.Service | ||
import android.content.Context | ||
import android.content.Intent | ||
import android.content.pm.ServiceInfo | ||
import android.os.Binder | ||
import android.os.Build | ||
import android.os.IBinder | ||
import android.util.Log | ||
import androidx.core.app.NotificationCompat | ||
import androidx.core.app.ServiceCompat | ||
import com.mux.video.upload.api.MuxUpload | ||
import com.mux.video.upload.api.MuxUploadManager | ||
import com.mux.video.upload.api.UploadEventListener | ||
import com.mux.video.upload.api.UploadStatus | ||
|
||
/** | ||
* Service that monitors ongoing [MuxUpload]s, showing progress notifications for them. This | ||
* service will enter the foreground whenever there are uploads in progress and will exit foreground | ||
* and stop itself when there are no more uploads in progress (ie, all have completed, paused, or | ||
* failed) | ||
*/ | ||
class UploadNotificationService : Service() { | ||
|
||
companion object { | ||
private const val TAG = "BackgroundUploadService" | ||
|
||
const val ACTION_START = "start" | ||
const val NOTIFICATION_FG = 200002 | ||
const val CHANNEL_UPLOAD_PROGRESS = "upload_progress" | ||
|
||
fun startCompat(context: Context) { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||
startImplApiO(context) | ||
} else { | ||
startImplLegacy(context) | ||
} | ||
} | ||
|
||
@TargetApi(Build.VERSION_CODES.O) | ||
private fun startImplApiO(context: Context) { | ||
val startIntent = Intent(context, UploadNotificationService::class.java) | ||
startIntent.action = ACTION_START | ||
context.startForegroundService(startIntent) | ||
} | ||
|
||
private fun startImplLegacy(context: Context) { | ||
val startIntent = Intent(context, UploadNotificationService::class.java) | ||
startIntent.action = ACTION_START | ||
context.startService(startIntent) | ||
} | ||
} | ||
|
||
private var uploadListListener: UploadListListener? = null | ||
// uploads tracked by this Service, regardless of state. cleared when the service is destroyed | ||
private val uploadsByFile = mutableMapOf<String, MuxUpload>() | ||
|
||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { | ||
val action = intent?.action | ||
if (action != ACTION_START) { | ||
throw RuntimeException("Unknown action") | ||
} | ||
|
||
// can be commanded to start arbitrary number of times | ||
if (uploadListListener == null) { | ||
notify(MuxUploadManager.allUploadJobs()) | ||
|
||
val lis = UploadListListener() | ||
this.uploadListListener = lis | ||
MuxUploadManager.addUploadsUpdatedListener(lis) | ||
} | ||
|
||
return super.onStartCommand(intent, flags, startId) | ||
} | ||
|
||
override fun onBind(intent: Intent?): IBinder? { | ||
return MyBinder() | ||
} | ||
|
||
override fun onDestroy() { | ||
uploadListListener?.let { MuxUploadManager.removeUploadsUpdatedListener(it) } | ||
} | ||
|
||
private fun notifyWithCurrentUploads() = notify(this.uploadsByFile.values) | ||
|
||
@SuppressLint("InlinedApi", "MissingPermission") // inline use of FOREGROUND_SERVICE | ||
private fun notify(uploads: Collection<MuxUpload>) { | ||
if (uploads.isEmpty()) { | ||
// only notify if there are uploads being tracked (in-progress or finished) | ||
return | ||
} | ||
|
||
val uploadsInProgress = uploads.filter { it.isRunning } | ||
val uploadsCompleted = uploads.filter { it.isSuccessful } | ||
val uploadsFailed = uploads.filter { it.error != null } | ||
|
||
Log.v(TAG, "notify: uploadsInProgress: ${uploadsInProgress.size}") | ||
Log.v(TAG, "notify: uploadsCompleted: ${uploadsCompleted.size}") | ||
Log.v(TAG, "notify: uploadsFailed: ${uploadsFailed.size}") | ||
|
||
val builder = NotificationCompat.Builder(this, CHANNEL_UPLOAD_PROGRESS) | ||
builder.setSmallIcon(R.drawable.ic_launcher) | ||
builder.setAutoCancel(false) | ||
builder.setOngoing(true) | ||
|
||
if (uploadsInProgress.isNotEmpty()) { | ||
Log.d(TAG, "notifying progress") | ||
if (uploadsInProgress.size == 1 && this.uploadsByFile.size == 1) { | ||
// Special case: A single upload in progress, with a single upload requested | ||
val upload = uploadsInProgress.first() | ||
val kbUploaded = (upload.currentProgress.bytesUploaded / 1024).toInt() | ||
val kbTotal = (upload.currentProgress.totalBytes / 1024).toInt() | ||
|
||
Log.d(TAG, "upload state: ${upload.uploadStatus}") | ||
|
||
builder.setProgress(kbTotal, kbUploaded, false) | ||
builder.setContentText( | ||
resources.getQuantityString( | ||
R.plurals.notif_txt_uploading, 1, 1, 1 | ||
) | ||
) | ||
builder.setContentTitle( | ||
resources.getQuantityString( | ||
R.plurals.notif_title_uploading, 1, 1 | ||
) | ||
) | ||
} else { | ||
// Multiple uploads requested simultaneously so we batch them into one | ||
val totalKbUploaded = uploadsInProgress.sumOf { it.currentProgress.bytesUploaded / 1024 } | ||
val totalKb = uploadsInProgress.sumOf { it.currentProgress.totalBytes / 1024 } | ||
|
||
builder.setProgress(totalKb.toInt(),totalKbUploaded.toInt(), false) | ||
builder.setContentText( | ||
resources.getQuantityString( | ||
R.plurals.notif_txt_uploading, | ||
uploads.size, | ||
uploadsInProgress.size, | ||
) | ||
) | ||
builder.setContentTitle( | ||
resources.getQuantityString( | ||
R.plurals.notif_title_uploading, uploads.size, | ||
uploads.size | ||
) | ||
) | ||
} | ||
} else if (uploadsFailed.isNotEmpty()) { | ||
Log.i(TAG, "notifying Fail") | ||
builder.setContentTitle( | ||
resources.getQuantityString( | ||
R.plurals.notif_title_failed, | ||
uploadsFailed.size, | ||
uploadsFailed.size | ||
) | ||
) | ||
builder.setContentText( | ||
resources.getQuantityString( | ||
R.plurals.notif_txt_failed, | ||
uploadsFailed.size, | ||
uploadsFailed.size | ||
) | ||
) | ||
} else if (uploadsCompleted.isNotEmpty()) { | ||
Log.i(TAG, "notifying Complete") | ||
builder.setContentText(getString(R.string.notif_txt_success)) | ||
builder.setContentTitle( | ||
resources.getQuantityString( | ||
R.plurals.notif_title_success, | ||
uploadsCompleted.size, | ||
uploadsCompleted.size, | ||
) | ||
) | ||
} | ||
|
||
// always startForeground even if we're about to detach (to update the notification) | ||
ServiceCompat.startForeground( | ||
this, | ||
NOTIFICATION_FG, | ||
builder.build(), | ||
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC | ||
) | ||
|
||
if (uploadsInProgress.isEmpty()) { | ||
// we only need foreground/to even be running while uploads are actually running | ||
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH) | ||
stopSelf() | ||
} | ||
} | ||
|
||
private fun updateCurrentUploads(incomingUploads: List<MuxUpload>) { | ||
// listen to status of new uploads | ||
incomingUploads | ||
.filter { !this.uploadsByFile.containsKey(it.videoFile.path) } | ||
.forEach { | ||
this.uploadsByFile[it.videoFile.path] = it | ||
it.setStatusListener(UploadStatusListener()) | ||
} | ||
} | ||
|
||
private inner class UploadListListener : UploadEventListener<List<MuxUpload>> { | ||
override fun onEvent(event: List<MuxUpload>) { | ||
val service = this@UploadNotificationService | ||
service.updateCurrentUploads(event) | ||
service.notifyWithCurrentUploads() | ||
} | ||
} | ||
|
||
private inner class UploadStatusListener : UploadEventListener<UploadStatus> { | ||
override fun onEvent(event: UploadStatus) { | ||
val service = this@UploadNotificationService | ||
service.notifyWithCurrentUploads() | ||
} | ||
} | ||
|
||
private inner class MyBinder : Binder() { | ||
fun getService(): UploadNotificationService = this@UploadNotificationService | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.