1 /* 2 * Copyright (C) 2014 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 android.media.projection; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemService; 22 import android.app.Activity; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.media.projection.IMediaProjection; 26 import android.os.Handler; 27 import android.os.IBinder; 28 import android.os.RemoteException; 29 import android.os.ServiceManager; 30 import android.util.ArrayMap; 31 import android.util.Log; 32 33 import java.util.Map; 34 35 /** 36 * Manages the retrieval of certain types of {@link MediaProjection} tokens. 37 */ 38 @SystemService(Context.MEDIA_PROJECTION_SERVICE) 39 public final class MediaProjectionManager { 40 private static final String TAG = "MediaProjectionManager"; 41 /** @hide */ 42 public static final String EXTRA_APP_TOKEN = "android.media.projection.extra.EXTRA_APP_TOKEN"; 43 /** @hide */ 44 public static final String EXTRA_MEDIA_PROJECTION = 45 "android.media.projection.extra.EXTRA_MEDIA_PROJECTION"; 46 47 /** @hide */ 48 public static final int TYPE_SCREEN_CAPTURE = 0; 49 /** @hide */ 50 public static final int TYPE_MIRRORING = 1; 51 /** @hide */ 52 public static final int TYPE_PRESENTATION = 2; 53 54 private Context mContext; 55 private Map<Callback, CallbackDelegate> mCallbacks; 56 private IMediaProjectionManager mService; 57 58 /** @hide */ MediaProjectionManager(Context context)59 public MediaProjectionManager(Context context) { 60 mContext = context; 61 IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE); 62 mService = IMediaProjectionManager.Stub.asInterface(b); 63 mCallbacks = new ArrayMap<>(); 64 } 65 66 /** 67 * Returns an Intent that <b>must</b> passed to startActivityForResult() 68 * in order to start screen capture. The activity will prompt 69 * the user whether to allow screen capture. The result of this 70 * activity should be passed to getMediaProjection. 71 */ createScreenCaptureIntent()72 public Intent createScreenCaptureIntent() { 73 Intent i = new Intent(); 74 i.setClassName("com.android.systemui", 75 "com.android.systemui.media.MediaProjectionPermissionActivity"); 76 return i; 77 } 78 79 /** 80 * Retrieve the MediaProjection obtained from a succesful screen 81 * capture request. Will be null if the result from the 82 * startActivityForResult() is anything other than RESULT_OK. 83 * 84 * @param resultCode The result code from {@link android.app.Activity#onActivityResult(int, 85 * int, android.content.Intent)} 86 * @param resultData The resulting data from {@link android.app.Activity#onActivityResult(int, 87 * int, android.content.Intent)} 88 */ getMediaProjection(int resultCode, @NonNull Intent resultData)89 public MediaProjection getMediaProjection(int resultCode, @NonNull Intent resultData) { 90 if (resultCode != Activity.RESULT_OK || resultData == null) { 91 return null; 92 } 93 IBinder projection = resultData.getIBinderExtra(EXTRA_MEDIA_PROJECTION); 94 if (projection == null) { 95 return null; 96 } 97 return new MediaProjection(mContext, IMediaProjection.Stub.asInterface(projection)); 98 } 99 100 /** 101 * Get the {@link MediaProjectionInfo} for the active {@link MediaProjection}. 102 * @hide 103 */ getActiveProjectionInfo()104 public MediaProjectionInfo getActiveProjectionInfo() { 105 try { 106 return mService.getActiveProjectionInfo(); 107 } catch (RemoteException e) { 108 Log.e(TAG, "Unable to get the active projection info", e); 109 } 110 return null; 111 } 112 113 /** 114 * Stop the current projection if there is one. 115 * @hide 116 */ stopActiveProjection()117 public void stopActiveProjection() { 118 try { 119 mService.stopActiveProjection(); 120 } catch (RemoteException e) { 121 Log.e(TAG, "Unable to stop the currently active media projection", e); 122 } 123 } 124 125 /** 126 * Add a callback to monitor all of the {@link MediaProjection}s activity. 127 * Not for use by regular applications, must have the MANAGE_MEDIA_PROJECTION permission. 128 * @hide 129 */ addCallback(@onNull Callback callback, @Nullable Handler handler)130 public void addCallback(@NonNull Callback callback, @Nullable Handler handler) { 131 if (callback == null) { 132 throw new IllegalArgumentException("callback must not be null"); 133 } 134 CallbackDelegate delegate = new CallbackDelegate(callback, handler); 135 mCallbacks.put(callback, delegate); 136 try { 137 mService.addCallback(delegate); 138 } catch (RemoteException e) { 139 Log.e(TAG, "Unable to add callbacks to MediaProjection service", e); 140 } 141 } 142 143 /** 144 * Remove a MediaProjection monitoring callback. 145 * @hide 146 */ removeCallback(@onNull Callback callback)147 public void removeCallback(@NonNull Callback callback) { 148 if (callback == null) { 149 throw new IllegalArgumentException("callback must not be null"); 150 } 151 CallbackDelegate delegate = mCallbacks.remove(callback); 152 try { 153 if (delegate != null) { 154 mService.removeCallback(delegate); 155 } 156 } catch (RemoteException e) { 157 Log.e(TAG, "Unable to add callbacks to MediaProjection service", e); 158 } 159 } 160 161 /** @hide */ 162 public static abstract class Callback { onStart(MediaProjectionInfo info)163 public abstract void onStart(MediaProjectionInfo info); onStop(MediaProjectionInfo info)164 public abstract void onStop(MediaProjectionInfo info); 165 } 166 167 /** @hide */ 168 private final static class CallbackDelegate extends IMediaProjectionWatcherCallback.Stub { 169 private Callback mCallback; 170 private Handler mHandler; 171 CallbackDelegate(Callback callback, Handler handler)172 public CallbackDelegate(Callback callback, Handler handler) { 173 mCallback = callback; 174 if (handler == null) { 175 handler = new Handler(); 176 } 177 mHandler = handler; 178 } 179 180 @Override onStart(final MediaProjectionInfo info)181 public void onStart(final MediaProjectionInfo info) { 182 mHandler.post(new Runnable() { 183 @Override 184 public void run() { 185 mCallback.onStart(info); 186 } 187 }); 188 } 189 190 @Override onStop(final MediaProjectionInfo info)191 public void onStop(final MediaProjectionInfo info) { 192 mHandler.post(new Runnable() { 193 @Override 194 public void run() { 195 mCallback.onStop(info); 196 } 197 }); 198 } 199 } 200 } 201