1c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright/*
2c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * Copyright (C) 2014 The Android Open Source Project
3c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright *
4c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * Licensed under the Apache License, Version 2.0 (the "License");
5c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * you may not use this file except in compliance with the License.
6c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * You may obtain a copy of the License at
7c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright *
8c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright *      http://www.apache.org/licenses/LICENSE-2.0
9c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright *
10c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * Unless required by applicable law or agreed to in writing, software
11c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * distributed under the License is distributed on an "AS IS" BASIS,
12c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * See the License for the specific language governing permissions and
14c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * limitations under the License.
15c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright */
16c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
17c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightpackage android.media.projection;
18c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
19c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.annotation.NonNull;
20c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.annotation.Nullable;
21c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.content.Context;
22c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.hardware.display.DisplayManager;
23c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.hardware.display.VirtualDisplay;
24c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.AudioRecord;
25c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.IMediaProjection;
26c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.IMediaProjectionCallback;
27c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.Handler;
28c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.Looper;
29c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.RemoteException;
30c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.util.ArrayMap;
31c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.util.Log;
32c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.view.Surface;
33c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
34c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport java.util.Map;
35c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
36c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright/**
37c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * A token granting applications the ability to capture screen contents and/or
38c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * record system audio. The exact capabilities granted depend on the type of
39c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * MediaProjection.
40c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright *
41c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * <p>
42c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * A screen capture session can be started through {@link
43cde5bb45cc86d181d96ee69da1832e6132162871Michael Wright * MediaProjectionManager#createScreenCaptureIntent}. This grants the ability to
44c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * capture screen contents, but not system audio.
45c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * </p>
46c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright */
47c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightpublic final class MediaProjection {
48c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private static final String TAG = "MediaProjection";
49c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
50c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private final IMediaProjection mImpl;
51c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private final Context mContext;
52c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private final Map<Callback, CallbackRecord> mCallbacks;
53c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
54c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    /** @hide */
55c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public MediaProjection(Context context, IMediaProjection impl) {
56c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        mCallbacks = new ArrayMap<Callback, CallbackRecord>();
57c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        mContext = context;
58c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        mImpl = impl;
59c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        try {
60c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            mImpl.start(new MediaProjectionCallback());
61c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        } catch (RemoteException e) {
62c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            throw new RuntimeException("Failed to start media projection", e);
63c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
64c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
65c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
66c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    /** Register a listener to receive notifications about when the {@link
67c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * MediaProjection} changes state.
68c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     *
69c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @param callback The callback to call.
70c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @param handler The handler on which the callback should be invoked, or
71c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * null if the callback should be invoked on the calling thread's looper.
72c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     *
73cde5bb45cc86d181d96ee69da1832e6132162871Michael Wright     * @see #unregisterCallback
74c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     */
75cde5bb45cc86d181d96ee69da1832e6132162871Michael Wright    public void registerCallback(Callback callback, Handler handler) {
76c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        if (callback == null) {
77c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            throw new IllegalArgumentException("callback should not be null");
78c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
799e8d9aca07913b3e8a017614088048c721a82ccbMichael Wright        if (handler == null) {
809e8d9aca07913b3e8a017614088048c721a82ccbMichael Wright            handler = new Handler();
819e8d9aca07913b3e8a017614088048c721a82ccbMichael Wright        }
82c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        mCallbacks.put(callback, new CallbackRecord(callback, handler));
83c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
84c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
85c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    /** Unregister a MediaProjection listener.
86c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     *
87c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @param callback The callback to unregister.
88c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     *
89cde5bb45cc86d181d96ee69da1832e6132162871Michael Wright     * @see #registerCallback
90c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     */
91cde5bb45cc86d181d96ee69da1832e6132162871Michael Wright    public void unregisterCallback(Callback callback) {
92c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        if (callback == null) {
93c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            throw new IllegalArgumentException("callback should not be null");
94c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
95c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        mCallbacks.remove(callback);
96c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
97c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
98c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    /**
996720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright     * @hide
1006720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright     */
1016720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright    public VirtualDisplay createVirtualDisplay(@NonNull String name,
1026720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright            int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
10375ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
1046720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright        DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
1056720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright        int flags = isSecure ? DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE : 0;
1066720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright        return dm.createVirtualDisplay(this, name, width, height, dpi, surface,
1076720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                    flags | DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR |
10875ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                    DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION, callback, handler);
1096720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright    }
1106720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright
1116720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright    /**
112c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * Creates a {@link android.hardware.display.VirtualDisplay} to capture the
113c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * contents of the screen.
114c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     *
115c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @param name The name of the virtual display, must be non-empty.
116c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @param width The width of the virtual display in pixels. Must be
117c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * greater than 0.
118c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @param height The height of the virtual display in pixels. Must be
119c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * greater than 0.
120c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @param dpi The density of the virtual display in dpi. Must be greater
121c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * than 0.
122c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @param surface The surface to which the content of the virtual display
123c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * should be rendered, or null if there is none initially.
1246720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright     * @param flags A combination of virtual display flags. See {@link DisplayManager} for the full
1256720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright     * list of flags.
12675ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright     * @param callback Callback to call when the virtual display's state
127c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * changes, or null if none.
128c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @param handler The {@link android.os.Handler} on which the callback should be
129c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * invoked, or null if the callback should be invoked on the calling
130c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * thread's main {@link android.os.Looper}.
131c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     *
1321e88cf0796c8b15952b7d6b3160d0d097e857f15Ryan Lothian     * @see android.hardware.display.VirtualDisplay
133c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     */
134c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public VirtualDisplay createVirtualDisplay(@NonNull String name,
1356720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright            int width, int height, int dpi, int flags, @Nullable Surface surface,
13675ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
137c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
138c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        return dm.createVirtualDisplay(
13975ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                    this, name, width, height, dpi, surface, flags, callback, handler);
140c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
141c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
142c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    /**
143c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * Creates an AudioRecord to capture audio played back by the system.
144d5bfcff975cadc037d836bdab2f0976a40fad4dfMichael Wright     * @hide
145c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     */
146c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public AudioRecord createAudioRecord(
147c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            int sampleRateInHz, int channelConfig,
148c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            int audioFormat, int bufferSizeInBytes) {
149c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        return null;
150c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
151c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
152c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    /**
153c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * Stops projection.
154c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     */
155c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public void stop() {
156c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        try {
157c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            mImpl.stop();
158c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        } catch (RemoteException e) {
159c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            Log.e(TAG, "Unable to stop projection", e);
160c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
161c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
162c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
163c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    /**
164c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * Get the underlying IMediaProjection.
165c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * @hide
166c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     */
167c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public IMediaProjection getProjection() {
168c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        return mImpl;
169c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
170c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
171c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    /**
172c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     * Callbacks for the projection session.
173c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright     */
174c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public static abstract class Callback {
175c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        /**
176c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright         * Called when the MediaProjection session is no longer valid.
1779469cdde2ce55051b18fdbd6bf80bc710517c358Michael Wright         * <p>
178c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright         * Once a MediaProjection has been stopped, it's up to the application to release any
179c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright         * resources it may be holding (e.g. {@link android.hardware.display.VirtualDisplay}s).
1809469cdde2ce55051b18fdbd6bf80bc710517c358Michael Wright         * </p>
181c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright         */
182c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public void onStop() { }
183c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
184c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
185c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub {
186c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override
187c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public void onStop() {
1889e8d9aca07913b3e8a017614088048c721a82ccbMichael Wright            for (CallbackRecord cbr : mCallbacks.values()) {
1899e8d9aca07913b3e8a017614088048c721a82ccbMichael Wright                cbr.onStop();
190c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
191c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
192c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
193c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
194c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private final static class CallbackRecord {
1959e8d9aca07913b3e8a017614088048c721a82ccbMichael Wright        private final Callback mCallback;
1969e8d9aca07913b3e8a017614088048c721a82ccbMichael Wright        private final Handler mHandler;
197c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
198c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public CallbackRecord(Callback callback, Handler handler) {
199c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            mCallback = callback;
200c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            mHandler = handler;
201c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
202c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
203c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public void onStop() {
204c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            mHandler.post(new Runnable() {
205c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                @Override
206c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                public void run() {
207c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    mCallback.onStop();
208c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                }
209c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            });
210c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
211c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
212c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright}
213