diff --git a/androidenhancedvideoplayer/.gitignore b/androidenhancedvideoplayer/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/androidenhancedvideoplayer/.gitignore @@ -0,0 +1 @@ +/build diff --git a/androidenhancedvideoplayer/build.gradle b/androidenhancedvideoplayer/build.gradle new file mode 100644 index 00000000..9f5d17d4 --- /dev/null +++ b/androidenhancedvideoplayer/build.gradle @@ -0,0 +1,70 @@ +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.profusion.androidenhancedvideoplayer' + compileSdk 33 + + defaultConfig { + minSdk 26 + targetSdk 33 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + buildFeatures { + compose true + } + + composeOptions { + kotlinCompilerExtensionVersion '1.3.2' + } + + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } +} + +dependencies { + implementation 'androidx.core:core-ktx:1.8.0' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' + implementation 'androidx.activity:activity-compose:1.5.1' + implementation platform('androidx.compose:compose-bom:2022.10.00') + implementation 'androidx.compose.ui:ui' + implementation 'androidx.compose.ui:ui-graphics' + implementation 'androidx.compose.ui:ui-tooling-preview' + implementation 'androidx.compose.material3:material3' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00') + androidTestImplementation 'androidx.compose.ui:ui-test-junit4' + debugImplementation 'androidx.compose.ui:ui-tooling' + debugImplementation 'androidx.compose.ui:ui-test-manifest' + + // exoplayer + implementation "androidx.media3:media3-exoplayer:$mediaVersion" + implementation "androidx.media3:media3-ui:$mediaVersion" + implementation "androidx.media3:media3-exoplayer-dash:$mediaVersion" +} diff --git a/androidenhancedvideoplayer/proguard-rules.pro b/androidenhancedvideoplayer/proguard-rules.pro new file mode 100644 index 00000000..f1b42451 --- /dev/null +++ b/androidenhancedvideoplayer/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/androidenhancedvideoplayer/src/androidTest/java/com/profusion/androidenhancedvideoplayer/ExampleInstrumentedTest.kt b/androidenhancedvideoplayer/src/androidTest/java/com/profusion/androidenhancedvideoplayer/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..44f329b3 --- /dev/null +++ b/androidenhancedvideoplayer/src/androidTest/java/com/profusion/androidenhancedvideoplayer/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.profusion.androidenhancedvideoplayer + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import junit.framework.TestCase.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.profusion.androidenhancedvideoplayer.test", appContext.packageName) + } +} diff --git a/androidenhancedvideoplayer/src/main/AndroidManifest.xml b/androidenhancedvideoplayer/src/main/AndroidManifest.xml new file mode 100644 index 00000000..8bdb7e14 --- /dev/null +++ b/androidenhancedvideoplayer/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/androidenhancedvideoplayer/src/main/java/com/profusion/androidenhancedvideoplayer/components/EnhancedVideoPlayer.kt b/androidenhancedvideoplayer/src/main/java/com/profusion/androidenhancedvideoplayer/components/EnhancedVideoPlayer.kt new file mode 100644 index 00000000..abe9ac9c --- /dev/null +++ b/androidenhancedvideoplayer/src/main/java/com/profusion/androidenhancedvideoplayer/components/EnhancedVideoPlayer.kt @@ -0,0 +1,57 @@ +package com.profusion.androidenhancedvideoplayer.components + +import android.net.Uri +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.viewinterop.AndroidView +import androidx.media3.common.MediaItem +import androidx.media3.common.Player +import androidx.media3.common.util.UnstableApi +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.ui.AspectRatioFrameLayout +import androidx.media3.ui.PlayerView + +private const val MAIN_PACKAGE_PATH_PREFIX = "android.resource://" + +@androidx.annotation.OptIn(UnstableApi::class) +@Composable +fun EnhancedVideoPlayer( + resourceId: Int, + useControls: Boolean = false, + alwaysRepeat: Boolean = true, + fullScreen: Boolean = true, + playImmediately: Boolean = true, + soundOff: Boolean = true +) { + val context = LocalContext.current + val mainPackagePath = "$MAIN_PACKAGE_PATH_PREFIX${context.packageName}/" + val exoPlayer = ExoPlayer.Builder(context).build() + LaunchedEffect(Unit) { + exoPlayer.apply { + setMediaItem( + MediaItem.fromUri( + Uri.parse(mainPackagePath + resourceId.toString()) + ) + ) + volume = if (soundOff) 0f else 1f + repeatMode = if (alwaysRepeat) Player.REPEAT_MODE_ALL else Player.REPEAT_MODE_OFF + playWhenReady = playImmediately + prepare() + } + } + + AndroidView( + factory = { factoryContext -> + PlayerView(factoryContext).apply { + player = exoPlayer + useController = useControls + resizeMode = if (fullScreen) { + AspectRatioFrameLayout.RESIZE_MODE_ZOOM + } else { + AspectRatioFrameLayout.RESIZE_MODE_FIT + } + } + } + ) +} diff --git a/androidenhancedvideoplayer/src/test/java/com/profusion/androidenhancedvideoplayer/ExampleUnitTest.kt b/androidenhancedvideoplayer/src/test/java/com/profusion/androidenhancedvideoplayer/ExampleUnitTest.kt new file mode 100644 index 00000000..7af92cd5 --- /dev/null +++ b/androidenhancedvideoplayer/src/test/java/com/profusion/androidenhancedvideoplayer/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.profusion.androidenhancedvideoplayer + +import junit.framework.TestCase.assertEquals +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +}