1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.recordissue 18 19 import android.content.Context 20 import android.net.Uri 21 import android.os.SystemClock 22 import android.util.Log 23 import android.util.SparseArray 24 import androidx.annotation.VisibleForTesting 25 import androidx.core.content.FileProvider 26 import com.android.systemui.dagger.SysUISingleton 27 import com.android.systemui.settings.UserTracker 28 import java.io.File 29 import java.util.concurrent.TimeUnit 30 import javax.inject.Inject 31 import org.json.JSONObject 32 33 private const val TAG = "ScreenRecordingStartTimeStore" 34 @VisibleForTesting const val REAL_TO_ELAPSED_TIME_OFFSET_NANOS_KEY = "realToElapsedTimeOffsetNanos" 35 @VisibleForTesting const val ELAPSED_REAL_TIME_NANOS_KEY = "elapsedRealTimeNanos" 36 private const val RECORDING_METADATA_FILE_SUFFIX = "screen_recording_metadata.json" 37 private const val AUTHORITY = "com.android.systemui.fileprovider" 38 39 @SysUISingleton 40 class ScreenRecordingStartTimeStore @Inject constructor(private val userTracker: UserTracker) { 41 @VisibleForTesting val userIdToScreenRecordingStartTime = SparseArray<JSONObject>() 42 markStartTimenull43 fun markStartTime() { 44 val elapsedRealTimeNano = SystemClock.elapsedRealtimeNanos() 45 val realToElapsedTimeOffsetNano = 46 TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis()) - 47 SystemClock.elapsedRealtimeNanos() 48 val startTimeMetadata = 49 JSONObject() 50 .put(ELAPSED_REAL_TIME_NANOS_KEY, elapsedRealTimeNano) 51 .put(REAL_TO_ELAPSED_TIME_OFFSET_NANOS_KEY, realToElapsedTimeOffsetNano) 52 userIdToScreenRecordingStartTime.put(userTracker.userId, startTimeMetadata) 53 } 54 55 /** 56 * Outputs start time metadata as Json to a file that can then be shared. Returns the Uri or 57 * null if the file system is not usable and the start time meta data is available. Uses 58 * com.android.systemui.fileprovider's authority. 59 * 60 * Because this file is not uniquely named, it doesn't need to be cleaned up. Every time it is 61 * outputted, it will overwrite the last file's contents. This is a feature, not a bug. 62 */ getFileUrinull63 fun getFileUri(context: Context): Uri? { 64 val dir = context.externalCacheDir?.apply { mkdirs() } ?: return null 65 try { 66 val outFile = 67 File(dir, RECORDING_METADATA_FILE_SUFFIX).apply { 68 userIdToScreenRecordingStartTime.get(userTracker.userId)?.let { 69 writeText(it.toString()) 70 } ?: return null 71 } 72 return FileProvider.getUriForFile(context, AUTHORITY, outFile) 73 } catch (e: Exception) { 74 Log.e(TAG, "failed to get screen recording start time metadata via file uri", e) 75 return null 76 } 77 } 78 } 79