diff options
7 files changed, 185 insertions, 80 deletions
diff --git a/libs/bufferstreams/examples/app/Android.bp b/libs/bufferstreams/examples/app/Android.bp index d6305f895c..bb573c596c 100644 --- a/libs/bufferstreams/examples/app/Android.bp +++ b/libs/bufferstreams/examples/app/Android.bp @@ -23,6 +23,9 @@ android_app { kotlincflags: [ "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api", ], + optimize: { + proguard_flags_files: ["proguard-rules.pro"], + }, resource_dirs: ["res"], diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt index a2db9349aa..ede77938de 100644 --- a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt @@ -10,18 +10,18 @@ class BufferStreamJNI { * A native method that is implemented by the 'bufferstreamsdemoapp' native library, which is * packaged with this application. */ - external fun stringFromJNI() - external fun testBufferQueueCreation() + external fun stringFromJNI(): String; + external fun testBufferQueueCreation(); companion object { - fun companion_stringFromJNI() { + fun companion_stringFromJNI(): String { val instance = BufferStreamJNI() - instance.stringFromJNI() + return instance.stringFromJNI() } fun companion_testBufferQueueCreation() { val instance = BufferStreamJNI() - instance.testBufferQueueCreation() + return instance.testBufferQueueCreation() } } }
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt index 46ce0283b4..95e415ecd5 100644 --- a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt @@ -4,10 +4,8 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button -import androidx.compose.material3.Card import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -17,17 +15,21 @@ import androidx.compose.ui.unit.dp @Composable fun DemoScreen1(modifier: Modifier = Modifier) { Column(modifier = modifier, verticalArrangement = Arrangement.SpaceBetween) { - Card(modifier = Modifier.fillMaxWidth().weight(1f, false).padding(16.dp).height(400.dp)) { - Text("Log output", modifier = Modifier.padding(16.dp)) - } + LogOutput.getInstance().LogOutputComposable() Row(modifier = Modifier.weight(1f, false).padding(16.dp)) { Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { Button( - modifier = Modifier.fillMaxWidth(), - onClick = { BufferStreamJNI.companion_testBufferQueueCreation() } - ) { Text("Run") } - OutlinedButton(modifier = Modifier.fillMaxWidth(), onClick = {}) { Text("Clear") } + modifier = Modifier.fillMaxWidth(), + onClick = { BufferStreamJNI.companion_testBufferQueueCreation() }) { + Text("Run") + } + + OutlinedButton( + modifier = Modifier.fillMaxWidth(), + onClick = { LogOutput.getInstance().clearText() }) { + Text("Clear") + } } } } -}
\ No newline at end of file +} diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/LogOutput.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/LogOutput.kt new file mode 100644 index 0000000000..3f0926f497 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/LogOutput.kt @@ -0,0 +1,65 @@ +package com.android.graphics.bufferstreamsdemoapp + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Card +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import java.util.Collections + +/* +LogOutput centralizes logging: storing, displaying, adding, and clearing log messages with +thread safety. It is a singleton that's also accessed from C++. The private constructor will +not allow this class to be initialized, limiting it to getInstance(). + */ +class LogOutput private constructor() { + val logs = Collections.synchronizedList(mutableStateListOf<String>()) + + @Composable + fun LogOutputComposable() { + val rlogs = remember { logs } + + Card(modifier = Modifier.fillMaxWidth().padding(16.dp).height(400.dp)) { + Column( + modifier = + Modifier.padding(10.dp).size(380.dp).verticalScroll(rememberScrollState())) { + for (log in rlogs) { + Text(log, modifier = Modifier.padding(0.dp)) + } + } + } + } + + fun clearText() { + logs.clear() + } + + fun addLog(log: String) { + logs.add(log) + } + + companion object { + @Volatile private var instance: LogOutput? = null + + @JvmStatic + fun getInstance(): LogOutput { + if (instance == null) { + synchronized(this) { + if (instance == null) { + instance = LogOutput() + } + } + } + return instance!! + } + } +} diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt index f3f440482f..2ccd8d75ef 100644 --- a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt @@ -31,17 +31,19 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import com.android.graphics.bufferstreamsdemoapp.ui.theme.JetpackTheme +import java.util.* class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setContent { JetpackTheme { Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background - ) { BufferDemosApp() } + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background) { + BufferDemosApp() + } } } } @@ -67,38 +69,32 @@ fun BufferDemosApp() { val backStackEntry by navController.currentBackStackEntryAsState() // Get the name of the current screen val currentScreen = - BufferDemoScreen.findByRoute( - backStackEntry?.destination?.route ?: BufferDemoScreen.Start.route - ) + BufferDemoScreen.findByRoute( + backStackEntry?.destination?.route ?: BufferDemoScreen.Start.route) Scaffold( - topBar = { - BufferDemosAppBar( - currentScreen = currentScreen, - canNavigateBack = navController.previousBackStackEntry != null, - navigateUp = { navController.navigateUp() } - ) - } - ) { - NavHost( + topBar = { + BufferDemosAppBar( + currentScreen = currentScreen, + canNavigateBack = navController.previousBackStackEntry != null, + navigateUp = { navController.navigateUp() }) + }) { + NavHost( navController = navController, startDestination = BufferDemoScreen.Start.route, - modifier = Modifier.padding(10.dp) - ) { - composable(route = BufferDemoScreen.Start.route) { - DemoList( - onButtonClicked = { - navController.navigate(it) - }, - ) - } - composable(route = BufferDemoScreen.Demo1.route) { - DemoScreen1(modifier = Modifier.fillMaxHeight().padding(top = 100.dp)) - } - composable(route = BufferDemoScreen.Demo2.route) { DemoScreen2() } - composable(route = BufferDemoScreen.Demo3.route) { DemoScreen3() } + modifier = Modifier.padding(10.dp)) { + composable(route = BufferDemoScreen.Start.route) { + DemoList( + onButtonClicked = { navController.navigate(it) }, + ) + } + composable(route = BufferDemoScreen.Demo1.route) { + DemoScreen1(modifier = Modifier.fillMaxHeight().padding(top = 100.dp)) + } + composable(route = BufferDemoScreen.Demo2.route) { DemoScreen2() } + composable(route = BufferDemoScreen.Demo3.route) { DemoScreen3() } + } } - } } @Composable @@ -107,25 +103,25 @@ fun DemoList(onButtonClicked: (String) -> Unit) { Column(modifier = modifier, verticalArrangement = Arrangement.SpaceBetween) { Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - Spacer(modifier = Modifier.height(100.dp)) - Text(text = "Buffer Demos", style = MaterialTheme.typography.titleLarge) - Spacer(modifier = Modifier.height(8.dp)) - } + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp)) { + Spacer(modifier = Modifier.height(100.dp)) + Text(text = "Buffer Demos", style = MaterialTheme.typography.titleLarge) + Spacer(modifier = Modifier.height(8.dp)) + } Row(modifier = Modifier.weight(2f, false)) { Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - for (item in BufferDemoScreen.values()) { - if (item.route != BufferDemoScreen.Start.route) - SelectDemoButton(name = stringResource(item.title), onClick = { onButtonClicked(item.route) }) + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp)) { + for (item in BufferDemoScreen.values()) { + if (item.route != BufferDemoScreen.Start.route) + SelectDemoButton( + name = stringResource(item.title), + onClick = { onButtonClicked(item.route) }) + } } - } } } } diff --git a/libs/bufferstreams/examples/app/jni/main.cpp b/libs/bufferstreams/examples/app/jni/main.cpp index 3d3fee4c6a..550ad22ae8 100644 --- a/libs/bufferstreams/examples/app/jni/main.cpp +++ b/libs/bufferstreams/examples/app/jni/main.cpp @@ -13,25 +13,41 @@ // limitations under the License. #include <jni.h> +#include <string> #include <gui/BufferQueue.h> -extern "C" -{ - JNIEXPORT jstring JNICALL - Java_com_android_graphics_bufferstreamsdemoapp_BufferStreamJNI_stringFromJNI( - JNIEnv* env, - jobject /* this */) { - const char* hello = "Hello from C++"; - return env->NewStringUTF(hello); - } - - JNIEXPORT void JNICALL - Java_com_android_graphics_bufferstreamsdemoapp_BufferStreamJNI_testBufferQueueCreation( - JNIEnv* /* env */, - jobject /* this */) { - android::sp<android::IGraphicBufferProducer> producer; - android::sp<android::IGraphicBufferConsumer> consumer; - android::BufferQueue::createBufferQueue(&producer, &consumer); - } +void log(JNIEnv* env, std::string l) { + jclass clazz = env->FindClass("com/android/graphics/bufferstreamsdemoapp/LogOutput"); + jmethodID getInstance = env->GetStaticMethodID(clazz, "getInstance", + "()Lcom/android/graphics/bufferstreamsdemoapp/LogOutput;"); + jmethodID addLog = env->GetMethodID(clazz, "addLog", "(Ljava/lang/String;)V"); + jobject dmg = env->CallStaticObjectMethod(clazz, getInstance); + + jstring jlog = env->NewStringUTF(l.c_str()); + env->CallVoidMethod(dmg, addLog, jlog); +} + +extern "C" { + +JNIEXPORT jstring JNICALL +Java_com_android_graphics_bufferstreamsdemoapp_BufferStreamJNI_stringFromJNI(JNIEnv* env, + jobject /* this */) { + const char* hello = "Hello from C++"; + return env->NewStringUTF(hello); +} + +JNIEXPORT void JNICALL +Java_com_android_graphics_bufferstreamsdemoapp_BufferStreamJNI_testBufferQueueCreation( + JNIEnv* env, jobject /* thiz */) { + + log(env, "Calling testBufferQueueCreation."); + android::sp<android::IGraphicBufferProducer> producer; + log(env, "Created producer."); + android::sp<android::IGraphicBufferConsumer> consumer; + log(env, "Created consumer."); + android::BufferQueue::createBufferQueue(&producer, &consumer); + log(env, "Created BufferQueue successfully."); + log(env, "Done!"); +} }
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/proguard-rules.pro b/libs/bufferstreams/examples/app/proguard-rules.pro new file mode 100644 index 0000000000..7a987fc7c4 --- /dev/null +++ b/libs/bufferstreams/examples/app/proguard-rules.pro @@ -0,0 +1,23 @@ +# 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 + +-keep,allowoptimization,allowobfuscation class com.android.graphics.bufferstreamsdemoapp.** { *; } |