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