1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.screenshot; 18 19 import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS; 20 21 import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_COMPLETE; 22 import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI; 23 24 import android.app.Service; 25 import android.content.BroadcastReceiver; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.graphics.Bitmap; 31 import android.graphics.Insets; 32 import android.graphics.Rect; 33 import android.net.Uri; 34 import android.os.Handler; 35 import android.os.IBinder; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.Messenger; 39 import android.os.RemoteException; 40 import android.os.UserManager; 41 import android.util.Log; 42 import android.view.WindowManager; 43 44 import com.android.internal.logging.UiEventLogger; 45 import com.android.internal.util.ScreenshotHelper; 46 import com.android.systemui.shared.recents.utilities.BitmapUtil; 47 48 import java.util.function.Consumer; 49 50 import javax.inject.Inject; 51 52 public class TakeScreenshotService extends Service { 53 private static final String TAG = "TakeScreenshotService"; 54 55 private final GlobalScreenshot mScreenshot; 56 private final UserManager mUserManager; 57 private final UiEventLogger mUiEventLogger; 58 59 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 60 61 @Override 62 public void onReceive(Context context, Intent intent) { 63 if (ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction()) && mScreenshot != null) { 64 mScreenshot.dismissScreenshot("close system dialogs", false); 65 } 66 } 67 }; 68 69 private Handler mHandler = new Handler(Looper.myLooper()) { 70 @Override 71 public void handleMessage(Message msg) { 72 final Messenger callback = msg.replyTo; 73 Consumer<Uri> uriConsumer = uri -> { 74 Message reply = Message.obtain(null, SCREENSHOT_MSG_URI, uri); 75 try { 76 callback.send(reply); 77 } catch (RemoteException e) { 78 } 79 }; 80 Runnable onComplete = () -> { 81 Message reply = Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE); 82 try { 83 callback.send(reply); 84 } catch (RemoteException e) { 85 } 86 }; 87 88 // If the storage for this user is locked, we have no place to store 89 // the screenshot, so skip taking it instead of showing a misleading 90 // animation and error notification. 91 if (!mUserManager.isUserUnlocked()) { 92 Log.w(TAG, "Skipping screenshot because storage is locked!"); 93 post(() -> uriConsumer.accept(null)); 94 post(onComplete); 95 return; 96 } 97 98 ScreenshotHelper.ScreenshotRequest screenshotRequest = 99 (ScreenshotHelper.ScreenshotRequest) msg.obj; 100 101 mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource())); 102 103 switch (msg.what) { 104 case WindowManager.TAKE_SCREENSHOT_FULLSCREEN: 105 mScreenshot.takeScreenshotFullscreen(uriConsumer, onComplete); 106 break; 107 case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION: 108 mScreenshot.takeScreenshotPartial(uriConsumer, onComplete); 109 break; 110 case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE: 111 Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap( 112 screenshotRequest.getBitmapBundle()); 113 Rect screenBounds = screenshotRequest.getBoundsInScreen(); 114 Insets insets = screenshotRequest.getInsets(); 115 int taskId = screenshotRequest.getTaskId(); 116 int userId = screenshotRequest.getUserId(); 117 ComponentName topComponent = screenshotRequest.getTopComponent(); 118 mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets, 119 taskId, userId, topComponent, uriConsumer, onComplete); 120 break; 121 default: 122 Log.d(TAG, "Invalid screenshot option: " + msg.what); 123 } 124 } 125 }; 126 127 @Inject TakeScreenshotService(GlobalScreenshot globalScreenshot, UserManager userManager, UiEventLogger uiEventLogger)128 public TakeScreenshotService(GlobalScreenshot globalScreenshot, UserManager userManager, 129 UiEventLogger uiEventLogger) { 130 mScreenshot = globalScreenshot; 131 mUserManager = userManager; 132 mUiEventLogger = uiEventLogger; 133 } 134 135 @Override onBind(Intent intent)136 public IBinder onBind(Intent intent) { 137 // register broadcast receiver 138 IntentFilter filter = new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS); 139 registerReceiver(mBroadcastReceiver, filter); 140 141 return new Messenger(mHandler).getBinder(); 142 143 } 144 145 @Override onUnbind(Intent intent)146 public boolean onUnbind(Intent intent) { 147 if (mScreenshot != null) mScreenshot.stopScreenshot(); 148 unregisterReceiver(mBroadcastReceiver); 149 return true; 150 } 151 } 152