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 com.android.server.media.projection;
18c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
19c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport com.android.server.Watchdog;
20c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
21c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.Manifest;
22c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.app.AppOpsManager;
23c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.content.Context;
24c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.content.pm.PackageManager;
25c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.hardware.display.DisplayManager;
2689c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wrightimport android.media.MediaRouter;
27c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.IMediaProjectionManager;
28c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.IMediaProjection;
29c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.IMediaProjectionCallback;
30d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wrightimport android.media.projection.IMediaProjectionWatcherCallback;
31d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wrightimport android.media.projection.MediaProjectionInfo;
32c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.MediaProjectionManager;
33c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.Binder;
34c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.Handler;
35c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.IBinder;
36c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.Looper;
37c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.os.RemoteException;
38d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wrightimport android.os.UserHandle;
39c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.util.ArrayMap;
40c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.util.Slog;
41c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
42fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkeyimport com.android.internal.util.DumpUtils;
43c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport com.android.server.SystemService;
44c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
45c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport java.io.FileDescriptor;
46c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport java.io.PrintWriter;
47c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport java.util.Map;
48c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
49c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright/**
50c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * Manages MediaProjection sessions.
51c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright *
52c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * The {@link MediaProjectionManagerService} manages the creation and lifetime of MediaProjections,
53c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * as well as the capabilities they grant. Any service using MediaProjection tokens as permission
54c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * grants <b>must</b> validate the token before use by calling {@link
55c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright * IMediaProjectionService#isValidMediaProjection}.
56c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright */
57c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightpublic final class MediaProjectionManagerService extends SystemService
58c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        implements Watchdog.Monitor {
59c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private static final String TAG = "MediaProjectionManagerService";
60c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
61c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private final Object mLock = new Object(); // Protects the list of media projections
62d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private final Map<IBinder, IBinder.DeathRecipient> mDeathEaters;
63d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private final CallbackDelegate mCallbackDelegate;
64c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
65c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private final Context mContext;
66c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private final AppOpsManager mAppOps;
67c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
6889c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright    private final MediaRouter mMediaRouter;
6989c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright    private final MediaRouterCallback mMediaRouterCallback;
7089c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright    private MediaRouter.RouteInfo mMediaRouteInfo;
7189c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright
72d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private IBinder mProjectionToken;
73d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private MediaProjection mProjectionGrant;
74d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
75c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public MediaProjectionManagerService(Context context) {
76c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        super(context);
77c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        mContext = context;
78d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
79d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        mCallbackDelegate = new CallbackDelegate();
80c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
8189c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
8289c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        mMediaRouterCallback = new MediaRouterCallback();
83c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        Watchdog.getInstance().addMonitor(this);
84c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
85c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
86c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    @Override
87c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public void onStart() {
88c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        publishBinderService(Context.MEDIA_PROJECTION_SERVICE, new BinderService(),
89c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                false /*allowIsolated*/);
904444c5b27874866f18cd8f4abb8914cc17857ea7Jason Monk        mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback,
914444c5b27874866f18cd8f4abb8914cc17857ea7Jason Monk                MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
9289c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright    }
9389c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright
9489c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright    @Override
9589c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright    public void onSwitchUser(int userId) {
9689c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        mMediaRouter.rebindAsUser(userId);
9705aab5810a5f0296c3650f104c58479b2765c0b7Michael Wright        synchronized (mLock) {
9805aab5810a5f0296c3650f104c58479b2765c0b7Michael Wright            if (mProjectionGrant != null) {
9905aab5810a5f0296c3650f104c58479b2765c0b7Michael Wright                mProjectionGrant.stop();
10005aab5810a5f0296c3650f104c58479b2765c0b7Michael Wright            }
10105aab5810a5f0296c3650f104c58479b2765c0b7Michael Wright        }
102c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
103c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
104c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    @Override
105c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public void monitor() {
106c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        synchronized (mLock) { /* check for deadlock */ }
107c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
108c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
109d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private void startProjectionLocked(final MediaProjection projection) {
110d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        if (mProjectionGrant != null) {
111d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mProjectionGrant.stop();
112d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
11389c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        if (mMediaRouteInfo != null) {
11489c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright            mMediaRouter.getDefaultRoute().select();
11589c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        }
116d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        mProjectionToken = projection.asBinder();
117d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        mProjectionGrant = projection;
118d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        dispatchStart(projection);
119d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
120d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
121d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private void stopProjectionLocked(final MediaProjection projection) {
122d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        mProjectionToken = null;
123d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        mProjectionGrant = null;
124d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        dispatchStop(projection);
125d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
126d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
127d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private void addCallback(final IMediaProjectionWatcherCallback callback) {
128d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
129d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            @Override
130d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            public void binderDied() {
131ac3f8e5534b1653a29714b63a3afbc6c1a90e669Jae Seo                removeCallback(callback);
132d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
133d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        };
134d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        synchronized (mLock) {
135d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mCallbackDelegate.add(callback);
136d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            linkDeathRecipientLocked(callback, deathRecipient);
137d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
138d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
139d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
140d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private void removeCallback(IMediaProjectionWatcherCallback callback) {
141d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        synchronized (mLock) {
142d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            unlinkDeathRecipientLocked(callback);
14378b8c8fbde12b214314cc2ab2644350b5d5189a5John Spurlock            mCallbackDelegate.remove(callback);
144d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
145d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
146d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
147d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private void linkDeathRecipientLocked(IMediaProjectionWatcherCallback callback,
148d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            IBinder.DeathRecipient deathRecipient) {
149d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        try {
150d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            final IBinder token = callback.asBinder();
151d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            token.linkToDeath(deathRecipient, 0);
152d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mDeathEaters.put(token, deathRecipient);
153d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        } catch (RemoteException e) {
154d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            Slog.e(TAG, "Unable to link to death for media projection monitoring callback", e);
155d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
156d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
157d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
158d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private void unlinkDeathRecipientLocked(IMediaProjectionWatcherCallback callback) {
159d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        final IBinder token = callback.asBinder();
160d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        IBinder.DeathRecipient deathRecipient = mDeathEaters.remove(token);
161d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        if (deathRecipient != null) {
162d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            token.unlinkToDeath(deathRecipient, 0);
163d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
164d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
165d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
166d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private void dispatchStart(MediaProjection projection) {
167d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        mCallbackDelegate.dispatchStart(projection);
168d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
169d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
170d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private void dispatchStop(MediaProjection projection) {
171d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        mCallbackDelegate.dispatchStop(projection);
172d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
173d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
174d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private boolean isValidMediaProjection(IBinder token) {
175d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        synchronized (mLock) {
176d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (mProjectionToken != null) {
177d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                return mProjectionToken.equals(token);
178d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
179d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            return false;
180d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
181d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
182d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
183d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private MediaProjectionInfo getActiveProjectionInfo() {
184d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        synchronized (mLock) {
185d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (mProjectionGrant == null) {
186d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                return null;
187d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
188d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            return mProjectionGrant.getProjectionInfo();
189d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
190d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
191d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
192c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private void dump(final PrintWriter pw) {
193c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        pw.println("MEDIA PROJECTION MANAGER (dumpsys media_projection)");
194c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        synchronized (mLock) {
195d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            pw.println("Media Projection: ");
196d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (mProjectionGrant != null ) {
197d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                mProjectionGrant.dump(pw);
198d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            } else {
199d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                pw.println("null");
200c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
201c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
202c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
203c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
204c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private final class BinderService extends IMediaProjectionManager.Stub {
205c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
206c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
207c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public boolean hasProjectionPermission(int uid, String packageName) {
208c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            long token = Binder.clearCallingIdentity();
209c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            boolean hasPermission = false;
210c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            try {
211c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                hasPermission |= checkPermission(packageName,
212c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                        android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
2136720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                        || mAppOps.noteOpNoThrow(
214c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                                AppOpsManager.OP_PROJECT_MEDIA, uid, packageName)
215c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                        == AppOpsManager.MODE_ALLOWED;
216c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            } finally {
217c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                Binder.restoreCallingIdentity(token);
218c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
219c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            return hasPermission;
220c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
221c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
222c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
223c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public IMediaProjection createProjection(int uid, String packageName, int type,
224c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                boolean isPermanentGrant) {
225d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
226c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                        != PackageManager.PERMISSION_GRANTED) {
227d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to grant "
228c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                        + "projection permission");
229c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
230d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (packageName == null || packageName.isEmpty()) {
231d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                throw new IllegalArgumentException("package name must not be empty");
232d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
233c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            long callingToken = Binder.clearCallingIdentity();
234c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            MediaProjection projection;
235c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            try {
236c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                projection = new MediaProjection(type, uid, packageName);
237c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                if (isPermanentGrant) {
238c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA,
239c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                            projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED);
240c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                }
241c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            } finally {
242c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                Binder.restoreCallingIdentity(callingToken);
243c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
244c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            return projection;
245c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
246c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
247c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
248c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public boolean isValidMediaProjection(IMediaProjection projection) {
249d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            return MediaProjectionManagerService.this.isValidMediaProjection(
250d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    projection.asBinder());
251d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
252d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
253d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        @Override // Binder call
254d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public MediaProjectionInfo getActiveProjectionInfo() {
255d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
256d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        != PackageManager.PERMISSION_GRANTED) {
257d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
258d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        + "projection callbacks");
259d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
260d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            final long token = Binder.clearCallingIdentity();
261d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            try {
262d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                return MediaProjectionManagerService.this.getActiveProjectionInfo();
263d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            } finally {
264d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                Binder.restoreCallingIdentity(token);
265d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
266d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
267d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
268d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        @Override // Binder call
269d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void stopActiveProjection() {
270d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
271d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        != PackageManager.PERMISSION_GRANTED) {
272d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
273d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        + "projection callbacks");
274d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
275d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            final long token = Binder.clearCallingIdentity();
276d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            try {
277d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                if (mProjectionGrant != null) {
278d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    mProjectionGrant.stop();
279d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                }
280d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            } finally {
281d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                Binder.restoreCallingIdentity(token);
282d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
283d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
284d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
285d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
286d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        @Override //Binder call
287d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void addCallback(final IMediaProjectionWatcherCallback callback) {
288d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
289d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        != PackageManager.PERMISSION_GRANTED) {
290d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
291d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        + "projection callbacks");
292d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
293d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            final long token = Binder.clearCallingIdentity();
294d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            try {
295d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                MediaProjectionManagerService.this.addCallback(callback);
296d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            } finally {
297d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                Binder.restoreCallingIdentity(token);
298d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
299d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
300d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
301d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        @Override
302d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void removeCallback(IMediaProjectionWatcherCallback callback) {
303d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
304d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        != PackageManager.PERMISSION_GRANTED) {
305d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to remove "
306d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        + "projection callbacks");
307d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
308d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            final long token = Binder.clearCallingIdentity();
309d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            try {
310d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                MediaProjectionManagerService.this.removeCallback(callback);
311d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            } finally {
312d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                Binder.restoreCallingIdentity(token);
313d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
314c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
315c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
316c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
317c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
318fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkey            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
319c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            final long token = Binder.clearCallingIdentity();
320c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            try {
3219b84309bea122e63009408b3fa94a3e498ae60c9John Spurlock                MediaProjectionManagerService.this.dump(pw);
322c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            } finally {
323c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                Binder.restoreCallingIdentity(token);
324c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
325c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
326c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
327d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
328c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        private boolean checkPermission(String packageName, String permission) {
329c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            return mContext.getPackageManager().checkPermission(permission, packageName)
330c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    == PackageManager.PERMISSION_GRANTED;
331c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
332c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
333c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
334d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private final class MediaProjection extends IMediaProjection.Stub {
335d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public final int uid;
336d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public final String packageName;
337d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public final UserHandle userHandle;
338c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
339ac3f8e5534b1653a29714b63a3afbc6c1a90e669Jae Seo        private IMediaProjectionCallback mCallback;
340c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        private IBinder mToken;
341d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        private IBinder.DeathRecipient mDeathEater;
342c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        private int mType;
343c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
344c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public MediaProjection(int type, int uid, String packageName) {
345c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            mType = type;
346c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            this.uid = uid;
347c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            this.packageName = packageName;
348d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            userHandle = new UserHandle(UserHandle.getUserId(uid));
349c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
350c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
351c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
352c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public boolean canProjectVideo() {
353c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            return mType == MediaProjectionManager.TYPE_MIRRORING ||
354c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    mType == MediaProjectionManager.TYPE_SCREEN_CAPTURE;
355c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
356c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
357c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
358c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public boolean canProjectSecureVideo() {
359c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            return false;
360c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
361c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
362c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
363c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public boolean canProjectAudio() {
364c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            return mType == MediaProjectionManager.TYPE_MIRRORING ||
365c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    mType == MediaProjectionManager.TYPE_PRESENTATION;
366c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
367c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
368c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
3696720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright        public int applyVirtualDisplayFlags(int flags) {
3706720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright            if (mType == MediaProjectionManager.TYPE_SCREEN_CAPTURE) {
3716720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
3726720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
3736720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
3746720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                return flags;
3756720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright            } else if (mType == MediaProjectionManager.TYPE_MIRRORING) {
3766720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                flags &= ~(DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
3776720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
3786720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
3796720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                        DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
3806720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                return flags;
3816720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright            } else if (mType == MediaProjectionManager.TYPE_PRESENTATION) {
3826720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
3836720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
3846720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                        DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION |
3856720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
3866720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                return flags;
3876720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright            } else  {
3886720be4e8c65e90d4453ddad5cef192bc3820038Michael Wright                throw new RuntimeException("Unknown MediaProjection type");
389c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
390c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
391c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
392c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
393d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void start(final IMediaProjectionCallback callback) {
394c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            if (callback == null) {
395c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                throw new IllegalArgumentException("callback must not be null");
396c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
397c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            synchronized (mLock) {
398d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                if (isValidMediaProjection(asBinder())) {
399c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    throw new IllegalStateException(
400c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                            "Cannot start already started MediaProjection");
401c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                }
402ac3f8e5534b1653a29714b63a3afbc6c1a90e669Jae Seo                mCallback = callback;
403ac3f8e5534b1653a29714b63a3afbc6c1a90e669Jae Seo                registerCallback(mCallback);
404c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                try {
405c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    mToken = callback.asBinder();
406d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    mDeathEater = new IBinder.DeathRecipient() {
407d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        @Override
408d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        public void binderDied() {
409d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                            mCallbackDelegate.remove(callback);
410d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                            stop();
411d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        }
412d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    };
413d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    mToken.linkToDeath(mDeathEater, 0);
414c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                } catch (RemoteException e) {
415c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    Slog.w(TAG,
416c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                            "MediaProjectionCallbacks must be valid, aborting MediaProjection", e);
417c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    return;
418c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                }
419d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                startProjectionLocked(this);
420c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
421c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
422c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
423c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
424c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public void stop() {
425c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            synchronized (mLock) {
426d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                if (!isValidMediaProjection(asBinder())) {
427c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    Slog.w(TAG, "Attempted to stop inactive MediaProjection "
428c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                            + "(uid=" + Binder.getCallingUid() + ", "
429c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                            + "pid=" + Binder.getCallingPid() + ")");
430c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    return;
431c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                }
432d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                stopProjectionLocked(this);
433ac3f8e5534b1653a29714b63a3afbc6c1a90e669Jae Seo                mToken.unlinkToDeath(mDeathEater, 0);
434ac3f8e5534b1653a29714b63a3afbc6c1a90e669Jae Seo                mToken = null;
435ac3f8e5534b1653a29714b63a3afbc6c1a90e669Jae Seo                unregisterCallback(mCallback);
436ac3f8e5534b1653a29714b63a3afbc6c1a90e669Jae Seo                mCallback = null;
437c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
438c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
439c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
440c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override
441cde5bb45cc86d181d96ee69da1832e6132162871Michael Wright        public void registerCallback(IMediaProjectionCallback callback) {
442c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            if (callback == null) {
443c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                throw new IllegalArgumentException("callback must not be null");
444c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
445c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            mCallbackDelegate.add(callback);
446c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
447c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
448c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override
449cde5bb45cc86d181d96ee69da1832e6132162871Michael Wright        public void unregisterCallback(IMediaProjectionCallback callback) {
450c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            if (callback == null) {
451c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                throw new IllegalArgumentException("callback must not be null");
452c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
453c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            mCallbackDelegate.remove(callback);
454c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
455c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
456d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public MediaProjectionInfo getProjectionInfo() {
457d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            return new MediaProjectionInfo(packageName, userHandle);
458d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
459d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
460d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void dump(PrintWriter pw) {
461d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            pw.println("(" + packageName + ", uid=" + uid + "): " + typeToString(mType));
462c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
463c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
464c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
46589c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright    private class MediaRouterCallback extends MediaRouter.SimpleCallback {
46689c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        @Override
46789c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        public void onRouteSelected(MediaRouter router, int type, MediaRouter.RouteInfo info) {
46889c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright            synchronized (mLock) {
46989c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright                if ((type & MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
47089c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright                    mMediaRouteInfo = info;
47189c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright                    if (mProjectionGrant != null) {
47289c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright                        mProjectionGrant.stop();
47389c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright                    }
47489c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright                }
47589c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright            }
47689c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        }
47789c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright
47889c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        @Override
47989c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        public void onRouteUnselected(MediaRouter route, int type, MediaRouter.RouteInfo info) {
48089c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright            if (mMediaRouteInfo == info) {
48189c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright                mMediaRouteInfo = null;
48289c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright            }
48389c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright        }
48489c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright    }
48589c2cb6f31cddb926dea3498f8adf01a8cc1426aMichael Wright
486d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
487c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private static class CallbackDelegate {
488d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        private Map<IBinder, IMediaProjectionCallback> mClientCallbacks;
489d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        private Map<IBinder, IMediaProjectionWatcherCallback> mWatcherCallbacks;
490c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        private Handler mHandler;
491c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        private Object mLock = new Object();
492c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
493c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public CallbackDelegate() {
494c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            mHandler = new Handler(Looper.getMainLooper(), null, true /*async*/);
495d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mClientCallbacks = new ArrayMap<IBinder, IMediaProjectionCallback>();
496d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mWatcherCallbacks = new ArrayMap<IBinder, IMediaProjectionWatcherCallback>();
497c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
498c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
499c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public void add(IMediaProjectionCallback callback) {
500c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            synchronized (mLock) {
501d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                mClientCallbacks.put(callback.asBinder(), callback);
502d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
503d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
504d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
505d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void add(IMediaProjectionWatcherCallback callback) {
506d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            synchronized (mLock) {
507d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                mWatcherCallbacks.put(callback.asBinder(), callback);
508c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
509c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
510c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
511c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public void remove(IMediaProjectionCallback callback) {
512c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            synchronized (mLock) {
513d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                mClientCallbacks.remove(callback.asBinder());
514c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
515c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
516c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
517d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void remove(IMediaProjectionWatcherCallback callback) {
518c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            synchronized (mLock) {
519d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                mWatcherCallbacks.remove(callback.asBinder());
520d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
521d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
522d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
523d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void dispatchStart(MediaProjection projection) {
524d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (projection == null) {
525d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                Slog.e(TAG, "Tried to dispatch start notification for a null media projection."
526d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        + " Ignoring!");
527d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                return;
528d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
529d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            synchronized (mLock) {
530d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                for (IMediaProjectionWatcherCallback callback : mWatcherCallbacks.values()) {
531d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    MediaProjectionInfo info = projection.getProjectionInfo();
532d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    mHandler.post(new WatcherStartCallback(info, callback));
533c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                }
534c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
535c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
536d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
537d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void dispatchStop(MediaProjection projection) {
538d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            if (projection == null) {
539d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                Slog.e(TAG, "Tried to dispatch stop notification for a null media projection."
540d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                        + " Ignoring!");
541d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                return;
542d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
543d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            synchronized (mLock) {
544d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                for (IMediaProjectionCallback callback : mClientCallbacks.values()) {
545d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    mHandler.post(new ClientStopCallback(callback));
546d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                }
547d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
548d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                for (IMediaProjectionWatcherCallback callback : mWatcherCallbacks.values()) {
549d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    MediaProjectionInfo info = projection.getProjectionInfo();
550d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                    mHandler.post(new WatcherStopCallback(info, callback));
551d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                }
552d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
553d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
554d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
555d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
556d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private static final class WatcherStartCallback implements Runnable {
557d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        private IMediaProjectionWatcherCallback mCallback;
558d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        private MediaProjectionInfo mInfo;
559d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
560d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public WatcherStartCallback(MediaProjectionInfo info,
561d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                IMediaProjectionWatcherCallback callback) {
562d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mInfo = info;
563d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mCallback = callback;
564d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
565d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
566d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        @Override
567d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void run() {
568d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            try {
569d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                mCallback.onStart(mInfo);
570d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            } catch (RemoteException e) {
571d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                Slog.w(TAG, "Failed to notify media projection has stopped", e);
572d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
573d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
574d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
575d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
576d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private static final class WatcherStopCallback implements Runnable {
577d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        private IMediaProjectionWatcherCallback mCallback;
578d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        private MediaProjectionInfo mInfo;
579d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
580d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public WatcherStopCallback(MediaProjectionInfo info,
581d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                IMediaProjectionWatcherCallback callback) {
582d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mInfo = info;
583d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mCallback = callback;
584d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
585d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
586d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        @Override
587d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void run() {
588d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            try {
589d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                mCallback.onStop(mInfo);
590d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            } catch (RemoteException e) {
591d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                Slog.w(TAG, "Failed to notify media projection has stopped", e);
592d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
593d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
594c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
595c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
596d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    private static final class ClientStopCallback implements Runnable {
597d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        private IMediaProjectionCallback mCallback;
598d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
599d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public ClientStopCallback(IMediaProjectionCallback callback) {
600d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            mCallback = callback;
601d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
602d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
603d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        @Override
604d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        public void run() {
605d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            try {
606d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                mCallback.onStop();
607d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            } catch (RemoteException e) {
608d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright                Slog.w(TAG, "Failed to notify media projection has stopped", e);
609d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright            }
610d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright        }
611d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright    }
612d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
613d86ecd26d78c7bcd7f820b9ef5e3f4c3eb037510Michael Wright
614c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    private static String typeToString(int type) {
615c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        switch (type) {
616c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            case MediaProjectionManager.TYPE_SCREEN_CAPTURE:
617c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                return "TYPE_SCREEN_CAPTURE";
618c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            case MediaProjectionManager.TYPE_MIRRORING:
619c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                return "TYPE_MIRRORING";
620c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            case MediaProjectionManager.TYPE_PRESENTATION:
621c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                return "TYPE_PRESENTATION";
622c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
623c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        return Integer.toString(type);
624c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
625c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright}
626