1a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlaspackage com.android.internal.util; 2a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 3d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaverimport android.annotation.NonNull; 4a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.content.ComponentName; 5a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.content.Context; 6a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.content.Intent; 7a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.content.ServiceConnection; 8a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.os.Handler; 9a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.os.IBinder; 10a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.os.Message; 11a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.os.Messenger; 12a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.os.RemoteException; 13a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.os.UserHandle; 14a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlasimport android.util.Log; 15a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 16a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlaspublic class ScreenshotHelper { 17a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas private static final String TAG = "ScreenshotHelper"; 18a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 19a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas private static final String SYSUI_PACKAGE = "com.android.systemui"; 20a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas private static final String SYSUI_SCREENSHOT_SERVICE = 21a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas "com.android.systemui.screenshot.TakeScreenshotService"; 22a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER = 23a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver"; 24a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 25a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas // Time until we give up on the screenshot & show an error instead. 26a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas private final int SCREENSHOT_TIMEOUT_MS = 10000; 27a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 28a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas private final Object mScreenshotLock = new Object(); 29a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas private ServiceConnection mScreenshotConnection = null; 30a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas private final Context mContext; 31a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 32a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas public ScreenshotHelper(Context context) { 33a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas mContext = context; 34a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 35a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 36d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver /** 37d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver * Request a screenshot be taken. 38d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver * 39d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver * @param screenshotType The type of screenshot, for example either 40d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver * {@link android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN} 41d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver * or {@link android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION} 42d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver * @param hasStatus {@code true} if the status bar is currently showing. {@code false} if not. 43d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver * @param hasNav {@code true} if the navigation bar is currently showing. {@code false} if not. 44d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver * @param handler A handler used in case the screenshot times out 45d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver */ 46a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas public void takeScreenshot(final int screenshotType, final boolean hasStatus, 47d0429743fa6c3a4ce9dd3b1ec903a0c553e76969Phil Weaver final boolean hasNav, @NonNull Handler handler) { 48a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas synchronized (mScreenshotLock) { 49a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas if (mScreenshotConnection != null) { 50a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas return; 51a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 52a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas final ComponentName serviceComponent = new ComponentName(SYSUI_PACKAGE, 53a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas SYSUI_SCREENSHOT_SERVICE); 54a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas final Intent serviceIntent = new Intent(); 55a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 56a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas final Runnable mScreenshotTimeout = new Runnable() { 57a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas @Override public void run() { 58a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas synchronized (mScreenshotLock) { 59a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas if (mScreenshotConnection != null) { 60a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas mContext.unbindService(mScreenshotConnection); 61a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas mScreenshotConnection = null; 62a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas notifyScreenshotError(); 63a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 64a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 65a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 66a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas }; 67a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 68a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas serviceIntent.setComponent(serviceComponent); 69a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas ServiceConnection conn = new ServiceConnection() { 70a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas @Override 71a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas public void onServiceConnected(ComponentName name, IBinder service) { 72a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas synchronized (mScreenshotLock) { 73a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas if (mScreenshotConnection != this) { 74a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas return; 75a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 76a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas Messenger messenger = new Messenger(service); 77a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas Message msg = Message.obtain(null, screenshotType); 78a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas final ServiceConnection myConn = this; 79a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas Handler h = new Handler(handler.getLooper()) { 80a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas @Override 81a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas public void handleMessage(Message msg) { 82a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas synchronized (mScreenshotLock) { 83a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas if (mScreenshotConnection == myConn) { 84a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas mContext.unbindService(mScreenshotConnection); 85a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas mScreenshotConnection = null; 86a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas handler.removeCallbacks(mScreenshotTimeout); 87a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 88a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 89a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 90a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas }; 91a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas msg.replyTo = new Messenger(h); 92a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas msg.arg1 = hasStatus ? 1: 0; 93a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas msg.arg2 = hasNav ? 1: 0; 94a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas try { 95a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas messenger.send(msg); 96a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } catch (RemoteException e) { 97a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas Log.e(TAG, "Couldn't take screenshot: " + e); 98a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 99a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 100a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 101a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 102a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas @Override 103a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas public void onServiceDisconnected(ComponentName name) { 104a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas synchronized (mScreenshotLock) { 105a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas if (mScreenshotConnection != null) { 106a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas mContext.unbindService(mScreenshotConnection); 107a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas mScreenshotConnection = null; 108a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas handler.removeCallbacks(mScreenshotTimeout); 109a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas notifyScreenshotError(); 110a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 111a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 112a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 113a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas }; 114a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas if (mContext.bindServiceAsUser(serviceIntent, conn, 115a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, 116a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas UserHandle.CURRENT)) { 117a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas mScreenshotConnection = conn; 118a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas handler.postDelayed(mScreenshotTimeout, SCREENSHOT_TIMEOUT_MS); 119a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 120a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 121a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 122a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 123a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas /** 124a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas * Notifies the screenshot service to show an error. 125a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas */ 126a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas private void notifyScreenshotError() { 127a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas // If the service process is killed, then ask it to clean up after itself 128a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas final ComponentName errorComponent = new ComponentName(SYSUI_PACKAGE, 129a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas SYSUI_SCREENSHOT_ERROR_RECEIVER); 130a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas // Broadcast needs to have a valid action. We'll just pick 131a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas // a generic one, since the receiver here doesn't care. 132a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas Intent errorIntent = new Intent(Intent.ACTION_USER_PRESENT); 133a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas errorIntent.setComponent(errorComponent); 134a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas errorIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | 135a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas Intent.FLAG_RECEIVER_FOREGROUND); 136a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas mContext.sendBroadcastAsUser(errorIntent, UserHandle.CURRENT); 137a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas } 138a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas 139a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537Alison Cichowlas} 140