蒙阴做网站,邢台信息港最新二手房出售信息,wordpress wp_page_menu,中文域名是什么1.概述
Android原生对MediaProjection的管理逻辑#xff0c;是如果服务端已经保存有MediaProjection的实例#xff0c;那么再次创建的时候#xff0c;之前的MediaProjection实例就会被暂停#xff0c;并且引用指向新的实例#xff0c;也就导致了当开启后一个录屏应用时是如果服务端已经保存有MediaProjection的实例那么再次创建的时候之前的MediaProjection实例就会被暂停并且引用指向新的实例也就导致了当开启后一个录屏应用时前一个录屏应用会被暂停。为了能实现多个录屏应用同时录屏或者共享屏幕或投屏的时候录屏我们需要对framework进行修改只需对一个文件进行修改frameworks/base/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
2.实现能同时开启多个MediaProjection
大致的思路就是修改MediaProjectionManagerService.java使得MediaProjectionManagerService服务端能够保存多个MediaProjeciton实例。
/** Copyright (C) 2014 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the License);* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.android.server.media.projection;import android.Manifest;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.IProcessObserver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionManager;
import android.media.projection.IMediaProjectionWatcherCallback;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.Watchdog;import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** Manages MediaProjection sessions.** The {link MediaProjectionManagerService} manages the creation and lifetime of MediaProjections,* as well as the capabilities they grant. Any service using MediaProjection tokens as permission* grants bmust/b validate the token before use by calling {link* IMediaProjectionService#isValidMediaProjection}.*/
public final class MediaProjectionManagerService extends SystemServiceimplements Watchdog.Monitor {private static final boolean REQUIRE_FG_SERVICE_FOR_PROJECTION true;private static final String TAG MediaProjectionManagerService;private static boolean DEBUG false;private final Object mLock new Object(); // Protects the list of media projectionsprivate final MapIBinder, IBinder.DeathRecipient mDeathEaters;private final CallbackDelegate mCallbackDelegate;private final Context mContext;private final AppOpsManager mAppOps;private final ActivityManagerInternal mActivityManagerInternal;private final PackageManager mPackageManager;private final MediaRouter mMediaRouter;private final MediaRouterCallback mMediaRouterCallback;private MediaRouter.RouteInfo mMediaRouteInfo;private MapIBinder, MediaProjectionEntry mEntryMap;public MediaProjectionManagerService(Context context) {super(context);mContext context;mDeathEaters new ArrayMapIBinder, IBinder.DeathRecipient();mCallbackDelegate new CallbackDelegate();mAppOps (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);mActivityManagerInternal LocalServices.getService(ActivityManagerInternal.class);mPackageManager mContext.getPackageManager();mMediaRouter (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);mMediaRouterCallback new MediaRouterCallback();mEntryMap new ArrayMapIBinder, MediaProjectionEntry();if (userdebug.equals(SystemProperties.get(ro.build.type, user))) {DEBUG true;}Watchdog.getInstance().addMonitor(this);}Overridepublic void onStart() {logd(onStart);publishBinderService(Context.MEDIA_PROJECTION_SERVICE, new BinderService(),false /*allowIsolated*/);mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback,MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);if (REQUIRE_FG_SERVICE_FOR_PROJECTION) {mActivityManagerInternal.registerProcessObserver(new IProcessObserver.Stub() {Overridepublic void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {}Overridepublic void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {MediaProjectionManagerService.this.handleForegroundServicesChanged(pid, uid,serviceTypes);}Overridepublic void onProcessDied(int pid, int uid) {}});}}Overridepublic void onSwitchUser(int userId) {logd(onSwitchUser: userId userId);mMediaRouter.rebindAsUser(userId);synchronized (mLock) {if (mEntryMap ! null !mEntryMap.isEmpty()) {for (MediaProjectionEntry entry : mEntryMap.values()) {if (entry ! null) {entry.getProjectionGrant().stop();}}}}}Overridepublic void monitor() {synchronized (mLock) { /* check for deadlock */ }}/*** Called when the set of active foreground service types for a given {code uid / pid} changes.* We will stop the active projection grant if its owner targets {code Q} or higher and has no* started foreground services of type {code FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}.*/private void handleForegroundServicesChanged(int pid, int uid, int serviceTypes) {synchronized (mLock) {logd(handleForegroundServicesChanged: pid pid , uid uid , serviceTypes serviceTypes);if (mEntryMap null || mEntryMap.isEmpty()) {return;}String uidpid String.format(%s_%s, uid, pid);MediaProjectionEntry entry getMediaProjectionEntryByUidPid(uidpid);if (entry null || entry.getProjectionGrant() null) {return;}MediaProjection mediaProjection entry.getProjectionGrant();if (!mediaProjection.requiresForegroundService()) {return;}if ((serviceTypes ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION) ! 0) {return;}mediaProjection.stop();logd(handleForegroundServicesChanged: MediaProjection mediaProjection.getProjectionInfo() hashCode mediaProjection.asBinder().hashCode() stoped);}}private void startProjectionLocked(final String uidpid, final MediaProjection projection) {logd(startProjectionLocked: calling uidpid uidpid , MediaProjection projection.getProjectionInfo() hashCode projection.asBinder().hashCode() , current MediaProjection count mEntryMap.size());if (mMediaRouteInfo ! null) {mMediaRouter.getFallbackRoute().select();}ListIBinder removedMediaProjections new ArrayList();logd( MediaProjections:);if (mEntryMap.isEmpty()) {logd( null);} else {for (MediaProjectionEntry entry : mEntryMap.values()) {if (entry ! null) {logd( entry.getProjectionGrant().getProjectionInfo() hashCode entry.getProjectionToken().hashCode());MediaProjection mp entry.getProjectionGrant();if (mp.packageName.equals(projection.packageName)) {removedMediaProjections.add(entry.getProjectionToken());}} else {logd( null);}}}for (IBinder token : removedMediaProjections) {MediaProjectionEntry entry mEntryMap.get(token);if (entry ! null) {MediaProjection mp entry.getProjectionGrant();logd(mp.packageName already existing MediaProjection mp.getProjectionInfo() hashCode mp.asBinder().hashCode() , remove it);mp.stop();}}MediaProjectionEntry entry new MediaProjectionEntry(uidpid, projection.asBinder(),projection);mEntryMap.put(projection.asBinder(), entry);dispatchStart(projection);logd(startProjectionLocked: start success, current MediaProjection count mEntryMap.size());}private void stopProjectionLocked(final MediaProjection projection) {logd(stopProjectionLocked: MediaProjection projection.getProjectionInfo() hashCode projection.asBinder().hashCode());mEntryMap.remove(projection.asBinder());dispatchStop(projection);logd(stopProjectionLocked: stop success, remaining MediaProjection count mEntryMap.size());}private void addCallback(final IMediaProjectionWatcherCallback callback) {logd(addCallback: callback callback);IBinder.DeathRecipient deathRecipient new IBinder.DeathRecipient() {Overridepublic void binderDied() {removeCallback(callback);}};synchronized (mLock) {mCallbackDelegate.add(callback);linkDeathRecipientLocked(callback, deathRecipient);}}private void removeCallback(IMediaProjectionWatcherCallback callback) {synchronized (mLock) {logd(removeCallback: callback callback);unlinkDeathRecipientLocked(callback);mCallbackDelegate.remove(callback);}}private void linkDeathRecipientLocked(IMediaProjectionWatcherCallback callback,IBinder.DeathRecipient deathRecipient) {try {logd(linkDeathRecipientLocked: callback callback , deathRecipient deathRecipient);final IBinder token callback.asBinder();token.linkToDeath(deathRecipient, 0);mDeathEaters.put(token, deathRecipient);} catch (RemoteException e) {Slog.e(TAG, Unable to link to death for media projection monitoring callback, e);}}private void unlinkDeathRecipientLocked(IMediaProjectionWatcherCallback callback) {logd(unlinkDeathRecipientLocked: callback callback);final IBinder token callback.asBinder();IBinder.DeathRecipient deathRecipient mDeathEaters.remove(token);if (deathRecipient ! null) {token.unlinkToDeath(deathRecipient, 0);}}private void dispatchStart(MediaProjection projection) {logd(dispatchStart: MediaProjection projection.getProjectionInfo() hashCode projection.asBinder().hashCode());mCallbackDelegate.dispatchStart(projection);}private void dispatchStop(MediaProjection projection) {logd(dispatchStop: MediaProjection projection.getProjectionInfo() hashCode projection.asBinder().hashCode());mCallbackDelegate.dispatchStop(projection);}private boolean isValidMediaProjection(IBinder token) {synchronized (mLock) {logd(isValidMediaProjection: MediaProjection hashCode token.hashCode());if (mEntryMap null mEntryMap.isEmpty()) {return false;}for (MediaProjectionEntry entry : mEntryMap.values()) {if (entry ! null entry.getProjectionToken().equals(token)) {logd(isValidMediaProjection: MediaProjection hashCode token.hashCode() is valid);return true;}}logd(isValidMediaProjection: MediaProjection hashCode token.hashCode() is invalid);return false;}}private MediaProjectionInfo getActiveProjectionInfo(String uidpid) {synchronized (mLock) {if (mEntryMap null || mEntryMap.isEmpty()) {return null;}MediaProjectionEntry entry getMediaProjectionEntryByUidPid(uidpid);if (entry null) {return null;}logd(getActiveProjectionInfo: MediaProjection entry.getProjectionGrant().getProjectionInfo() hashCode entry.getProjectionToken().hashCode());return entry.getProjectionGrant().getProjectionInfo();}}private void dump(final PrintWriter pw) {pw.println(MEDIA PROJECTION MANAGER (dumpsys media_projection));synchronized (mLock) {pw.println(Media Projection: );if (mEntryMap ! null !mEntryMap.isEmpty()) {for (MediaProjectionEntry entry : mEntryMap.values()) {if (entry ! null) {entry.dump(pw);}}} else {pw.println(null);}}}private final class BinderService extends IMediaProjectionManager.Stub {Override // Binder callpublic boolean hasProjectionPermission(int uid, String packageName) {logd(BinderService hasProjectionPermission: uid uid , packageName packageName);long token Binder.clearCallingIdentity();boolean hasPermission false;try {hasPermission | checkPermission(packageName,android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)|| mAppOps.noteOpNoThrow(AppOpsManager.OP_PROJECT_MEDIA, uid, packageName) AppOpsManager.MODE_ALLOWED;} finally {Binder.restoreCallingIdentity(token);}return hasPermission;}Override // Binder callpublic IMediaProjection createProjection(int uid, String packageName, int type,boolean isPermanentGrant) {final String uidpid getCallingUidPid();logd(BinderService createProjection: uid uid , packageName packageName , type type , isPermanentGrant isPermanentGrant , calling uidpid uidpid);if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)! PackageManager.PERMISSION_GRANTED) {throw new SecurityException(Requires MANAGE_MEDIA_PROJECTION in order to grant projection permission);}if (packageName null || packageName.isEmpty()) {throw new IllegalArgumentException(package name must not be empty);}final UserHandle callingUser Binder.getCallingUserHandle();long callingToken Binder.clearCallingIdentity();MediaProjection projection;try {ApplicationInfo ai;try {ai mPackageManager.getApplicationInfoAsUser(packageName, 0, callingUser);} catch (NameNotFoundException e) {throw new IllegalArgumentException(No package matching : packageName);}projection new MediaProjection(type, uid, packageName, ai.targetSdkVersion,ai.isPrivilegedApp());if (isPermanentGrant) {mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA,projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED);}} finally {Binder.restoreCallingIdentity(callingToken);}return projection;}Override // Binder callpublic boolean isValidMediaProjection(IMediaProjection projection) {return MediaProjectionManagerService.this.isValidMediaProjection(projection.asBinder());}Override // Binder callpublic MediaProjectionInfo getActiveProjectionInfo() {final String uidpid getCallingUidPid();logd(BinderService getActiveProjectionInfo: calling uidpid uidpid);if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)! PackageManager.PERMISSION_GRANTED) {throw new SecurityException(Requires MANAGE_MEDIA_PROJECTION in order to add projection callbacks);}final long token Binder.clearCallingIdentity();try {return MediaProjectionManagerService.this.getActiveProjectionInfo(uidpid);} finally {Binder.restoreCallingIdentity(token);}}Override // Binder callpublic void stopActiveProjection() {final String uidpid getCallingUidPid();logd(BinderService stopActiveProjection: calling uidpid uidpid);if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)! PackageManager.PERMISSION_GRANTED) {throw new SecurityException(Requires MANAGE_MEDIA_PROJECTION in order to add projection callbacks);}final long token Binder.clearCallingIdentity();try {MediaProjectionEntry entry getMediaProjectionEntryByUidPid(uidpid);if (entry ! null) {logd(BinderService stopActiveProjection: MediaProjection entry.getProjectionGrant().getProjectionInfo() hashCode entry.getProjectionToken().hashCode());entry.getProjectionGrant().stop();}} finally {Binder.restoreCallingIdentity(token);}}Override //Binder callpublic void addCallback(final IMediaProjectionWatcherCallback callback) {logd(BinderService addCallback: callback callback);if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)! PackageManager.PERMISSION_GRANTED) {throw new SecurityException(Requires MANAGE_MEDIA_PROJECTION in order to add projection callbacks);}final long token Binder.clearCallingIdentity();try {MediaProjectionManagerService.this.addCallback(callback);} finally {Binder.restoreCallingIdentity(token);}}Overridepublic void removeCallback(IMediaProjectionWatcherCallback callback) {logd(BinderService removeCallback: callback callback);if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)! PackageManager.PERMISSION_GRANTED) {throw new SecurityException(Requires MANAGE_MEDIA_PROJECTION in order to remove projection callbacks);}final long token Binder.clearCallingIdentity();try {MediaProjectionManagerService.this.removeCallback(callback);} finally {Binder.restoreCallingIdentity(token);}}Override // Binder callpublic void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;final long token Binder.clearCallingIdentity();try {MediaProjectionManagerService.this.dump(pw);} finally {Binder.restoreCallingIdentity(token);}}private boolean checkPermission(String packageName, String permission) {return mContext.getPackageManager().checkPermission(permission, packageName) PackageManager.PERMISSION_GRANTED;}}private final class MediaProjection extends IMediaProjection.Stub {public final int uid;public final String packageName;public final UserHandle userHandle;private final int mTargetSdkVersion;private final boolean mIsPrivileged;private final int mType;private IMediaProjectionCallback mCallback;private IBinder mToken;private IBinder.DeathRecipient mDeathEater;private boolean mRestoreSystemAlertWindow;MediaProjection(int type, int uid, String packageName, int targetSdkVersion,boolean isPrivileged) {mType type;this.uid uid;this.packageName packageName;userHandle new UserHandle(UserHandle.getUserId(uid));mTargetSdkVersion targetSdkVersion;mIsPrivileged isPrivileged;}Override // Binder callpublic boolean canProjectVideo() {return mType MediaProjectionManager.TYPE_MIRRORING ||mType MediaProjectionManager.TYPE_SCREEN_CAPTURE;}Override // Binder callpublic boolean canProjectSecureVideo() {return false;}Override // Binder callpublic boolean canProjectAudio() {return mType MediaProjectionManager.TYPE_MIRRORING|| mType MediaProjectionManager.TYPE_PRESENTATION|| mType MediaProjectionManager.TYPE_SCREEN_CAPTURE;}Override // Binder callpublic int applyVirtualDisplayFlags(int flags) {if (mType MediaProjectionManager.TYPE_SCREEN_CAPTURE) {flags ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;flags | DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR| DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;return flags;} else if (mType MediaProjectionManager.TYPE_MIRRORING) {flags ~(DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);flags | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;return flags;} else if (mType MediaProjectionManager.TYPE_PRESENTATION) {flags ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;flags | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION |DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;return flags;} else {throw new RuntimeException(Unknown MediaProjection type);}}Override // Binder callpublic void start(final IMediaProjectionCallback callback) {if (callback null) {throw new IllegalArgumentException(callback must not be null);}synchronized (mLock) {final String uidpid getCallingUidPid();logd(MediaProjection start: calling uidpid uidpid , callback callback);if (isValidMediaProjection(asBinder())) {Slog.w(TAG, UID Binder.getCallingUid() attempted to start already started MediaProjection);return;}if (REQUIRE_FG_SERVICE_FOR_PROJECTION requiresForegroundService() !mActivityManagerInternal.hasRunningForegroundService(uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {throw new SecurityException(Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);}mCallback callback;registerCallback(mCallback);try {mToken callback.asBinder();mDeathEater new IBinder.DeathRecipient() {Overridepublic void binderDied() {mCallbackDelegate.remove(asBinder(), callback);stop();}};mToken.linkToDeath(mDeathEater, 0);} catch (RemoteException e) {Slog.w(TAG, MediaProjectionCallbacks must be valid, aborting MediaProjection, e);return;}if (mType MediaProjectionManager.TYPE_SCREEN_CAPTURE) {final long token Binder.clearCallingIdentity();try {// We allow an app running a current screen capture session to use// SYSTEM_ALERT_WINDOW for the duration of the session, to enable// them to overlay their UX on top of what is being captured.// We only do this if the app requests the permission, and the appop// is in its default state (the user has neither explicitly allowed nor// disallowed it).final PackageInfo packageInfo mPackageManager.getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS,UserHandle.getUserId(uid));if (ArrayUtils.contains(packageInfo.requestedPermissions,Manifest.permission.SYSTEM_ALERT_WINDOW)) {final int currentMode mAppOps.unsafeCheckOpRawNoThrow(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName);if (currentMode AppOpsManager.MODE_DEFAULT) {mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid,packageName, AppOpsManager.MODE_ALLOWED);mRestoreSystemAlertWindow true;}}} catch (PackageManager.NameNotFoundException e) {Slog.w(TAG, Package not found, aborting MediaProjection, e);return;} finally {Binder.restoreCallingIdentity(token);}}startProjectionLocked(uidpid, this);}}Override // Binder callpublic void stop() {synchronized (mLock) {logd(MediaProjection stop: calling uidpid getCallingUidPid());if (!isValidMediaProjection(asBinder())) {Slog.w(TAG, Attempted to stop inactive MediaProjection (uid Binder.getCallingUid() , pid Binder.getCallingPid() ));return;}if (mRestoreSystemAlertWindow) {final long token Binder.clearCallingIdentity();try {// Put the appop back how it was, unless it has been changed from what// we set it to.// Note that WindowManager takes care of removing any existing overlay// windows when we do this.final int currentMode mAppOps.unsafeCheckOpRawNoThrow(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName);if (currentMode AppOpsManager.MODE_ALLOWED) {mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName,AppOpsManager.MODE_DEFAULT);}mRestoreSystemAlertWindow false;} finally {Binder.restoreCallingIdentity(token);}}stopProjectionLocked(this);mToken.unlinkToDeath(mDeathEater, 0);mToken null;unregisterCallbacks();mCallback null;}}Overridepublic void registerCallback(IMediaProjectionCallback callback) {if (callback null) {throw new IllegalArgumentException(callback must not be null);}logd(MediaProjection registerCallback: MediaProjection(hashCode asBinder().hashCode() ) callback callback);mCallbackDelegate.add(asBinder(), callback);}Overridepublic void unregisterCallback(IMediaProjectionCallback callback) {if (callback null) {throw new IllegalArgumentException(callback must not be null);}logd(MediaProjection unregisterCallback: MediaProjection(hashCode asBinder().hashCode() ) callback callback);mCallbackDelegate.remove(asBinder(), callback);}private void unregisterCallbacks() {logd(MediaProjection unregister callbacks for MediaProjection(hashCode asBinder().hashCode() ) because media projection stopped);mCallbackDelegate.remove(asBinder());}public MediaProjectionInfo getProjectionInfo() {return new MediaProjectionInfo(packageName, userHandle);}boolean requiresForegroundService() {return mTargetSdkVersion Build.VERSION_CODES.Q !mIsPrivileged;}public void dump(PrintWriter pw) {pw.println(( packageName , uid uid ): typeToString(mType));}}private class MediaRouterCallback extends MediaRouter.SimpleCallback {Overridepublic void onRouteSelected(MediaRouter router, int type, MediaRouter.RouteInfo info) {synchronized (mLock) {logd(MediaRouterCallback onRouteSelected: router router , type type , info info , calling uidpid getCallingUidPid());if ((type MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY) ! 0) {mMediaRouteInfo info;for (MediaProjectionEntry entry : mEntryMap.values()) {if (entry ! null) {entry.getProjectionGrant().stop();}}}}}Overridepublic void onRouteUnselected(MediaRouter route, int type, MediaRouter.RouteInfo info) {logd(MediaRouterCallback onRouteUnselected: router route , type type , info info);if (mMediaRouteInfo info) {mMediaRouteInfo null;}}}private static class CallbackDelegate {private MapIBinder, MapIBinder, IMediaProjectionCallback mClientCallbacks;private MapIBinder, IMediaProjectionWatcherCallback mWatcherCallbacks;private Handler mHandler;private Object mLock new Object();public CallbackDelegate() {mHandler new Handler(Looper.getMainLooper(), null, true /*async*/);mClientCallbacks new ArrayMapIBinder, MapIBinder, IMediaProjectionCallback();mWatcherCallbacks new ArrayMapIBinder, IMediaProjectionWatcherCallback();}public void add(IBinder token, IMediaProjectionCallback callback) {synchronized (mLock) {if (mClientCallbacks.get(token) null) {mClientCallbacks.put(token, new ArrayMapIBinder, IMediaProjectionCallback());logd(CallbackDelegate add: create callback container for MediaProjection(hashCode token.hashCode() ));}MapIBinder, IMediaProjectionCallback callbacks mClientCallbacks.get(token);callbacks.put(callback.asBinder(), callback);logd(CallbackDelegate add callback: MediaProjection(hashCode token.hashCode() ) callback callback , remaining IMediaProjectionCallback for MediaProjection(hashCode token.hashCode() ) count callbacks.size() , remaining IMediaProjectionCallback count mClientCallbacks.size());}}public void add(IMediaProjectionWatcherCallback callback) {synchronized (mLock) {mWatcherCallbacks.put(callback.asBinder(), callback);logd(CallbackDelegate add callback callback.hashCode() , remaining IMediaProjectionWatcherCallback count mWatcherCallbacks.size());}}public void remove(IBinder token, IMediaProjectionCallback callback) {synchronized (mLock) {MapIBinder, IMediaProjectionCallback callbacks mClientCallbacks.get(token);if (callbacks ! null) {callbacks.remove(callback.asBinder());logd(CallbackDelegate remove callback: MediaProjection(hashCode token.hashCode() ) callback callback , remaining IMediaProjectionCallback for MediaProjection(hashCode token.hashCode() ) count callbacks.size() , remaining IMediaProjectionCallback count mClientCallbacks.size());if (callbacks.isEmpty()) {mClientCallbacks.remove(token);}}}}public void remove(IBinder token) {synchronized (mLock) {mClientCallbacks.remove(token);logd(CallbackDelegate remove all callbacks for MediaProjection(hashCode token.hashCode() ));}}public void remove(IMediaProjectionWatcherCallback callback) {synchronized (mLock) {mWatcherCallbacks.remove(callback.asBinder());logd(CallbackDelegate remove callback callback.hashCode() , remaining IMediaProjectionWatcherCallback count mWatcherCallbacks.size());}}public void dispatchStart(MediaProjection projection) {if (projection null) {Slog.e(TAG, Tried to dispatch start notification for a null media projection. Ignoring!);return;}synchronized (mLock) {logd(CallbackDelegate dispatchStart: projection projection.getProjectionInfo() hashCode projection.asBinder().hashCode() , IMediaProjectionWatcherCallback count mWatcherCallbacks.size());for (IMediaProjectionWatcherCallback callback : mWatcherCallbacks.values()) {MediaProjectionInfo info projection.getProjectionInfo();mHandler.post(new WatcherStartCallback(info, callback));}}}public void dispatchStop(MediaProjection projection) {if (projection null) {Slog.e(TAG, Tried to dispatch stop notification for a null media projection. Ignoring!);return;}synchronized (mLock) {logd(CallbackDelegate dispatchStop: projection projection.getProjectionInfo() hashCode projection.asBinder().hashCode() , IMediaProjectionWatcherCallback count mWatcherCallbacks.size() , IMediaProjectionCallback count mClientCallbacks.size());MapIBinder, IMediaProjectionCallback callbacks mClientCallbacks.get(projection.asBinder());if (callbacks ! null) {for (IMediaProjectionCallback cb : callbacks.values()) {logd(CallbackDelegate dispatchStop: post IMediaProjectionCallback cb);mHandler.post(new ClientStopCallback(cb));}}for (IMediaProjectionWatcherCallback callback : mWatcherCallbacks.values()) {MediaProjectionInfo info projection.getProjectionInfo();mHandler.post(new WatcherStopCallback(info, callback));}}}}private static final class WatcherStartCallback implements Runnable {private IMediaProjectionWatcherCallback mCallback;private MediaProjectionInfo mInfo;public WatcherStartCallback(MediaProjectionInfo info,IMediaProjectionWatcherCallback callback) {mInfo info;mCallback callback;}Overridepublic void run() {try {mCallback.onStart(mInfo);} catch (RemoteException e) {Slog.w(TAG, Failed to notify media projection has stopped, e);}}}private static final class WatcherStopCallback implements Runnable {private IMediaProjectionWatcherCallback mCallback;private MediaProjectionInfo mInfo;public WatcherStopCallback(MediaProjectionInfo info,IMediaProjectionWatcherCallback callback) {mInfo info;mCallback callback;}Overridepublic void run() {try {mCallback.onStop(mInfo);} catch (RemoteException e) {Slog.w(TAG, Failed to notify media projection has stopped, e);}}}private static final class ClientStopCallback implements Runnable {private IMediaProjectionCallback mCallback;public ClientStopCallback(IMediaProjectionCallback callback) {mCallback callback;}Overridepublic void run() {try {mCallback.onStop();} catch (RemoteException e) {Slog.w(TAG, Failed to notify media projection has stopped, e);}}}private static String typeToString(int type) {switch (type) {case MediaProjectionManager.TYPE_SCREEN_CAPTURE:return TYPE_SCREEN_CAPTURE;case MediaProjectionManager.TYPE_MIRRORING:return TYPE_MIRRORING;case MediaProjectionManager.TYPE_PRESENTATION:return TYPE_PRESENTATION;}return Integer.toString(type);}private static final class MediaProjectionEntry {private String mUidPid;private IBinder mProjectionToken;private MediaProjection mProjectionGrant;public MediaProjectionEntry(String uidpid, IBinder token, MediaProjection mp) {this.mUidPid uidpid;this.mProjectionToken token;this.mProjectionGrant mp;}public String getUidPid() {return mUidPid;}public IBinder getProjectionToken() {return mProjectionToken;}public MediaProjection getProjectionGrant() {return mProjectionGrant;}public void dump(PrintWriter pw) {pw.println(( mProjectionGrant.packageName , uid_pid mUidPid , token mProjectionToken.hashCode() ): typeToString(mProjectionGrant.mType));}}private MediaProjectionEntry getMediaProjectionEntryByUidPid(String uidpid) {if (mEntryMap null || mEntryMap.isEmpty() || uidpid null || uidpid.length() 0) {return null;}for (MediaProjectionEntry entry : mEntryMap.values()) {if (entry ! null uidpid.equals(entry.getUidPid())) {return entry;}}return null;}private String getCallingUidPid() {int pid Binder.getCallingPid();int uid Binder.getCallingUid();return String.format(%s_%s, uid, pid);}private static void logd(String msg) {logd(TAG, msg);}private static void loge(String msg) {loge(TAG, msg);}private static void logd(String tag, String msg) {if (DEBUG) {Slog.d(tag, msg);}}private static void loge(String tag, String msg) {Slog.e(tag, msg);}}