Skip to content

Commit

Permalink
Add Persistent, Pauseable Uploads (#20)
Browse files Browse the repository at this point in the history
* Add UploadPersistence file

* More skeleton

* Read and Write with UploadPersistence

* Update

* Wait that's all I need

* minor naming things

* up

* Use SharedFlow

* Gotta test the listeners

* Save progress updates

* Update callbacks and stuff

* Yay it works

* This is better

* up

* Rename

* Try this

* Ok

* Spedoinkle

* alfjk

* Make sure to set up

* moment of truth

* Heck yes

* cleanup

* iup

* Ok now it cancels to much and doesn't update UploadInfo job

* Add a pause button

* OK here we are

* Skip to actual file pos

* pause with integrity
  • Loading branch information
daytime-em authored Apr 5, 2023
1 parent 2ba3368 commit b09428d
Show file tree
Hide file tree
Showing 15 changed files with 464 additions and 160 deletions.
14 changes: 1 addition & 13 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<application
android:allowBackup="true"
android:name=".UploadExampleApp"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
Expand All @@ -31,19 +32,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".PlaceholderActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>

</manifest>
11 changes: 11 additions & 0 deletions app/src/main/java/com/mux/video/vod/demo/UploadExampleApp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.mux.video.vod.demo

import android.app.Application
import com.mux.video.upload.MuxUploadSdk

class UploadExampleApp : Application() {
override fun onCreate() {
super.onCreate()
MuxUploadSdk.initialize(this)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class MediaStoreVideosActivity : AppCompatActivity() {
companion object {
// For now, you have to paste this from the direct-upload response
const val PUT_URL =
"https://storage.googleapis.com/video-storage-gcp-us-east1-vop1-uploads/zExa1hBKQ3eFjd8RE9a38G?Expires=1680553720&GoogleAccessId=uploads-gcp-us-east1-vop1%40mux-video-production.iam.gserviceaccount.com&Signature=yO9FvxH688VRa7da2cWoVDEDpQuTXkWzBO3rfWUL2fxSdsyB%2FZvaRotAAojtSJ3SAlqWFWuqSPhJhYDbAmDxd1lsqr5ILY7S%2FnlcJhriHdB6ygykF5mKS%2BV29AvZ5uUiyxRkWR9IK1adoxup%2FHZJ3bV6iXne%2BiKirxAJBeQL7%2FvKjLU53VtSv1mso4kWilorxp9p24bXQP0sSDexLIAfBKo1yE1KKyAJaUs9qTEFOUMSkH7%2BLCXxEJPCli9WwvTtpTQ1Qk9Ri9n11XWliFeOwUIb%2B2tb1BqZzo9GSc4Bc4w04wyT%2BIMRrFuOj7NVGEzBcbdTDPXPOQ0WajkjEkyGHA%3D%3D&upload_id=ADPycduVimwfe--UstCIP70zfr9O4C3B5TfT2vdQVHP-hz4_sxQqmJUnMUG7rA9cKbkymOFAWeJjQOruq_uv_HLvglwnhQ"
"https://storage.googleapis.com/video-storage-gcp-us-east1-vop1-uploads/ivU3KeuN6aBRasvUQflUWG?Expires=1680730767&GoogleAccessId=uploads-gcp-us-east1-vop1%40mux-video-production.iam.gserviceaccount.com&Signature=x4H5Ce8517S1D5oWoGJ2Bf6xlpwtyUpdF6LiLpqyKlpVBiXPKB5ImlA3fti0CUWJJSsO1g5G8jpyeA%2FwFv7hEInDmWa9gyO3oGRKCynv5WfDtndsedRvUCrQQBJXsRWex5VLdK5imLwo1kwEjATGZSwIZ7oK3ciH2gNPG%2BTymmGlyrrCzWloQ0jYhhpQLjNFZL3iYm%2BMGalZdXkndSqTeX%2F1j8rMHBrZ3HLJxqt8RYn5xCMTLAPET2kp7LEW4Vrj8Cn0DgkBnY46hQzc3KjbvK4orAUMSacmqADRtT6w3jm9XcOZFXnqwfJphrNcEs%2FUmGgtMFi6z3oJUT6b9Pg6yg%3D%3D&upload_id=ADPycdvjKQvrueNuLUqPXj3uo_bLjJ9pHBgDxYfAllAT_GjiO2_4a35u8dtKNXd6ynqZpMplbHtzRd9TcjCcIPUfsaSoxBelRqNX"
}

private lateinit var binding: ActivityVideoListBinding
Expand Down Expand Up @@ -58,8 +58,7 @@ class MediaStoreVideosActivity : AppCompatActivity() {
}

private fun handleListUpdate(list: List<MuxUpload>) {
// TODO: Use AsyncListDiffer to make this look nice
listAdapter = MediaStoreVideosAdapter(list)
listAdapter = MediaStoreVideosAdapter(list, viewModel)
binding.videoListList.includeRecyclerView.adapter = listAdapter
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.mux.video.upload.api.MuxUpload
import com.mux.video.vod.demo.databinding.ListItemUploadingVideoBinding
import java.text.DecimalFormat
import java.util.*

class MediaStoreVideosAdapter(
private var items: List<MuxUpload>,
private var viewModel: MediaStoreVideosViewModel,
) : RecyclerView.Adapter<MediaStoreVideoViewHolder>() {

private var progressConsumer: Consumer<MuxUpload.State>? = null
private var progressConsumer: Consumer<MuxUpload.Progress>? = null

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaStoreVideoViewHolder {
val viewBinding =
Expand Down Expand Up @@ -46,6 +46,20 @@ class MediaStoreVideosAdapter(
holder.viewBinding.mediastoreVideoDate.text =
"${listItem.currentState.bytesUploaded} bytes in ${elapsedTime / 1000F} s elapsed "
holder.viewBinding.mediastoreVideoFilesize.text = "${formattedRate} KBytes/s"

if (listItem.isRunning) {
holder.viewBinding.mediastoreVideoPause.setImageResource(android.R.drawable.ic_media_pause)
} else {
holder.viewBinding.mediastoreVideoPause.setImageResource(android.R.drawable.ic_media_play)
}

holder.viewBinding.mediastoreVideoPause.setOnClickListener {
if (listItem.isRunning) {
listItem.pause()
} else {
listItem.start()
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import android.os.Build
import android.provider.MediaStore
import android.provider.MediaStore.Video.VideoColumns
import android.util.Log
import android.widget.Toast
import androidx.core.text.htmlEncode
import androidx.core.util.Consumer
import androidx.lifecycle.AndroidViewModel
Expand Down Expand Up @@ -44,15 +45,19 @@ class MediaStoreVideosViewModel(private val app: Application) : AndroidViewModel
Log.d(javaClass.simpleName, "Copied file to $copiedFile")

val upl = MuxUpload.Builder(MediaStoreVideosActivity.PUT_URL, copiedFile).build()
upl.addProgressConsumer(Consumer {
Log.v(javaClass.simpleName, "Upload progress: ${it.bytesUploaded} / ${it.totalBytes}")
upl.addProgressListener {
//Log.v(javaClass.simpleName, "Upload progress: ${it.bytesUploaded} / ${it.totalBytes}")
innerUploads.postValue(uploadList)
})
upl.addSuccessConsumer(Consumer {
Log.w(javaClass.simpleName, "YAY! Uploaded the file: $contentUri")
Log.i(javaClass.simpleName, "final state is $it")
innerUploads.postValue(uploadList)
})
}
upl.addResultListener {
if (it.isSuccess) {
Log.w(javaClass.simpleName, "YAY! Uploaded the file: $contentUri")
Log.i(javaClass.simpleName, "final state is $it")
innerUploads.postValue(uploadList)
} else {
innerUploads.postValue(uploadList)
}
}
uploadList += upl
innerUploads.postValue(uploadList)

Expand Down Expand Up @@ -98,7 +103,7 @@ class MediaStoreVideosViewModel(private val app: Application) : AndroidViewModel
return destFile
}

// TODO: Don't need
// Might need something like this
private suspend fun fetchVideos(): List<UploadingVideo> {
fun ownerPackageName(cursor: Cursor): String {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/res/layout/list_item_uploading_video.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@
android:layout_marginTop="18dp"
xmlns:tools="http://schemas.android.com/tools">

<ImageButton
android:id="@+id/mediastore_video_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_media_pause"
android:contentDescription="@string/pause_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>

<!-- TODO: A thumbnail from the content provider would be pretty easy-->
<TextView
android:id="@+id/mediastore_video_title"
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<resources>
<string name="app_name">Mux Video VOD Upload SDK</string>
<string name="title_activity_scrolling">ScrollingActivity</string>
<string name="title_activity_scrolling">Mux Upload Example</string>
<string name="action_settings">Settings</string>
<string name="pause_button">Pause Button</string>
</resources>
1 change: 0 additions & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ dependencies {

implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
implementation "com.squareup.okhttp3:okhttp:4.10.0"
implementation "com.mux:utils-kt:0.7.2"

implementation 'androidx.core:core-ktx:1.9.0'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
Expand Down
9 changes: 7 additions & 2 deletions library/src/main/java/com/mux/video/upload/MuxUploadSdk.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.mux.video.upload
import android.content.Context
import android.util.Log
import com.mux.video.upload.internal.UploadJobFactory
import com.mux.video.upload.internal.initializeUploadPersistence
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import java.util.concurrent.TimeUnit
Expand All @@ -14,9 +15,9 @@ import java.util.concurrent.TimeUnit
*/
object MuxUploadSdk {
/**
* The current version of this SDK. Release builds of this SDK strictly follow the rules of
* semantic versioning (https://semver.org)
* The current version of this SDK. Release builds of this SDK follow semver (https://semver.org)
*/
@Suppress("unused")
const val VERSION = BuildConfig.LIB_VERSION

/**
Expand Down Expand Up @@ -53,15 +54,19 @@ object MuxUploadSdk {
.build()
}

@Suppress("unused")
fun initialize(appContext: Context) {
// TODO: Collect caller app metrics, get the cache directory, etc.
// Also, try not to save the appContext. Context.applicationContext is safe to hold statically
// but it makes compiler warnings

initializeUploadPersistence(appContext)
}

/**
* Use the specified [OkHttpClient] instead of the default internal okhttp client
*/
@Suppress("unused")
fun useOkHttpClient(okHttpClient: OkHttpClient) {
httpClient = okHttpClient
}
Expand Down
Loading

0 comments on commit b09428d

Please sign in to comment.