summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceSessionTest.kt12
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt12
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/TraceurConnectionTest.kt77
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/UserAwareConnectionTest.kt70
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceSession.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/TraceurConnection.kt145
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt189
-rw-r--r--packages/SystemUI/src/com/android/systemui/recordissue/UserAwareConnection.kt76
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt8
12 files changed, 401 insertions, 222 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceSessionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceSessionTest.kt
index 3e5dee69c85c..8e57914050d6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceSessionTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceSessionTest.kt
@@ -53,7 +53,7 @@ class IssueRecordingServiceSessionTest : SysuiTestCase() {
private val bgExecutor = kosmos.fakeExecutor
private val userContextProvider: UserContextProvider = kosmos.userTracker
private val dialogTransitionAnimator: DialogTransitionAnimator = kosmos.dialogTransitionAnimator
- private lateinit var traceurMessageSender: TraceurMessageSender
+ private lateinit var traceurConnection: TraceurConnection
private val issueRecordingState =
IssueRecordingState(kosmos.userTracker, kosmos.userFileManager)
@@ -65,13 +65,13 @@ class IssueRecordingServiceSessionTest : SysuiTestCase() {
@Before
fun setup() {
- traceurMessageSender = mock<TraceurMessageSender>()
+ traceurConnection = mock<TraceurConnection>()
underTest =
IssueRecordingServiceSession(
bgExecutor,
dialogTransitionAnimator,
panelInteractor,
- traceurMessageSender,
+ traceurConnection,
issueRecordingState,
iActivityManager,
notificationManager,
@@ -85,7 +85,7 @@ class IssueRecordingServiceSessionTest : SysuiTestCase() {
bgExecutor.runAllReady()
Truth.assertThat(issueRecordingState.isRecording).isTrue()
- verify(traceurMessageSender).startTracing(any<TraceConfig>())
+ verify(traceurConnection).startTracing(any<TraceConfig>())
}
@Test
@@ -94,7 +94,7 @@ class IssueRecordingServiceSessionTest : SysuiTestCase() {
bgExecutor.runAllReady()
Truth.assertThat(issueRecordingState.isRecording).isFalse()
- verify(traceurMessageSender).stopTracing()
+ verify(traceurConnection).stopTracing()
}
@Test
@@ -124,7 +124,7 @@ class IssueRecordingServiceSessionTest : SysuiTestCase() {
underTest.share(0, uri, mContext)
bgExecutor.runAllReady()
- verify(traceurMessageSender).shareTraces(mContext, uri)
+ verify(traceurConnection).shareTraces(mContext, uri)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
index 8d84c3e7392e..9ca8f447d374 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
@@ -78,7 +78,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() {
@Mock private lateinit var sysuiState: SysUiState
@Mock private lateinit var systemUIDialogManager: SystemUIDialogManager
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock private lateinit var traceurMessageSender: TraceurMessageSender
+ @Mock private lateinit var traceurConnection: TraceurConnection
private val systemClock = FakeSystemClock()
private val bgExecutor = FakeExecutor(systemClock)
private val mainExecutor = FakeExecutor(systemClock)
@@ -104,7 +104,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() {
systemUIDialogManager,
sysuiState,
broadcastDispatcher,
- mDialogTransitionAnimator
+ mDialogTransitionAnimator,
)
)
@@ -120,7 +120,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() {
mediaProjectionMetricsLogger,
screenCaptureDisabledDialogDelegate,
state,
- traceurMessageSender
+ traceurConnection,
) {
latch.countDown()
}
@@ -166,7 +166,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() {
verify(mediaProjectionMetricsLogger, never())
.notifyProjectionInitiated(
anyInt(),
- eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER)
+ eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER),
)
assertThat(screenRecordSwitch.isChecked).isFalse()
}
@@ -188,7 +188,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() {
verify(mediaProjectionMetricsLogger)
.notifyProjectionInitiated(
anyInt(),
- eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER)
+ eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER),
)
verify(factory, times(2)).create(any(SystemUIDialog.Delegate::class.java))
}
@@ -208,7 +208,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() {
verify(mediaProjectionMetricsLogger)
.notifyProjectionInitiated(
anyInt(),
- eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER)
+ eq(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER),
)
verify(factory, never()).create()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/TraceurConnectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/TraceurConnectionTest.kt
new file mode 100644
index 000000000000..85a8237ff955
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/TraceurConnectionTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recordissue
+
+import android.os.IBinder
+import android.os.Looper
+import android.os.Messenger
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.UserContextProvider
+import com.android.traceur.PresetTraceConfigs
+import java.util.concurrent.CountDownLatch
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class TraceurConnectionTest : SysuiTestCase() {
+
+ @Mock private lateinit var userContextProvider: UserContextProvider
+
+ private lateinit var underTest: TraceurConnection
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ whenever(userContextProvider.userContext).thenReturn(mContext)
+ underTest = TraceurConnection(userContextProvider, Looper.getMainLooper())
+ }
+
+ @Test
+ fun onBoundRunnables_areRun_whenServiceIsBound() {
+ val latch = CountDownLatch(1)
+ underTest.onBound.add { latch.countDown() }
+
+ underTest.onServiceConnected(
+ InstrumentationRegistry.getInstrumentation().componentName,
+ mock(IBinder::class.java),
+ )
+
+ latch.await()
+ }
+
+ @Test
+ fun startTracing_sendsMsg_toStartTracing() {
+ underTest.binder = mock(Messenger::class.java)
+
+ underTest.startTracing(PresetTraceConfigs.getThermalConfig())
+
+ verify(underTest.binder)!!.send(any())
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/UserAwareConnectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/UserAwareConnectionTest.kt
new file mode 100644
index 000000000000..f671bf44c42b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/UserAwareConnectionTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recordissue
+
+import android.content.Context
+import android.content.Intent
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.UserContextProvider
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class UserAwareConnectionTest : SysuiTestCase() {
+
+ @Mock private lateinit var userContextProvider: UserContextProvider
+ @Mock private lateinit var mockContext: Context
+
+ private lateinit var underTest: UserAwareConnection
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ whenever(userContextProvider.userContext).thenReturn(mockContext)
+ whenever(mockContext.bindService(any(), any(), anyInt())).thenReturn(true)
+ underTest = UserAwareConnection(userContextProvider, Intent())
+ }
+
+ @Test
+ fun doBindService_requestToBindToTheService_viaTheCorrectUserContext() {
+ underTest.doBind()
+
+ verify(userContextProvider).userContext
+ }
+
+ @Test
+ fun doBindService_DoesntRequestToBindToTheService_IfAlreadyRequested() {
+ underTest.doBind()
+ underTest.doBind()
+ underTest.doBind()
+
+ verify(userContextProvider, times(1)).userContext
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index d89e73d2c69f..c316c8626e8e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -48,7 +48,7 @@ import com.android.systemui.recordissue.IssueRecordingService.Companion.getStopI
import com.android.systemui.recordissue.IssueRecordingState
import com.android.systemui.recordissue.RecordIssueDialogDelegate
import com.android.systemui.recordissue.RecordIssueModule.Companion.TILE_SPEC
-import com.android.systemui.recordissue.TraceurMessageSender
+import com.android.systemui.recordissue.TraceurConnection
import com.android.systemui.res.R
import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.screenrecord.RecordingService
@@ -78,7 +78,7 @@ constructor(
private val dialogTransitionAnimator: DialogTransitionAnimator,
private val panelInteractor: PanelInteractor,
private val userContextProvider: UserContextProvider,
- private val traceurMessageSender: TraceurMessageSender,
+ private val traceurConnection: TraceurConnection,
@Background private val bgExecutor: Executor,
private val issueRecordingState: IssueRecordingState,
private val delegateFactory: RecordIssueDialogDelegate.Factory,
@@ -93,7 +93,7 @@ constructor(
metricsLogger,
statusBarStateController,
activityStarter,
- qsLogger
+ qsLogger,
) {
private val onRecordingChangeListener = Runnable { refreshState() }
@@ -109,7 +109,7 @@ constructor(
override fun handleDestroy() {
super.handleDestroy()
- bgExecutor.execute { traceurMessageSender.unbindFromTraceur(mContext) }
+ bgExecutor.execute { traceurConnection.doUnBind() }
}
override fun getTileLabel(): CharSequence = mContext.getString(R.string.qs_record_issue_label)
@@ -142,7 +142,7 @@ constructor(
DELAY_MS,
INTERVAL_MS,
pendingServiceIntent(getStartIntent(userContextProvider.userContext)),
- pendingServiceIntent(getStopIntent(userContextProvider.userContext))
+ pendingServiceIntent(getStopIntent(userContextProvider.userContext)),
)
private fun stopIssueRecordingService() =
@@ -154,7 +154,7 @@ constructor(
userContextProvider.userContext,
RecordingService.REQUEST_CODE,
action,
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
private fun showPrompt(expandable: Expandable?) {
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
index 4d2bc91aa52a..e804baffce05 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -50,7 +50,7 @@ constructor(
keyguardDismissUtil: KeyguardDismissUtil,
dialogTransitionAnimator: DialogTransitionAnimator,
panelInteractor: PanelInteractor,
- traceurMessageSender: TraceurMessageSender,
+ traceurConnection: TraceurConnection,
private val issueRecordingState: IssueRecordingState,
iActivityManager: IActivityManager,
) :
@@ -69,7 +69,7 @@ constructor(
bgExecutor,
dialogTransitionAnimator,
panelInteractor,
- traceurMessageSender,
+ traceurConnection,
issueRecordingState,
iActivityManager,
notificationManager,
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceSession.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceSession.kt
index e4d3e6cae502..6fc248ffa459 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceSession.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceSession.kt
@@ -42,7 +42,7 @@ class IssueRecordingServiceSession(
private val bgExecutor: Executor,
private val dialogTransitionAnimator: DialogTransitionAnimator,
private val panelInteractor: PanelInteractor,
- private val traceurMessageSender: TraceurMessageSender,
+ private val traceurConnection: TraceurConnection,
private val issueRecordingState: IssueRecordingState,
private val iActivityManager: IActivityManager,
private val notificationManager: NotificationManager,
@@ -50,7 +50,7 @@ class IssueRecordingServiceSession(
) {
fun start() {
- bgExecutor.execute { traceurMessageSender.startTracing(issueRecordingState.traceConfig) }
+ bgExecutor.execute { traceurConnection.startTracing(issueRecordingState.traceConfig) }
issueRecordingState.isRecording = true
}
@@ -59,7 +59,7 @@ class IssueRecordingServiceSession(
if (issueRecordingState.traceConfig.longTrace) {
Settings.Global.putInt(contentResolver, NOTIFY_SESSION_ENDED_SETTING, DISABLED)
}
- traceurMessageSender.stopTracing()
+ traceurConnection.stopTracing()
}
issueRecordingState.isRecording = false
}
@@ -75,7 +75,7 @@ class IssueRecordingServiceSession(
if (issueRecordingState.takeBugreport) {
iActivityManager.requestBugReportWithExtraAttachment(screenRecording)
} else {
- traceurMessageSender.shareTraces(context, screenRecording)
+ traceurConnection.shareTraces(context, screenRecording)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index ed67e64dfb76..e38fe9aafe32 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -64,7 +64,7 @@ constructor(
private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
private val screenCaptureDisabledDialogDelegate: ScreenCaptureDisabledDialogDelegate,
private val state: IssueRecordingState,
- private val traceurMessageSender: TraceurMessageSender,
+ private val traceurConnection: TraceurConnection,
@Assisted private val onStarted: Runnable,
) : SystemUIDialog.Delegate {
@@ -88,8 +88,8 @@ constructor(
setPositiveButton(R.string.qs_record_issue_start) { _, _ -> onStarted.run() }
}
bgExecutor.execute {
- traceurMessageSender.onBoundToTraceur.add { traceurMessageSender.getTags(state) }
- traceurMessageSender.bindToTraceur(dialog.context)
+ traceurConnection.onBound.add { traceurConnection.getTags(state) }
+ traceurConnection.doBind()
}
}
@@ -151,7 +151,7 @@ constructor(
mediaProjectionMetricsLogger.notifyProjectionInitiated(
userTracker.userId,
- SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER
+ SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER,
)
if (!state.hasUserApprovedScreenRecording) {
@@ -189,7 +189,7 @@ constructor(
CustomTraceSettingsDialogDelegate(
factory,
state.customTraceState,
- state.tagTitles
+ state.tagTitles,
) {
onMenuItemClickListener.onMenuItemClick(it)
}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurConnection.kt b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurConnection.kt
new file mode 100644
index 000000000000..75df49e3676f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurConnection.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recordissue
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.os.Handler
+import android.os.IBinder
+import android.os.Looper
+import android.os.Message
+import android.os.Messenger
+import android.util.Log
+import androidx.annotation.WorkerThread
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.recordissue.IssueRecordingState.Companion.TAG_TITLE_DELIMITER
+import com.android.systemui.settings.UserContextProvider
+import com.android.traceur.FileSender
+import com.android.traceur.MessageConstants
+import com.android.traceur.MessageConstants.TRACING_APP_ACTIVITY
+import com.android.traceur.MessageConstants.TRACING_APP_PACKAGE_NAME
+import com.android.traceur.TraceConfig
+import java.util.concurrent.CopyOnWriteArrayList
+import javax.inject.Inject
+
+private const val TAG = "TraceurConnection"
+
+@SysUISingleton
+class TraceurConnection
+@Inject
+constructor(userContextProvider: UserContextProvider, @Background private val bgLooper: Looper) :
+ UserAwareConnection(
+ userContextProvider,
+ Intent().setClassName(TRACING_APP_PACKAGE_NAME, TRACING_APP_ACTIVITY),
+ ) {
+
+ val onBound: MutableList<Runnable> = CopyOnWriteArrayList(mutableListOf())
+
+ override fun onServiceConnected(className: ComponentName, service: IBinder) {
+ super.onServiceConnected(className, service)
+ onBound.forEach(Runnable::run)
+ onBound.clear()
+ }
+
+ @WorkerThread
+ fun startTracing(traceType: TraceConfig) {
+ val data =
+ Bundle().apply { putParcelable(MessageConstants.INTENT_EXTRA_TRACE_TYPE, traceType) }
+ sendMessage(MessageConstants.START_WHAT, data)
+ }
+
+ @WorkerThread fun stopTracing() = sendMessage(MessageConstants.STOP_WHAT)
+
+ @WorkerThread
+ fun shareTraces(context: Context, screenRecord: Uri?) {
+ val replyHandler = Messenger(ShareFilesHandler(context, screenRecord, bgLooper))
+ sendMessage(MessageConstants.SHARE_WHAT, replyTo = replyHandler)
+ }
+
+ @WorkerThread
+ fun getTags(state: IssueRecordingState) =
+ sendMessage(MessageConstants.TAGS_WHAT, replyTo = Messenger(TagsHandler(bgLooper, state)))
+
+ @WorkerThread
+ private fun sendMessage(what: Int, data: Bundle = Bundle(), replyTo: Messenger? = null) =
+ try {
+ val msg =
+ Message.obtain().apply {
+ this.what = what
+ this.data = data
+ this.replyTo = replyTo
+ }
+ binder!!.send(msg)
+ } catch (e: Exception) {
+ Log.e(TAG, "failed to notify Traceur", e)
+ }
+}
+
+private class ShareFilesHandler(
+ private val context: Context,
+ private val screenRecord: Uri?,
+ looper: Looper,
+) : Handler(looper) {
+
+ override fun handleMessage(msg: Message) {
+ if (MessageConstants.SHARE_WHAT == msg.what) {
+ shareTraces(
+ msg.data.getParcelable(MessageConstants.EXTRA_PERFETTO, Uri::class.java),
+ msg.data.getParcelable(MessageConstants.EXTRA_WINSCOPE, Uri::class.java),
+ )
+ } else {
+ throw IllegalArgumentException("received unknown msg.what: " + msg.what)
+ }
+ }
+
+ private fun shareTraces(perfetto: Uri?, winscope: Uri?) {
+ val uris: ArrayList<Uri> =
+ ArrayList<Uri>().apply {
+ perfetto?.let { add(it) }
+ winscope?.let { add(it) }
+ screenRecord?.let { add(it) }
+ }
+ val fileSharingIntent =
+ FileSender.buildSendIntent(context, uris)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
+ context.startActivity(fileSharingIntent)
+ }
+}
+
+private class TagsHandler(looper: Looper, private val state: IssueRecordingState) :
+ Handler(looper) {
+
+ override fun handleMessage(msg: Message) {
+ if (MessageConstants.TAGS_WHAT == msg.what) {
+ val keys = msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAGS)
+ val values = msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAG_DESCRIPTIONS)
+ if (keys == null || values == null) {
+ throw IllegalArgumentException(
+ "Neither keys: $keys, nor values: $values can be null"
+ )
+ }
+ state.tagTitles =
+ keys.zip(values).map { it.first + TAG_TITLE_DELIMITER + it.second }.toSet()
+ } else {
+ throw IllegalArgumentException("received unknown msg.what: " + msg.what)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt b/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt
deleted file mode 100644
index 8bfd14a68811..000000000000
--- a/packages/SystemUI/src/com/android/systemui/recordissue/TraceurMessageSender.kt
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recordissue
-
-import android.annotation.SuppressLint
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.content.ServiceConnection
-import android.content.pm.PackageManager
-import android.net.Uri
-import android.os.Bundle
-import android.os.Handler
-import android.os.IBinder
-import android.os.Looper
-import android.os.Message
-import android.os.Messenger
-import android.util.Log
-import androidx.annotation.WorkerThread
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.recordissue.IssueRecordingState.Companion.TAG_TITLE_DELIMITER
-import com.android.traceur.FileSender
-import com.android.traceur.MessageConstants
-import com.android.traceur.TraceConfig
-import javax.inject.Inject
-
-private const val TAG = "TraceurMessageSender"
-
-@SysUISingleton
-class TraceurMessageSender @Inject constructor(@Background private val backgroundLooper: Looper) {
- private var binder: Messenger? = null
- private var isBound: Boolean = false
-
- val onBoundToTraceur = mutableListOf<Runnable>()
-
- private val traceurConnection =
- object : ServiceConnection {
- override fun onServiceConnected(className: ComponentName, service: IBinder) {
- binder = Messenger(service)
- isBound = true
- onBoundToTraceur.forEach(Runnable::run)
- onBoundToTraceur.clear()
- }
-
- override fun onServiceDisconnected(className: ComponentName) {
- binder = null
- isBound = false
- }
- }
-
- @SuppressLint("WrongConstant")
- @WorkerThread
- fun bindToTraceur(context: Context) {
- if (isBound) {
- // Binding needs to happen after the phone has been unlocked. The RecordIssueTile is
- // initialized before this happens though, so binding is placed at a later time, during
- // normal operations that can be repeated. This check avoids calling "bindService" 2x+
- return
- }
- try {
- val info =
- context.packageManager.getPackageInfo(
- MessageConstants.TRACING_APP_PACKAGE_NAME,
- PackageManager.MATCH_SYSTEM_ONLY
- )
- val intent =
- Intent().setClassName(info.packageName, MessageConstants.TRACING_APP_ACTIVITY)
- val flags =
- Context.BIND_AUTO_CREATE or
- Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE or
- Context.BIND_WAIVE_PRIORITY
- context.bindService(intent, traceurConnection, flags)
- } catch (e: Exception) {
- Log.e(TAG, "failed to bind to Traceur's service", e)
- }
- }
-
- @WorkerThread
- fun unbindFromTraceur(context: Context) {
- if (isBound) {
- context.unbindService(traceurConnection)
- }
- }
-
- @WorkerThread
- fun startTracing(traceType: TraceConfig) {
- val data =
- Bundle().apply { putParcelable(MessageConstants.INTENT_EXTRA_TRACE_TYPE, traceType) }
- notifyTraceur(MessageConstants.START_WHAT, data)
- }
-
- @WorkerThread fun stopTracing() = notifyTraceur(MessageConstants.STOP_WHAT)
-
- @WorkerThread
- fun shareTraces(context: Context, screenRecord: Uri?) {
- val replyHandler = Messenger(ShareFilesHandler(context, screenRecord, backgroundLooper))
- notifyTraceur(MessageConstants.SHARE_WHAT, replyTo = replyHandler)
- }
-
- @WorkerThread
- fun getTags(state: IssueRecordingState) {
- val replyHandler = Messenger(TagsHandler(backgroundLooper, state))
- notifyTraceur(MessageConstants.TAGS_WHAT, replyTo = replyHandler)
- }
-
- @WorkerThread
- private fun notifyTraceur(what: Int, data: Bundle = Bundle(), replyTo: Messenger? = null) {
- try {
- binder!!.send(
- Message.obtain().apply {
- this.what = what
- this.data = data
- this.replyTo = replyTo
- }
- )
- } catch (e: Exception) {
- Log.e(TAG, "failed to notify Traceur", e)
- }
- }
-
- private class ShareFilesHandler(
- private val context: Context,
- private val screenRecord: Uri?,
- looper: Looper,
- ) : Handler(looper) {
-
- override fun handleMessage(msg: Message) {
- if (MessageConstants.SHARE_WHAT == msg.what) {
- shareTraces(
- msg.data.getParcelable(MessageConstants.EXTRA_PERFETTO, Uri::class.java),
- msg.data.getParcelable(MessageConstants.EXTRA_WINSCOPE, Uri::class.java)
- )
- } else {
- throw IllegalArgumentException("received unknown msg.what: " + msg.what)
- }
- }
-
- private fun shareTraces(perfetto: Uri?, winscope: Uri?) {
- val uris: List<Uri> =
- mutableListOf<Uri>().apply {
- perfetto?.let { add(it) }
- winscope?.let { add(it) }
- screenRecord?.let { add(it) }
- }
- val fileSharingIntent =
- FileSender.buildSendIntent(context, uris)
- .addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
- )
- context.startActivity(fileSharingIntent)
- }
- }
-
- private class TagsHandler(looper: Looper, private val state: IssueRecordingState) :
- Handler(looper) {
-
- override fun handleMessage(msg: Message) {
- if (MessageConstants.TAGS_WHAT == msg.what) {
- val keys = msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAGS)
- val values =
- msg.data.getStringArrayList(MessageConstants.BUNDLE_KEY_TAG_DESCRIPTIONS)
- if (keys == null || values == null) {
- throw IllegalArgumentException(
- "Neither keys: $keys, nor values: $values can be null"
- )
- }
- state.tagTitles =
- keys.zip(values).map { it.first + TAG_TITLE_DELIMITER + it.second }.toSet()
- } else {
- throw IllegalArgumentException("received unknown msg.what: " + msg.what)
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/UserAwareConnection.kt b/packages/SystemUI/src/com/android/systemui/recordissue/UserAwareConnection.kt
new file mode 100644
index 000000000000..6aaa27dd7387
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/UserAwareConnection.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recordissue
+
+import android.annotation.SuppressLint
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.IBinder
+import android.os.Messenger
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import androidx.annotation.WorkerThread
+import com.android.systemui.settings.UserContextProvider
+
+private const val TAG = "UserAwareConnection"
+private const val BIND_FLAGS =
+ Context.BIND_AUTO_CREATE or
+ Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE or
+ Context.BIND_WAIVE_PRIORITY
+
+/** ServiceConnection class that can be used to keep an IntentService alive. */
+open class UserAwareConnection(
+ protected val userContextProvider: UserContextProvider,
+ private val intent: Intent,
+) : ServiceConnection {
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) var binder: Messenger? = null
+ private var shouldUnBind = false
+
+ override fun onServiceConnected(className: ComponentName, service: IBinder) {
+ binder = Messenger(service)
+ }
+
+ override fun onServiceDisconnected(className: ComponentName) {
+ binder = null
+ }
+
+ @SuppressLint("WrongConstant")
+ @WorkerThread
+ fun doBind() {
+ if (shouldUnBind) {
+ // Binding needs to happen after the phone has been unlocked. The RecordIssueTile is
+ // initialized before this happens though, so binding is placed at a later time, during
+ // normal operations that can be repeated. This check avoids calling "bindService" 2x+
+ return
+ }
+ try {
+ shouldUnBind = userContextProvider.userContext.bindService(intent, this, BIND_FLAGS)
+ } catch (e: Exception) {
+ Log.e(TAG, "failed to bind to the service", e)
+ }
+ }
+
+ @WorkerThread
+ fun doUnBind() {
+ if (shouldUnBind) {
+ userContextProvider.userContext.unbindService(this)
+ shouldUnBind = false
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
index ca518f9bc5d7..833cf424ef93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
@@ -33,7 +33,7 @@ import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
import com.android.systemui.recordissue.IssueRecordingState
import com.android.systemui.recordissue.RecordIssueDialogDelegate
-import com.android.systemui.recordissue.TraceurMessageSender
+import com.android.systemui.recordissue.TraceurConnection
import com.android.systemui.res.R
import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.settings.UserContextProvider
@@ -75,7 +75,7 @@ class RecordIssueTileTest : SysuiTestCase() {
@Mock private lateinit var panelInteractor: PanelInteractor
@Mock private lateinit var userContextProvider: UserContextProvider
@Mock private lateinit var issueRecordingState: IssueRecordingState
- @Mock private lateinit var traceurMessageSender: TraceurMessageSender
+ @Mock private lateinit var traceurConnection: TraceurConnection
@Mock private lateinit var delegateFactory: RecordIssueDialogDelegate.Factory
@Mock private lateinit var dialogDelegate: RecordIssueDialogDelegate
@Mock private lateinit var dialog: SystemUIDialog
@@ -107,7 +107,7 @@ class RecordIssueTileTest : SysuiTestCase() {
dialogLauncherAnimator,
panelInteractor,
userContextProvider,
- traceurMessageSender,
+ traceurConnection,
Executors.newSingleThreadExecutor(),
issueRecordingState,
delegateFactory,
@@ -169,7 +169,7 @@ class RecordIssueTileTest : SysuiTestCase() {
.executeWhenUnlocked(
isA(ActivityStarter.OnDismissAction::class.java),
eq(false),
- eq(true)
+ eq(true),
)
}
}