• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.Context;
22 import android.hardware.display.DisplayManager;
23 import android.hardware.display.VirtualDisplay;
24 import android.media.AudioRecord;
25 import android.media.projection.IMediaProjection;
26 import android.media.projection.IMediaProjectionCallback;
27 import android.os.Handler;
28 import android.os.RemoteException;
29 import android.util.ArrayMap;
30 import android.util.Log;
31 import android.view.Surface;
32 
33 import java.util.Map;
34 
35 /**
36  * A token granting applications the ability to capture screen contents and/or
37  * record system audio. The exact capabilities granted depend on the type of
38  * MediaProjection.
39  *
40  * <p>
41  * A screen capture session can be started through {@link
42  * MediaProjectionManager#createScreenCaptureIntent}. This grants the ability to
43  * capture screen contents, but not system audio.
44  * </p>
45  */
46 public final class MediaProjection {
47     private static final String TAG = "MediaProjection";
48 
49     private final IMediaProjection mImpl;
50     private final Context mContext;
51     private final Map<Callback, CallbackRecord> mCallbacks;
52 
53     /** @hide */
MediaProjection(Context context, IMediaProjection impl)54     public MediaProjection(Context context, IMediaProjection impl) {
55         mCallbacks = new ArrayMap<Callback, CallbackRecord>();
56         mContext = context;
57         mImpl = impl;
58         try {
59             mImpl.start(new MediaProjectionCallback());
60         } catch (RemoteException e) {
61             throw new RuntimeException("Failed to start media projection", e);
62         }
63     }
64 
65     /** Register a listener to receive notifications about when the {@link
66      * MediaProjection} changes state.
67      *
68      * @param callback The callback to call.
69      * @param handler The handler on which the callback should be invoked, or
70      * null if the callback should be invoked on the calling thread's looper.
71      *
72      * @see #unregisterCallback
73      */
registerCallback(Callback callback, Handler handler)74     public void registerCallback(Callback callback, Handler handler) {
75         if (callback == null) {
76             throw new IllegalArgumentException("callback should not be null");
77         }
78         if (handler == null) {
79             handler = new Handler();
80         }
81         mCallbacks.put(callback, new CallbackRecord(callback, handler));
82     }
83 
84     /** Unregister a MediaProjection listener.
85      *
86      * @param callback The callback to unregister.
87      *
88      * @see #registerCallback
89      */
unregisterCallback(Callback callback)90     public void unregisterCallback(Callback callback) {
91         if (callback == null) {
92             throw new IllegalArgumentException("callback should not be null");
93         }
94         mCallbacks.remove(callback);
95     }
96 
97     /**
98      * @hide
99      */
createVirtualDisplay(@onNull String name, int width, int height, int dpi, boolean isSecure, @Nullable Surface surface, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler)100     public VirtualDisplay createVirtualDisplay(@NonNull String name,
101             int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
102             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
103         DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
104         int flags = isSecure ? DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE : 0;
105         return dm.createVirtualDisplay(this, name, width, height, dpi, surface,
106                     flags | DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR |
107                     DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION, callback, handler,
108                     null /* uniqueId */);
109     }
110 
111     /**
112      * Creates a {@link android.hardware.display.VirtualDisplay} to capture the
113      * contents of the screen.
114      *
115      * @param name The name of the virtual display, must be non-empty.
116      * @param width The width of the virtual display in pixels. Must be
117      * greater than 0.
118      * @param height The height of the virtual display in pixels. Must be
119      * greater than 0.
120      * @param dpi The density of the virtual display in dpi. Must be greater
121      * than 0.
122      * @param surface The surface to which the content of the virtual display
123      * should be rendered, or null if there is none initially.
124      * @param flags A combination of virtual display flags. See {@link DisplayManager} for the full
125      * list of flags.
126      * @param callback Callback to call when the virtual display's state
127      * changes, or null if none.
128      * @param handler The {@link android.os.Handler} on which the callback should be
129      * invoked, or null if the callback should be invoked on the calling
130      * thread's main {@link android.os.Looper}.
131      *
132      * @see android.hardware.display.VirtualDisplay
133      */
createVirtualDisplay(@onNull String name, int width, int height, int dpi, int flags, @Nullable Surface surface, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler)134     public VirtualDisplay createVirtualDisplay(@NonNull String name,
135             int width, int height, int dpi, int flags, @Nullable Surface surface,
136             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
137         DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
138         return dm.createVirtualDisplay(this, name, width, height, dpi, surface, flags, callback,
139                 handler, null /* uniqueId */);
140     }
141 
142     /**
143      * Creates an AudioRecord to capture audio played back by the system.
144      * @hide
145      */
createAudioRecord( int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)146     public AudioRecord createAudioRecord(
147             int sampleRateInHz, int channelConfig,
148             int audioFormat, int bufferSizeInBytes) {
149         return null;
150     }
151 
152     /**
153      * Stops projection.
154      */
stop()155     public void stop() {
156         try {
157             mImpl.stop();
158         } catch (RemoteException e) {
159             Log.e(TAG, "Unable to stop projection", e);
160         }
161     }
162 
163     /**
164      * Get the underlying IMediaProjection.
165      * @hide
166      */
getProjection()167     public IMediaProjection getProjection() {
168         return mImpl;
169     }
170 
171     /**
172      * Callbacks for the projection session.
173      */
174     public static abstract class Callback {
175         /**
176          * Called when the MediaProjection session is no longer valid.
177          * <p>
178          * Once a MediaProjection has been stopped, it's up to the application to release any
179          * resources it may be holding (e.g. {@link android.hardware.display.VirtualDisplay}s).
180          * </p>
181          */
onStop()182         public void onStop() { }
183     }
184 
185     private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub {
186         @Override
onStop()187         public void onStop() {
188             for (CallbackRecord cbr : mCallbacks.values()) {
189                 cbr.onStop();
190             }
191         }
192     }
193 
194     private final static class CallbackRecord {
195         private final Callback mCallback;
196         private final Handler mHandler;
197 
CallbackRecord(Callback callback, Handler handler)198         public CallbackRecord(Callback callback, Handler handler) {
199             mCallback = callback;
200             mHandler = handler;
201         }
202 
onStop()203         public void onStop() {
204             mHandler.post(new Runnable() {
205                 @Override
206                 public void run() {
207                     mCallback.onStop();
208                 }
209             });
210         }
211     }
212 }
213