Home | History | Annotate | Download | only in projection
      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 */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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 {
    169         public abstract void onStart(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 
    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
    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
    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