Skip to content

Commit 4add6fe

Browse files
authored
andr(example): Add multi-process Service to gradle-test-app (#791)
* Add multi-process Service to gradle-test-app * Add more logs * Finish actual valid Service
1 parent d3adda9 commit 4add6fe

6 files changed

Lines changed: 92 additions & 0 deletions

File tree

platform/jvm/gradle-test-app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
xmlns:tools="http://schemas.android.com/tools">
44

55
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
6+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
7+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
68

79
<application
810
android:name=".GradleTestApp"
@@ -53,6 +55,16 @@
5355
android:name="android.webkit.WebView.Multiprocess"
5456
android:value="true"/>
5557

58+
<!-- Separate process to avoid starting the application when starting this service -->
59+
<service android:name=".ui.service.SendTelemetryService"
60+
android:process=":crashReportingProcess"
61+
android:exported="false"
62+
android:foregroundServiceType="specialUse">
63+
<property
64+
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
65+
android:value="This foreground service allows users to report issues" />
66+
</service>
67+
5668
</application>
5769

5870
</manifest>

platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/data/model/Actions.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ sealed class NavigationAction : AppAction {
7676
object NavigateToDialogAndModals : NavigationAction()
7777

7878
object NavigateToStressTest : NavigationAction()
79+
80+
object InvokeService : NavigationAction()
7981
}
8082

8183
sealed class StressTestAction : AppAction {

platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/ui/compose/components/NavigationCard.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ fun NavigationCard(onAction: (AppAction) -> Unit) {
6767
onClick = { onAction(NavigationAction.NavigateToDialogAndModals) },
6868
colors = ButtonDefaults.outlinedButtonColors(contentColor = BitdriftColors.TextPrimary),
6969
) { Text(stringResource(id = R.string.navigate_to_modal_bottom_sheet), maxLines = 1, softWrap = false) }
70+
71+
OutlinedButton(
72+
onClick = { onAction(NavigationAction.InvokeService) },
73+
colors = ButtonDefaults.outlinedButtonColors(contentColor = BitdriftColors.TextPrimary),
74+
) { Text("Invoke Service", maxLines = 1, softWrap = false) }
7075
}
7176
}
7277
}

platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/ui/fragments/FirstFragment.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import androidx.compose.material3.MaterialTheme
1818
import androidx.compose.runtime.collectAsState
1919
import androidx.compose.ui.platform.ComposeView
2020
import androidx.compose.ui.platform.ViewCompositionStrategy
21+
import androidx.core.content.ContextCompat
2122
import androidx.fragment.app.Fragment
2223
import androidx.fragment.app.activityViewModels
2324
import androidx.navigation.fragment.findNavController
@@ -32,6 +33,7 @@ import io.bitdrift.gradletestapp.data.repository.NetworkTestingRepository
3233
import io.bitdrift.gradletestapp.data.repository.SdkRepository
3334
import io.bitdrift.gradletestapp.data.repository.StressTestRepository
3435
import io.bitdrift.gradletestapp.ui.compose.MainScreen
36+
import io.bitdrift.gradletestapp.ui.service.SendTelemetryService
3537
import io.bitdrift.gradletestapp.ui.viewmodel.MainViewModel
3638
import io.bitdrift.gradletestapp.ui.viewmodel.MainViewModelFactory
3739

@@ -111,6 +113,13 @@ class FirstFragment : Fragment() {
111113
findNavController().navigate(R.id.action_FirstFragment_to_StressTestFragment)
112114
}
113115

116+
is NavigationAction.InvokeService -> {
117+
ContextCompat.startForegroundService(
118+
requireContext(),
119+
SendTelemetryService.createReportIntent(requireContext()),
120+
)
121+
}
122+
114123
else -> viewModel.handleAction(action)
115124
}
116125
},
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// capture-sdk - bitdrift's client SDK
2+
// Copyright Bitdrift, Inc. All rights reserved.
3+
//
4+
// Use of this source code is governed by a source available license that can be found in the
5+
// LICENSE file or at:
6+
// https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt
7+
8+
package io.bitdrift.gradletestapp.ui.service
9+
10+
import android.app.NotificationChannel
11+
import android.app.NotificationManager
12+
import android.app.Service
13+
import android.content.Context
14+
import android.content.Intent
15+
import android.os.Build
16+
import android.os.IBinder
17+
import android.os.Process
18+
import androidx.core.app.NotificationCompat
19+
import timber.log.Timber
20+
21+
class SendTelemetryService : Service() {
22+
override fun onBind(intent: Intent?): IBinder? {
23+
Timber.i("SendTelemetryService.onBind() called on process ${Process.myPid()}, thread=${Thread.currentThread().name}")
24+
// We don't provide binding, so return null
25+
return null
26+
}
27+
28+
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
29+
Timber.i("SendTelemetryService.onStartCommand() called on process ${Process.myPid()}, thread=${Thread.currentThread().name}")
30+
31+
val channelId = "send_telemetry_channel"
32+
val notificationId = 1
33+
34+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
35+
val channel = NotificationChannel(channelId, "Send Telemetry", NotificationManager.IMPORTANCE_LOW)
36+
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
37+
manager.createNotificationChannel(channel)
38+
}
39+
40+
val notification = NotificationCompat.Builder(this, channelId)
41+
.setContentTitle("Sending Telemetry")
42+
.setContentText("Processing...")
43+
.setSmallIcon(android.R.drawable.ic_dialog_info)
44+
.build()
45+
46+
startForeground(notificationId, notification)
47+
48+
// Simulate telemetry sending work
49+
Thread.sleep(500)
50+
// Stopping the service after work is done
51+
stopSelf()
52+
53+
return START_NOT_STICKY
54+
}
55+
56+
companion object {
57+
fun createReportIntent(context: Context) : Intent {//, crash: Crash): Intent {
58+
val intent = Intent(context, SendTelemetryService::class.java)
59+
Timber.i("SendTelemetryService.createReportIntent() called on process ${Process.myPid()}, thread=${Thread.currentThread().name}")
60+
return intent
61+
}
62+
}
63+
}

platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/ui/viewmodel/MainViewModel.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class MainViewModel(
136136
is NavigationAction.NavigateToXml -> {}
137137
is NavigationAction.NavigateToDialogAndModals -> {}
138138
is NavigationAction.NavigateToStressTest -> {}
139+
is NavigationAction.InvokeService -> {}
139140
}
140141
}
141142

0 commit comments

Comments
 (0)