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.annotation.SystemService;
     22 import android.app.Activity;
     23 import android.content.ComponentName;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.pm.PackageManager;
     27 import android.media.projection.IMediaProjection;
     28 import android.os.Handler;
     29 import android.os.IBinder;
     30 import android.os.RemoteException;
     31 import android.os.ServiceManager;
     32 import android.util.ArrayMap;
     33 import android.util.Log;
     34 
     35 import java.util.Map;
     36 
     37 /**
     38  * Manages the retrieval of certain types of {@link MediaProjection} tokens.
     39  */
     40 @SystemService(Context.MEDIA_PROJECTION_SERVICE)
     41 public final class MediaProjectionManager {
     42     private static final String TAG = "MediaProjectionManager";
     43     /** @hide */
     44     public static final String EXTRA_APP_TOKEN = "android.media.projection.extra.EXTRA_APP_TOKEN";
     45     /** @hide */
     46     public static final String EXTRA_MEDIA_PROJECTION =
     47             "android.media.projection.extra.EXTRA_MEDIA_PROJECTION";
     48 
     49     /** @hide */
     50     public static final int TYPE_SCREEN_CAPTURE = 0;
     51     /** @hide */
     52     public static final int TYPE_MIRRORING = 1;
     53     /** @hide */
     54     public static final int TYPE_PRESENTATION = 2;
     55 
     56     private Context mContext;
     57     private Map<Callback, CallbackDelegate> mCallbacks;
     58     private IMediaProjectionManager mService;
     59 
     60     /** @hide */
     61     public MediaProjectionManager(Context context) {
     62         mContext = context;
     63         IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
     64         mService = IMediaProjectionManager.Stub.asInterface(b);
     65         mCallbacks = new ArrayMap<>();
     66     }
     67 
     68     /**
     69      * Returns an Intent that <b>must</b> passed to startActivityForResult()
     70      * in order to start screen capture. The activity will prompt
     71      * the user whether to allow screen capture.  The result of this
     72      * activity should be passed to getMediaProjection.
     73      */
     74     public Intent createScreenCaptureIntent() {
     75         Intent i = new Intent();
     76         final ComponentName mediaProjectionPermissionDialogComponent =
     77                 ComponentName.unflattenFromString(mContext.getResources().getString(
     78                         com.android.internal.R.string
     79                         .config_mediaProjectionPermissionDialogComponent));
     80         i.setComponent(mediaProjectionPermissionDialogComponent);
     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      */
     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      */
    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      */
    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      */
    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      */
    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 {
    168         public abstract void onStart(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 
    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
    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
    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