diff --git a/video/app/build.gradle.kts b/video/app/build.gradle.kts index 00328d68cd..39b8101922 100644 --- a/video/app/build.gradle.kts +++ b/video/app/build.gradle.kts @@ -66,8 +66,8 @@ dependencies { implementation(project(":video")) implementation(project(":core-util")) implementation("androidx.work:work-runtime-ktx:2.9.0") - debugImplementation(libs.androidx.compose.ui.tooling.core) - debugImplementation(libs.androidx.compose.ui.test.manifest) + implementation(libs.androidx.compose.ui.tooling.core) + implementation(libs.androidx.compose.ui.test.manifest) androidTestImplementation(testLibs.junit.junit) androidTestImplementation(testLibs.androidx.test.runner) androidTestImplementation(testLibs.androidx.test.ext.junit.ktx) diff --git a/video/app/src/main/java/org/thoughtcrime/video/app/MainActivity.kt b/video/app/src/main/java/org/thoughtcrime/video/app/MainActivity.kt index c14daa8181..44841805e0 100644 --- a/video/app/src/main/java/org/thoughtcrime/video/app/MainActivity.kt +++ b/video/app/src/main/java/org/thoughtcrime/video/app/MainActivity.kt @@ -5,8 +5,11 @@ package org.thoughtcrime.video.app +import android.content.Context import android.content.Intent +import android.media.MediaScannerConnection import android.os.Bundle +import android.os.Environment import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.layout.Arrangement @@ -16,6 +19,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import org.signal.core.util.logging.Log import org.thoughtcrime.video.app.playback.PlaybackTestActivity import org.thoughtcrime.video.app.transcode.TranscodeTestActivity import org.thoughtcrime.video.app.ui.composables.LabeledButton @@ -25,6 +29,7 @@ import org.thoughtcrime.video.app.ui.theme.SignalTheme * Main activity for this sample app. */ class MainActivity : AppCompatActivity() { + private val TAG = Log.tag(MainActivity::class.java) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -44,4 +49,20 @@ class MainActivity : AppCompatActivity() { } } } + + override fun onStart() { + super.onStart() + refreshMediaProviderForExternalStorage(this, arrayOf("video/*")) + } + + private fun refreshMediaProviderForExternalStorage(context: Context, mimeTypes: Array) { + val rootPath = Environment.getExternalStorageDirectory().absolutePath + MediaScannerConnection.scanFile( + context, + arrayOf(rootPath), + mimeTypes + ) { _, _ -> + Log.i(TAG, "Re-scan of external storage for media completed.") + } + } } diff --git a/video/app/src/main/java/org/thoughtcrime/video/app/transcode/Constants.kt b/video/app/src/main/java/org/thoughtcrime/video/app/transcode/Constants.kt index c87fb59c61..35374abd75 100644 --- a/video/app/src/main/java/org/thoughtcrime/video/app/transcode/Constants.kt +++ b/video/app/src/main/java/org/thoughtcrime/video/app/transcode/Constants.kt @@ -8,9 +8,9 @@ package org.thoughtcrime.video.app.transcode /** * A dumping ground for constants that should be referenced across the sample app. */ -internal const val MIN_VIDEO_MEGABITRATE = 2f -internal const val DEFAULT_VIDEO_MEGABITRATE = 2f -internal const val MAX_VIDEO_MEGABITRATE = 10f +internal const val MIN_VIDEO_MEGABITRATE = 0.5f +internal const val DEFAULT_VIDEO_MEGABITRATE = 2.5f +internal const val MAX_VIDEO_MEGABITRATE = 5f enum class VideoResolution(val longEdge: Int, val shortEdge: Int) { SD(854, 480), diff --git a/video/app/src/main/java/org/thoughtcrime/video/app/transcode/TranscodeTestActivity.kt b/video/app/src/main/java/org/thoughtcrime/video/app/transcode/TranscodeTestActivity.kt index 59fd1cae66..21e015a2e2 100644 --- a/video/app/src/main/java/org/thoughtcrime/video/app/transcode/TranscodeTestActivity.kt +++ b/video/app/src/main/java/org/thoughtcrime/video/app/transcode/TranscodeTestActivity.kt @@ -8,6 +8,7 @@ package org.thoughtcrime.video.app.transcode import android.Manifest import android.app.NotificationChannel import android.app.NotificationManager +import android.content.DialogInterface import android.content.Intent import android.content.pm.PackageManager import android.net.Uri @@ -26,7 +27,9 @@ import androidx.compose.material3.Surface import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView +import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat +import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.thoughtcrime.video.app.R import org.thoughtcrime.video.app.transcode.composables.ConfigureEncodingParameters import org.thoughtcrime.video.app.transcode.composables.SelectInput @@ -85,11 +88,27 @@ class TranscodeTestActivity : AppCompatActivity() { } } getComposeView()?.keepScreenOn = true - if (Build.VERSION.SDK_INT >= 33 && ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { - requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) + if (Build.VERSION.SDK_INT >= 33) { + val notificationPermissionStatus = ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) + Log.v(TAG, "Notification permission status: $notificationPermissionStatus") + if (notificationPermissionStatus != PackageManager.PERMISSION_GRANTED) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.POST_NOTIFICATIONS)) { + showPermissionRationaleDialog { _, _ -> requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) } + } else { + requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) + } + } } } + private fun showPermissionRationaleDialog(okListener: DialogInterface.OnClickListener) { + MaterialAlertDialogBuilder(this) + .setTitle("The system will request the notification permission.") + .setMessage("This permission is required to show the transcoding progress in the notification tray.") + .setPositiveButton("Ok", okListener) + .show() + } + /** * This launches the system media picker and stores the resulting URI. */ diff --git a/video/app/src/main/java/org/thoughtcrime/video/app/transcode/composables/ConfigurationSelection.kt b/video/app/src/main/java/org/thoughtcrime/video/app/transcode/composables/ConfigurationSelection.kt index bbd5564bb1..4b6d7cc41d 100644 --- a/video/app/src/main/java/org/thoughtcrime/video/app/transcode/composables/ConfigurationSelection.kt +++ b/video/app/src/main/java/org/thoughtcrime/video/app/transcode/composables/ConfigurationSelection.kt @@ -40,7 +40,6 @@ import org.thoughtcrime.video.app.transcode.MAX_VIDEO_MEGABITRATE import org.thoughtcrime.video.app.transcode.MIN_VIDEO_MEGABITRATE import org.thoughtcrime.video.app.transcode.VideoResolution import org.thoughtcrime.video.app.ui.composables.LabeledButton -import kotlin.math.roundToInt /** * A view that shows the queue of video URIs to encode, and allows you to change the encoding options. @@ -83,6 +82,21 @@ fun ConfigureEncodingParameters( .padding(horizontal = 16.dp) ) } + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(horizontal = 8.dp) + .fillMaxWidth() + ) { + Checkbox( + checked = sequentialProcessingChecked.value, + onCheckedChange = { isChecked -> + sequentialProcessingChecked.value = isChecked + onSequentialSettingCheckChanged(isChecked) + } + ) + Text(text = "Force Sequential Queue Processing", style = MaterialTheme.typography.bodySmall) + } Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier @@ -97,7 +111,7 @@ fun ConfigureEncodingParameters( } ) Text( - text = "Calculate Output Settings Automatically", + text = "Match Signal App Transcoding Settings", style = MaterialTheme.typography.bodySmall ) } @@ -145,11 +159,10 @@ fun ConfigureEncodingParameters( activeTrackColor = MaterialTheme.colorScheme.secondary, inactiveTrackColor = MaterialTheme.colorScheme.secondaryContainer ), - steps = 5, valueRange = MIN_VIDEO_MEGABITRATE..MAX_VIDEO_MEGABITRATE, modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp) ) - Text(text = "${sliderPosition.roundToInt()} Mbit/s") + Text(text = String.format("%.1f Mbit/s", sliderPosition)) Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier @@ -163,22 +176,7 @@ fun ConfigureEncodingParameters( onFastStartSettingCheckChanged(isChecked) } ) - Text(text = "Enable postprocessing for faststart", style = MaterialTheme.typography.bodySmall) - } - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .padding(vertical = 8.dp, horizontal = 8.dp) - .fillMaxWidth() - ) { - Checkbox( - checked = sequentialProcessingChecked.value, - onCheckedChange = { isChecked -> - sequentialProcessingChecked.value = isChecked - onSequentialSettingCheckChanged(isChecked) - } - ) - Text(text = "Force Sequential Queue Processing", style = MaterialTheme.typography.bodySmall) + Text(text = "Enable Mp4San Postprocessing", style = MaterialTheme.typography.bodySmall) } } LabeledButton(buttonLabel = "Transcode", onClick = buttonClickListener, modifier = Modifier.padding(vertical = 8.dp))