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

Commit 09db9e2b authored by Miranda Kephart's avatar Miranda Kephart
Browse files

Persist screenrecord show taps setting across reboot

Screen recording allows users to turn on the 'show taps' setting for the
duration of the recording, and then restores the original setting.
However, if the phone is rebooted during recording, the process is never
cleaned up and the 'show taps' setting is never reset. This change
stores the original setting and whether it should be updated when a
recording is started, and adds a CoreStartable to check that setting and
update the 'show taps' setting if necessary to restore the pre-recording
state.

Bug: 431753924
Test: manual
Flag: com.android.systemui.restore_show_taps_setting
Change-Id: I0a66324843f6eda220450575294ffa389fd7acfb
parent 940d70b4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -725,6 +725,16 @@ flag {
    }
}

flag {
    name: "restore_show_taps_setting"
    namespace: "systemui"
    description: "Restore show taps setting even if screen recording session is interrupted"
    bug: "431753924"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "clipboard_overlay_multiuser"
    namespace: "systemui"
+15 −2
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.widget.Toast;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Flags;
import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget;
@@ -52,6 +53,7 @@ import com.android.systemui.recordissue.ScreenRecordingStartTimeStore;
import com.android.systemui.res.R;
import com.android.systemui.screenrecord.ScreenMediaRecorder.SavedRecording;
import com.android.systemui.screenrecord.ScreenMediaRecorder.ScreenMediaRecorderListener;
import com.android.systemui.screenrecord.domain.ScreenRecordingPreferenceUtil;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;

@@ -109,6 +111,9 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
    protected int mNotificationId = NOTIF_BASE_ID;
    private RecordingServiceStrings mStrings;

    private final ScreenRecordingPreferenceUtil mPreferenceUtil =
            new ScreenRecordingPreferenceUtil(this);

    @Inject
    public RecordingService(ScreenRecordUxController controller, @LongRunning Executor executor,
            @Main Handler handler, UiEventLogger uiEventLogger,
@@ -207,7 +212,11 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
                        Settings.System.SHOW_TOUCHES, 0) != 0;
                int displayId = intent.getIntExtra(EXTRA_DISPLAY_ID, Display.DEFAULT_DISPLAY);

                if (Flags.restoreShowTapsSetting()) {
                    mPreferenceUtil.updateShowTaps(mShowTaps);
                } else {
                    setTapsVisible(mShowTaps);
                }

                mRecorder = new ScreenMediaRecorder(
                        mUserContextTracker.getUserContext(),
@@ -498,7 +507,11 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
        }
        UserHandle currentUser = new UserHandle(userId);
        Log.d(getTag(), "notifying for user " + userId);
        if (Flags.restoreShowTapsSetting()) {
            mPreferenceUtil.restoreShowTapsSetting();
        } else {
            setTapsVisible(mOriginalShowTaps);
        }
        try {
            if (getRecorder() != null) {
                getRecorder().end(stopReason);
+16 −0
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@

package com.android.systemui.screenrecord

import com.android.systemui.CoreStartable
import com.android.systemui.Flags
import com.android.systemui.NoOpCoreStartable
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -50,6 +52,7 @@ import dagger.Binds
import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
import dagger.multibindings.StringKey
import java.util.concurrent.Executor
@@ -75,6 +78,19 @@ interface ScreenRecordModule {
    companion object {
        private const val SCREEN_RECORD_TILE_SPEC = "screenrecord"

        @Provides
        @IntoMap
        @ClassKey(ScreenRecordingCoreStartable::class)
        fun bindScreenRecordingCoreStartable(
            implLazy: Lazy<ScreenRecordingCoreStartable>
        ): CoreStartable {
            if (Flags.restoreShowTapsSetting()) {
                return implLazy.get()
            } else {
                return NoOpCoreStartable()
            }
        }

        @Provides
        @SysUISingleton
        fun provideScreenRecordUxController(
+32 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.screenrecord

import android.content.Context
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.screenrecord.domain.ScreenRecordingPreferenceUtil
import javax.inject.Inject

@SysUISingleton
class ScreenRecordingCoreStartable @Inject constructor(context: Context) : CoreStartable {
    private val preferenceUtil = ScreenRecordingPreferenceUtil(context)

    override fun start() {
        preferenceUtil.maybeRestoreShowTapsSetting()
    }
}
+69 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.screenrecord.domain

import android.app.Service.MODE_PRIVATE
import android.content.Context
import android.content.SharedPreferences
import android.provider.Settings
import androidx.core.content.edit

class ScreenRecordingPreferenceUtil(private val context: Context) {
    fun updateShowTaps(whileRecording: Boolean) {
        val originalSetting = getShowTaps()
        setShowTaps(whileRecording)
        if (whileRecording != originalSetting) {
            sharedPreference().edit {
                putBoolean(STORED_SHOW_TAPS_VALUE, originalSetting)
                putBoolean(UPDATE_SHOW_TAPS, true)
            }
        }
    }

    fun maybeRestoreShowTapsSetting() {
        if (sharedPreference().getBoolean(UPDATE_SHOW_TAPS, false)) {
            restoreShowTapsSetting()
        }
    }

    fun restoreShowTapsSetting() {
        setShowTaps(sharedPreference().getBoolean(STORED_SHOW_TAPS_VALUE, false))
        sharedPreference().edit { putBoolean(UPDATE_SHOW_TAPS, false) }
    }

    private fun setShowTaps(isOn: Boolean) {
        Settings.System.putInt(
            context.contentResolver,
            Settings.System.SHOW_TOUCHES,
            if (isOn) 1 else 0,
        )
    }

    private fun getShowTaps(): Boolean {
        return Settings.System.getInt(context.contentResolver, Settings.System.SHOW_TOUCHES, 0) != 0
    }

    private fun sharedPreference(): SharedPreferences {
        return context.getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE)
    }

    companion object {
        const val SHARED_PREFERENCES_NAME = "com.android.systemui.screenrecord"
        const val STORED_SHOW_TAPS_VALUE = "stored_show_taps_value"
        const val UPDATE_SHOW_TAPS = "update_show_taps"
    }
}
Loading