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