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

Commit 6ba5e1e1 authored by Stefan Andonian's avatar Stefan Andonian
Browse files

[Record Issue QS Tile] Save Start Time and output for go/winscope integration

This file is only going to be outputted when both a screen recording and
winscope traces are present. Otherwise the metadata is not useful.
Includes unit tests.

Bug: 372973430
Test: Verified that this file is outputted locally. Looked at the file
and verified that the correct JSON was present: https://drive.google.com/file/d/10HFrtPKabufsXKN-ElF_iBTsSbteDbia/view?usp=sharing
Flag: EXEMPT small change with unit tests.

Change-Id: Id02611a76fb9b36de997c6a29fa0d1ccb2e1db42
parent 08972cce
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ class IssueRecordingServiceSessionTest : SysuiTestCase() {
    private val iActivityManager = mock<IActivityManager>()
    private val notificationManager = mock<NotificationManager>()
    private val panelInteractor = mock<PanelInteractor>()
    private val screenRecordingStartTimeStore = mock<ScreenRecordingStartTimeStore>()

    private lateinit var underTest: IssueRecordingServiceSession

@@ -76,6 +77,7 @@ class IssueRecordingServiceSessionTest : SysuiTestCase() {
                iActivityManager,
                notificationManager,
                userContextProvider,
                screenRecordingStartTimeStore,
            )
    }

