Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 574233bc authored by Guillaume Jacquart's avatar Guillaume Jacquart
Browse files

test:4025: Add installapp-lib demo app

parent 66fb3596
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -145,6 +145,8 @@ telemetry = { module = "foundation.e.lib:telemetry", version.ref = "telemetry" }
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
truth = { module = "com.google.truth:truth", version.ref = "truth" }
viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "viewpager2" }
ui = { group = "androidx.compose.ui", name = "ui" }
ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" }
work-testing = { group = "androidx.work", name = "work-testing", version.ref = "workTesting" }

+1 −0
Original line number Diff line number Diff line
/build
 No newline at end of file
+63 −0
Original line number Diff line number Diff line
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.compose.compiler)
}

android {
    namespace = "foundation.e.apps.installapp.demo"
    compileSdk = libs.versions.compileSdk.get().toInt()

    defaultConfig {
        applicationId = "foundation.e.apps.installapp.demo"
        minSdk = libs.versions.minSdk.get().toInt()
        targetSdk = libs.versions.targetSdk.get().toInt()
        versionCode = 1
        versionName = "1.0"
    }

    signingConfigs {
        create("platformConfig") {
            storeFile = file("../../app/keystore/platform.jks")
            storePassword = "platform"
            keyAlias = "platform"
            keyPassword = "platform"
        }
    }

    buildTypes {
        debug {
            signingConfig = signingConfigs.get("platformConfig")
        }

        release {
            isMinifyEnabled = false
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.toVersion(libs.versions.jvmTarget.get())
        targetCompatibility = JavaVersion.toVersion(libs.versions.jvmTarget.get())
    }
    kotlinOptions {
        jvmTarget = libs.versions.jvmTarget.get()
    }
    buildFeatures {
        compose = true
    }
}

dependencies {
    implementation(project(":install-app-lib"))
//    implementation("foundation.e.apps:install-app-lib:1.0.0")

    implementation(libs.core.ktx)
    implementation(libs.lifecycle.runtime.ktx)
    implementation(libs.activity.compose)
    implementation(platform(libs.compose.bom))
    implementation(libs.ui)
    implementation(libs.ui.graphics)
    implementation(libs.compose.ui.tooling.preview)
    implementation(libs.compose.material3)
    debugImplementation(libs.compose.ui.tooling)
    debugImplementation(libs.compose.ui.test.manifest)
}
+19 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="foundation.e.apps.permission.BIND_INSTALL_SERVICE"/>
    <application
        android:allowBackup="true"
        android:label="InstallAppDemo"
        android:supportsRtl="true"
        android:icon="@drawable/app_icon">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
+162 −0
Original line number Diff line number Diff line
package foundation.e.apps.installapp.demo

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope
import foundation.e.apps.installapp.AppInstaller
import foundation.e.apps.installapp.AppLoungeConfiguration
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
    private val progress = MutableStateFlow<String>("Not-connected")
    private val installStatus = MutableStateFlow<String?>(null)
    private val appLoungeConfigurationFlow = MutableStateFlow<AppLoungeConfiguration?>(null)
    private var installJob: Job? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                InstallAppScreen(
                    modifier = Modifier.padding(innerPadding),
                    appLoungeConfigurationFlow,
                    progress,
                    installStatus,
                    ::installApp,
                    ::stopInstallApp
                )
            }
        }

        getAppLoungeConfiguration()
    }

    private fun installApp(packageName: String) {
        installStatus.value = null
        val appInstaller = AppInstaller(this)

        installJob = lifecycleScope.launch {
            installStatus.value = appInstaller.installByPackageName(packageName, {
                progress.value = it.name
            }).name
        }
    }

    private fun stopInstallApp() {
        installJob?.cancel()
    }

    private fun getAppLoungeConfiguration() {
        val appInstaller = AppInstaller(this)
        lifecycleScope.launch {
            appLoungeConfigurationFlow.value = appInstaller.getAppLoungeConfiguration()
        }
    }
}

@Composable()
fun InstallAppScreen(
    modifier: Modifier,
    appLoungeConfigurationFlow: Flow<AppLoungeConfiguration?>,
    statusFlow: Flow<String>,
    installStatusFlow: Flow<String?>,
    installApp: (String) -> Unit,
    stopInstallApp: () -> Unit
) {

    var packageName by remember { mutableStateOf("") }
    val status by statusFlow.collectAsState("not connected")
    val installStatus by installStatusFlow.collectAsState(null)
    val appLoungeConfiguration by appLoungeConfigurationFlow.collectAsState(null)

    Column(
        modifier = modifier
            .fillMaxWidth()
            .padding(16.dp),
        verticalArrangement = spacedBy(8.dp)
    ) {
        Text("AppLounge configuration")
        appLoungeConfiguration?.let {
            Text("GPlayAccountType:")
            Text(
                it.gPlayAccountType.name,
                Modifier.layoutId("GPlayAccountType")
                )
            Text("SearchableSources:")
            Text(
                it.searchableSources.joinToString("-"),
                Modifier.layoutId("SearchableSources"),
            )
        }

        TextField(
            value = packageName,
            onValueChange = { packageName = it },
            label = { Text(text = "Package name") },
            modifier = Modifier.fillMaxWidth()
        )

        Button(
            onClick = { installApp(packageName) },
            modifier = Modifier.fillMaxWidth().padding(top = 12.dp)
        ) {
            Text("Install")
        }

        Button(
            onClick = {
                stopInstallApp()
            },
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 12.dp)
        ) {
            Text("STOP")
        }

        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 12.dp)
        ) {
            Text("Status: ")
            Text(status, Modifier.layoutId("status"))
        }
        installStatus?.let {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 12.dp)
            ) {
                Text("Install status: ")
                Text(it, Modifier.layoutId("InstallStatus"))
            }
        }
    }
}
Loading