1 /* 2 * Copyright (C) 2023 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.media 18 19 import android.content.Context 20 import android.media.projection.IMediaProjection 21 import android.media.projection.IMediaProjectionManager 22 import android.media.projection.MediaProjectionManager 23 import android.media.projection.ReviewGrantedConsentResult 24 import android.os.RemoteException 25 import android.os.ServiceManager 26 import android.util.Log 27 28 /** 29 * Helper class that handles the media projection service related actions. It simplifies invoking 30 * the MediaProjectionManagerService and updating the permission consent. 31 */ 32 class MediaProjectionServiceHelper { 33 companion object { 34 private const val TAG = "MediaProjectionServiceHelper" 35 private val service = 36 IMediaProjectionManager.Stub.asInterface( 37 ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE) 38 ) 39 40 @JvmStatic 41 @Throws(RemoteException::class) 42 fun hasProjectionPermission(uid: Int, packageName: String) = 43 service.hasProjectionPermission(uid, packageName) 44 45 @JvmStatic 46 @Throws(RemoteException::class) 47 fun createOrReuseProjection( 48 uid: Int, 49 packageName: String, 50 reviewGrantedConsentRequired: Boolean 51 ): IMediaProjection { 52 val existingProjection = 53 if (reviewGrantedConsentRequired) service.getProjection(uid, packageName) else null 54 return existingProjection 55 ?: service.createProjection( 56 uid, 57 packageName, 58 MediaProjectionManager.TYPE_SCREEN_CAPTURE, 59 false /* permanentGrant */ 60 ) 61 } 62 63 /** 64 * This method is called when a host app reuses the consent token. If the token is being 65 * used more than once, ask the user to review their consent and send the reviewed result. 66 * 67 * @param consentResult consent result to update 68 * @param reviewGrantedConsentRequired if user must review already-granted consent that the 69 * host app is attempting to reuse 70 * @param projection projection token associated with the consent result, or null if the 71 * result is for cancelling. 72 */ 73 @JvmStatic 74 fun setReviewedConsentIfNeeded( 75 @ReviewGrantedConsentResult consentResult: Int, 76 reviewGrantedConsentRequired: Boolean, 77 projection: IMediaProjection? 78 ) { 79 // Only send the result to the server, when the user needed to review the re-used 80 // consent token. 81 if ( 82 reviewGrantedConsentRequired && consentResult != ReviewGrantedConsentResult.UNKNOWN 83 ) { 84 try { 85 service.setUserReviewGrantedConsentResult(consentResult, projection) 86 } catch (e: RemoteException) { 87 // If we are unable to pass back the result, capture continues with blank frames 88 Log.e(TAG, "Unable to set required consent result for token re-use", e) 89 } 90 } 91 } 92 } 93 } 94