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