@@ -90,7 +92,7 @@ class IssueRecordingServiceSessionTest : SysuiTestCase() {

    @Test
    fun stopsTracing_afterReceivingStopTracingCommand() {
        underTest.stop(mContext.contentResolver)
        underTest.stop()
        bgExecutor.runAllReady()

        Truth.assertThat(issueRecordingState.isRecording).isFalse()
@@ -124,7 +126,7 @@ class IssueRecordingServiceSessionTest : SysuiTestCase() {
        underTest.share(0, uri)
        bgExecutor.runAllReady()

        verify(traceurConnection).shareTraces(uri)
        verify(traceurConnection).shareTraces(any())
    }

    @Test
+57 −0
Original line number Diff line number Diff line
/*
 * 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.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testCase
import com.android.systemui.settings.UserTracker
import com.android.systemui.settings.userTracker
import com.google.common.truth.Truth
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.MockitoAnnotations

@SmallTest
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class ScreenRecordingStartTimeStoreTest : SysuiTestCase() {
    private val userTracker: UserTracker = Kosmos().also { it.testCase = this }.userTracker

    private lateinit var underTest: ScreenRecordingStartTimeStore

    @Before
    fun setup() {
        MockitoAnnotations.initMocks(this)
        underTest = ScreenRecordingStartTimeStore(userTracker)
    }

    @Test
    fun markStartTime_correctlyStoresValues_inSharedPreferences() {
        underTest.markStartTime()

        val startTimeMetadata = underTest.userIdToScreenRecordingStartTime.get(userTracker.userId)
        Truth.assertThat(startTimeMetadata).isNotNull()
        Truth.assertThat(startTimeMetadata!!.getLong(ELAPSED_REAL_TIME_NANOS_KEY)).isNotNull()
        Truth.assertThat(startTimeMetadata.getLong(REAL_TO_ELAPSED_TIME_OFFSET_NANOS_KEY))
            .isNotNull()
    }
}
+8 −4
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.recordissue.ScreenRecordingStartTimeStore;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -95,6 +96,8 @@ public class RecordingServiceTest extends SysuiTestCase {
    private SysuiStatusBarStateController mStatusBarStateController;
    @Mock
    private ActivityStarter mActivityStarter;
    @Mock
    private ScreenRecordingStartTimeStore mScreenRecordingStartTimeStore;

    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";

@@ -108,9 +111,10 @@ public class RecordingServiceTest extends SysuiTestCase {
                RecordingController controller, Executor executor,
                Handler handler, UiEventLogger uiEventLogger,
                NotificationManager notificationManager,
                UserContextProvider userContextTracker, KeyguardDismissUtil keyguardDismissUtil) {
            super(controller, executor, handler,
                    uiEventLogger, notificationManager, userContextTracker, keyguardDismissUtil);
                UserContextProvider userContextTracker, KeyguardDismissUtil keyguardDismissUtil,
                ScreenRecordingStartTimeStore screenRecordingStartTimeStore) {
            super(controller, executor, handler, uiEventLogger, notificationManager,
                    userContextTracker, keyguardDismissUtil, screenRecordingStartTimeStore);
            attachBaseContext(mContext);
        }
    }
@@ -120,7 +124,7 @@ public class RecordingServiceTest extends SysuiTestCase {
        MockitoAnnotations.initMocks(this);
        mRecordingService = Mockito.spy(new RecordingServiceTestable(mController, mExecutor,
                mHandler, mUiEventLogger, mNotificationManager,
                mUserContextTracker, mKeyguardDismissUtil));
                mUserContextTracker, mKeyguardDismissUtil, mScreenRecordingStartTimeStore));

        // Return actual context info
        doReturn(mContext).when(mRecordingService).getApplicationContext();
+9 −6
Original line number Diff line number Diff line
@@ -24,11 +24,9 @@ import android.content.res.Resources
import android.net.Uri
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.util.Log
import com.android.internal.logging.UiEventLogger
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.LongRunning
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
@@ -39,6 +37,7 @@ import com.android.systemui.screenrecord.RecordingServiceStrings
import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.traceur.MessageConstants.INTENT_EXTRA_TRACE_TYPE
import com.android.traceur.PresetTraceConfigs
import com.android.traceur.TraceConfig
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -47,7 +46,6 @@ class IssueRecordingService
@Inject
constructor(
    controller: RecordingController,
    @Background private val bgLooper: Looper,
    @LongRunning private val bgExecutor: Executor,
    @Main handler: Handler,
    uiEventLogger: UiEventLogger,
@@ -59,6 +57,7 @@ constructor(
    private val issueRecordingState: IssueRecordingState,
    traceurConnectionProvider: TraceurConnection.Provider,
    iActivityManager: IActivityManager,
    screenRecordingStartTimeStore: ScreenRecordingStartTimeStore,
) :
    RecordingService(
        controller,
@@ -68,6 +67,7 @@ constructor(
        notificationManager,
        userContextProvider,
        keyguardDismissUtil,
        screenRecordingStartTimeStore,
    ) {

    private val traceurConnection: TraceurConnection = traceurConnectionProvider.create()
@@ -82,6 +82,7 @@ constructor(
            iActivityManager,
            notificationManager,
            userContextProvider,
            screenRecordingStartTimeStore,
        )

    /**
@@ -111,21 +112,23 @@ constructor(
        Log.d(getTag(), "handling action: ${intent?.action}")
        when (intent?.action) {
            ACTION_START -> {
                session.start()
                val screenRecord = intent.getBooleanExtra(EXTRA_SCREEN_RECORD, false)
                with(session) {
                    traceConfig =
                        intent.getParcelableExtra(INTENT_EXTRA_TRACE_TYPE, TraceConfig::class.java)
                            ?: PresetTraceConfigs.getDefaultConfig()
                    takeBugReport = intent.getBooleanExtra(EXTRA_BUG_REPORT, false)
                    this.screenRecord = screenRecord
                    start()
                }
                if (!intent.getBooleanExtra(EXTRA_SCREEN_RECORD, false)) {
                if (!screenRecord) {
                    // If we don't want to record the screen, the ACTION_SHOW_START_NOTIF action
                    // will circumvent the RecordingService's screen recording start code.
                    return super.onStartCommand(Intent(ACTION_SHOW_START_NOTIF), flags, startId)
                }
            }
            ACTION_STOP,
            ACTION_STOP_NOTIF -> session.stop(contentResolver)
            ACTION_STOP_NOTIF -> session.stop()
            ACTION_SHARE -> {
                session.share(
                    intent.getIntExtra(EXTRA_NOTIFICATION_ID, mNotificationId),
+16 −5
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.systemui.recordissue

import android.app.IActivityManager
import android.app.NotificationManager
import android.content.ContentResolver
import android.net.Uri
import android.os.UserHandle
import android.provider.Settings
@@ -47,19 +46,25 @@ class IssueRecordingServiceSession(
    private val iActivityManager: IActivityManager,
    private val notificationManager: NotificationManager,
    private val userContextProvider: UserContextProvider,
    private val startTimeStore: ScreenRecordingStartTimeStore,
) {
    var takeBugReport = false
    var traceConfig = PresetTraceConfigs.getDefaultConfig()
    var screenRecord = false

    fun start() {
        bgExecutor.execute { traceurConnection.startTracing(traceConfig) }
        issueRecordingState.isRecording = true
    }

    fun stop(contentResolver: ContentResolver) {
    fun stop() {
        bgExecutor.execute {
            if (traceConfig.longTrace) {
                Settings.Global.putInt(contentResolver, NOTIFY_SESSION_ENDED_SETTING, DISABLED)
                Settings.Global.putInt(
                    userContextProvider.userContext.contentResolver,
                    NOTIFY_SESSION_ENDED_SETTING,
                    DISABLED,
                )
            }
            traceurConnection.stopTracing()
        }
@@ -73,11 +78,17 @@ class IssueRecordingServiceSession(
                notificationId,
                UserHandle(userContextProvider.userContext.userId),
            )

            val screenRecordingUris: List<Uri> =
                mutableListOf<Uri>().apply {
                    screenRecording?.let { add(it) }
                    if (traceConfig.winscope && screenRecord) {
                        startTimeStore.getFileUri(userContextProvider.userContext)?.let { add(it) }
                    }
                }
            if (takeBugReport) {
                iActivityManager.requestBugReportWithExtraAttachment(screenRecording)
            } else {
                traceurConnection.shareTraces(screenRecording)
                traceurConnection.shareTraces(screenRecordingUris)
            }
        }

Loading