• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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