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