Skip to content

Commit

Permalink
Add app initializer. set foreground notification (WIP).
Browse files Browse the repository at this point in the history
The app works as it used to, but the expected notification does not show up yet.
  • Loading branch information
atsushieno committed Apr 20, 2024
1 parent eb8e6b0 commit e24c52a
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 29 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ dependencies {
implementation("androidx.compose.material3:material3")
implementation(libs.androidx.navigation.compose)
implementation(project(":cipackageinstaller"))
implementation(libs.androidx.startup.runtime)

testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
Expand Down
9 changes: 8 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
android:name="dev.atsushieno.cipackageinstaller.SESSION_API_PACKAGE_INSTALLED" />
</intent-filter>
</activity>
</application>

<provider android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:replace="android:authorities"
tools:node="merge">
<meta-data android:name="org.androidaudioplugin.aapapkinstaller.ApkInstallerInitializer" android:value="androidx.startup" />
</provider>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.androidaudioplugin.aapapkinstaller

import android.content.Context
import androidx.startup.Initializer
import dev.atsushieno.cipackageinstaller.AppModelFactory
import dev.atsushieno.cipackageinstaller.ApplicationModel

class ApkInstallerInitializer : Initializer<Any> {
override fun create(context: Context) {
AppModelFactory.create = {
object : ApplicationModel() {
// They are specific to my app.
// Replace them with your own if you want to reuse cipackageinstaller package as a library.
override val LOG_TAG = "AAPAPKInstaller"
override val installerSessionReferrer =
"/~https://github.com/atsushieno/android-ci-package-installer"
}
}
}

override fun dependencies(): MutableList<Class<out Initializer<*>>> = mutableListOf()
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,4 @@ class MainActivity : CIPackageInstallerActivity() {
return context.packageManager.queryIntentServices(intent, 0).map { it.serviceInfo.packageName }
.distinct()
}

init {
AppModelFactory.create = { object: ApplicationModel() {
// They are specific to my app.
// Replace them with your own if you want to reuse cipackageinstaller package as a library.
override val LOG_TAG = "AAPAPKInstaller"
override val installerSessionReferrer = "/~https://github.com/atsushieno/android-ci-package-installer"
} }
}
}
10 changes: 9 additions & 1 deletion cipackageinstaller/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>

<application>

Expand All @@ -21,5 +23,11 @@

<receiver android:name=".PackageInstallerReceiver" android:exported="false" />
<receiver android:name=".PreapprovalReceiver" android:exported="false" />

<!-- https://stackoverflow.com/questions/76949759/foregroundservicetype-0x00000001-is-not-a-subset-of-foregroundservicetype-attrib -->
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
tools:node="merge" />
</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ abstract class ApplicationModel {
// Process permissions and then download and launch pending installation intent
// (that may involve user interaction).
fun performDownloadAndInstallation(context: Context, download: ApplicationArtifact) {
val request = OneTimeWorkRequestBuilder<InstallWorker>()
val request = OneTimeWorkRequestBuilder<DownloadAndInstallWorker>()
.setInputData(workDataOf(
InstallWorker.INPUT_DATA_ARTIFACT_TYPE to download.articactInfoType,
InstallWorker.INPUT_DATA_DOWNLOAD to download.serializeToString()))
DownloadAndInstallWorker.INPUT_DATA_ARTIFACT_TYPE to download.articactInfoType,
DownloadAndInstallWorker.INPUT_DATA_DOWNLOAD to download.serializeToString()))
.build()
WorkManager.getInstance(context).enqueue(request)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import androidx.work.Worker
import androidx.work.WorkerParameters
import java.io.FileInputStream

class InstallWorker(context: Context, parameters: WorkerParameters)
class DownloadAndInstallWorker(context: Context, parameters: WorkerParameters)
: Worker(context, parameters) {
companion object {
const val WORK_NAME = "InstallWorker"
const val WORK_NAME = "CIPackageInstallWorker"
const val INPUT_DATA_ARTIFACT_TYPE = "artifactType"
const val INPUT_DATA_DOWNLOAD = "download"
private const val PENDING_INTENT_REQUEST_CODE = 1
Expand Down Expand Up @@ -71,6 +71,8 @@ class InstallWorker(context: Context, parameters: WorkerParameters)
}

Log.d(LOG_TAG, "start downloading ${repo.info.appLabel} ...")

setForegroundAsync(DownloadStatusNotificationManager.createForegroundInfo(context))
val file = download.downloadApp()
Log.d(LOG_TAG, "completed downloading ${repo.info.appLabel}")
val outStream = session.openWrite(file.name, 0, file.length())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dev.atsushieno.cipackageinstaller
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.content.pm.ShortcutInfo
import android.os.Build
import androidx.core.app.NotificationChannelCompat
Expand All @@ -12,16 +13,15 @@ import androidx.work.ForegroundInfo
import dev.atsushieno.cipackageinstaller.ui.view.CIPackageInstallerActivity
import kotlin.random.Random

private const val bubbleRequestCode = 0 // FIXME: manage them
private const val bubbleShortLabel = "FIXME-shortLabel"
private const val mainRequestCode = 1 // FIXME: manage them
private const val category = "FIXME-com.example.category.IMG_SHARE_TARGET"
private const val CHANNEL_ID = "FIXME-CHANNEL_ID"
private val notificationId = Random.nextInt() // FIXME: manage them
object DownloadStatusNotificationManager {
private const val bubbleRequestCode = 0 // FIXME: manage them
private const val bubbleShortLabel = "FIXME-shortLabel"
private const val mainRequestCode = 1 // FIXME: manage them
private const val category = "FIXME-com.example.category.IMG_SHARE_TARGET"
private val notificationId = Random.nextInt() // FIXME: manage them
val shortcutId = "FIXME-shortcutId"

class DownloadStatusNotificationManager(private val context: Context) {

fun createForegroundInfo(): ForegroundInfo {
fun createForegroundInfo(context: Context): ForegroundInfo {
val notificationChannelId = javaClass.name

val channel = NotificationChannelCompat.Builder(
Expand All @@ -38,7 +38,6 @@ class DownloadStatusNotificationManager(private val context: Context) {
PendingIntent.getActivity(context, bubbleRequestCode, target, PendingIntent.FLAG_IMMUTABLE)

// Create a sharing shortcut.
val shortcutId = "FIXME-shortcutId"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
val shortcutBuilder = ShortcutInfo.Builder(context, shortcutId)
.setCategories(setOf(category))
Expand All @@ -59,13 +58,18 @@ class DownloadStatusNotificationManager(private val context: Context) {
.build()

// Create a notification, referencing the sharing shortcut.
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
//.setSmallIcon(smallIcon)
val builder = NotificationCompat.Builder(context, notificationChannelId)
.setBubbleMetadata(bubbleData)
.setShortcutId(shortcutId)
.setOnlyAlertOnce(true)
.setContentInfo("TEST")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
builder.setSmallIcon(CIPackageInstallerActivity.notificationIcon)
val notification = builder.build()

return ForegroundInfo(notificationId, notification)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
ForegroundInfo(notificationId, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
else
ForegroundInfo(notificationId, notification)
}
}
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ composeCompilerPlugin = "1.5.12"
workRuntimeKtx = "2.9.0"
accompanist-permissions = "0.32.0"
lifecycleService = "2.7.0"
startupRuntime = "1.1.1"


[libraries]
Expand Down Expand Up @@ -48,6 +49,7 @@ junit = { module = "junit:junit", version.ref = "junit" }
ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest" }
ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
androidx-lifecycle-service = { group = "androidx.lifecycle", name = "lifecycle-service", version.ref = "lifecycleService" }
androidx-startup-runtime = { group = "androidx.startup", name = "startup-runtime", version.ref = "startupRuntime" }

[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
Expand Down

0 comments on commit e24c52a

Please sign in to comment.