• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
20 import static com.android.systemui.screenshot.LogConfig.logTag;
21 import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType;
22 
23 import android.app.ActivityManager;
24 import android.app.Notification;
25 import android.content.ComponentName;
26 import android.content.Intent;
27 import android.graphics.Bitmap;
28 import android.net.Uri;
29 import android.os.SystemClock;
30 import android.os.UserHandle;
31 import android.util.Log;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.systemui.dagger.SysUISingleton;
35 import com.android.systemui.shared.system.ActivityManagerWrapper;
36 
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.concurrent.CompletableFuture;
40 import java.util.concurrent.TimeUnit;
41 import java.util.concurrent.TimeoutException;
42 
43 import javax.inject.Inject;
44 import javax.inject.Provider;
45 
46 /**
47  * Collects the static functions for retrieving and acting on smart actions.
48  */
49 @SysUISingleton
50 public class ScreenshotSmartActions {
51     private static final String TAG = logTag(ScreenshotSmartActions.class);
52     private final Provider<ScreenshotNotificationSmartActionsProvider>
53             mScreenshotNotificationSmartActionsProviderProvider;
54 
55     @Inject
ScreenshotSmartActions( Provider<ScreenshotNotificationSmartActionsProvider> screenshotNotificationSmartActionsProviderProvider )56     public ScreenshotSmartActions(
57             Provider<ScreenshotNotificationSmartActionsProvider>
58                     screenshotNotificationSmartActionsProviderProvider
59     ) {
60         mScreenshotNotificationSmartActionsProviderProvider =
61                 screenshotNotificationSmartActionsProviderProvider;
62     }
63 
64     @VisibleForTesting
getSmartActionsFuture( String screenshotId, Uri screenshotUri, Bitmap image, ScreenshotNotificationSmartActionsProvider smartActionsProvider, ScreenshotSmartActionType actionType, boolean smartActionsEnabled, UserHandle userHandle)65     CompletableFuture<List<Notification.Action>> getSmartActionsFuture(
66             String screenshotId, Uri screenshotUri, Bitmap image,
67             ScreenshotNotificationSmartActionsProvider smartActionsProvider,
68             ScreenshotSmartActionType actionType,
69             boolean smartActionsEnabled, UserHandle userHandle) {
70         if (DEBUG_ACTIONS) {
71             Log.d(TAG, String.format(
72                     "getSmartActionsFuture id=%s, uri=%s, provider=%s, actionType=%s, "
73                             + "smartActionsEnabled=%b, userHandle=%s",
74                     screenshotId, screenshotUri, smartActionsProvider.getClass(), actionType,
75                     smartActionsEnabled, userHandle));
76         }
77         if (!smartActionsEnabled) {
78             if (DEBUG_ACTIONS) {
79                 Log.d(TAG, "Screenshot Intelligence not enabled, returning empty list.");
80             }
81             return CompletableFuture.completedFuture(Collections.emptyList());
82         }
83         if (image.getConfig() != Bitmap.Config.HARDWARE) {
84             if (DEBUG_ACTIONS) {
85                 Log.d(TAG, String.format("Bitmap expected: Hardware, Bitmap found: %s. "
86                                 + "Returning empty list.", image.getConfig()));
87             }
88             return CompletableFuture.completedFuture(Collections.emptyList());
89         }
90         CompletableFuture<List<Notification.Action>> smartActionsFuture;
91         long startTimeMs = SystemClock.uptimeMillis();
92         try {
93             ActivityManager.RunningTaskInfo runningTask =
94                     ActivityManagerWrapper.getInstance().getRunningTask();
95             ComponentName componentName =
96                     (runningTask != null && runningTask.topActivity != null)
97                             ? runningTask.topActivity
98                             : new ComponentName("", "");
99             smartActionsFuture = smartActionsProvider.getActions(screenshotId, screenshotUri, image,
100                     componentName, actionType, userHandle);
101         } catch (Throwable e) {
102             long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
103             smartActionsFuture = CompletableFuture.completedFuture(Collections.emptyList());
104             if (DEBUG_ACTIONS) {
105                 Log.e(TAG, "Failed to get future for screenshot notification smart actions.", e);
106             }
107             notifyScreenshotOp(screenshotId, smartActionsProvider,
108                     ScreenshotNotificationSmartActionsProvider.ScreenshotOp.REQUEST_SMART_ACTIONS,
109                     ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR,
110                     waitTimeMs);
111         }
112         return smartActionsFuture;
113     }
114 
115     @VisibleForTesting
getSmartActions(String screenshotId, CompletableFuture<List<Notification.Action>> smartActionsFuture, int timeoutMs, ScreenshotNotificationSmartActionsProvider smartActionsProvider, ScreenshotSmartActionType actionType)116     List<Notification.Action> getSmartActions(String screenshotId,
117             CompletableFuture<List<Notification.Action>> smartActionsFuture, int timeoutMs,
118             ScreenshotNotificationSmartActionsProvider smartActionsProvider,
119             ScreenshotSmartActionType actionType) {
120         long startTimeMs = SystemClock.uptimeMillis();
121         if (DEBUG_ACTIONS) {
122             Log.d(TAG,
123                     String.format("getSmartActions id=%s, timeoutMs=%d, actionType=%s, provider=%s",
124                             screenshotId, timeoutMs, actionType, smartActionsProvider.getClass()));
125         }
126         try {
127             List<Notification.Action> actions = smartActionsFuture.get(timeoutMs,
128                     TimeUnit.MILLISECONDS);
129             long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
130             if (DEBUG_ACTIONS) {
131                 Log.d(TAG, String.format("Got %d smart actions. Wait time: %d ms, actionType=%s",
132                         actions.size(), waitTimeMs, actionType));
133             }
134             notifyScreenshotOp(screenshotId, smartActionsProvider,
135                     ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS,
136                     ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.SUCCESS,
137                     waitTimeMs);
138             return actions;
139         } catch (Throwable e) {
140             long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
141             if (DEBUG_ACTIONS) {
142                 Log.e(TAG, String.format(
143                         "Error getting smart actions. Wait time: %d ms, actionType=%s",
144                         waitTimeMs, actionType), e);
145             }
146             ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status =
147                     (e instanceof TimeoutException)
148                             ? ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.TIMEOUT
149                             : ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR;
150             notifyScreenshotOp(screenshotId, smartActionsProvider,
151                     ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS,
152                     status, waitTimeMs);
153             return Collections.emptyList();
154         }
155     }
156 
notifyScreenshotOp(String screenshotId, ScreenshotNotificationSmartActionsProvider smartActionsProvider, ScreenshotNotificationSmartActionsProvider.ScreenshotOp op, ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status, long durationMs)157     void notifyScreenshotOp(String screenshotId,
158             ScreenshotNotificationSmartActionsProvider smartActionsProvider,
159             ScreenshotNotificationSmartActionsProvider.ScreenshotOp op,
160             ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status, long durationMs) {
161         if (DEBUG_ACTIONS) {
162             Log.d(TAG, String.format("%s notifyOp: %s id=%s, status=%s, durationMs=%d",
163                     smartActionsProvider.getClass(), op, screenshotId, status, durationMs));
164         }
165         try {
166             smartActionsProvider.notifyOp(screenshotId, op, status, durationMs);
167         } catch (Throwable e) {
168             Log.e(TAG, "Error in notifyScreenshotOp: ", e);
169         }
170     }
171 
notifyScreenshotAction(String screenshotId, String action, boolean isSmartAction, Intent intent)172     void notifyScreenshotAction(String screenshotId, String action,
173             boolean isSmartAction, Intent intent) {
174         try {
175             ScreenshotNotificationSmartActionsProvider provider =
176                     mScreenshotNotificationSmartActionsProviderProvider.get();
177             if (DEBUG_ACTIONS) {
178                 Log.d(TAG, String.format("%s notifyAction: %s id=%s, isSmartAction=%b",
179                         provider.getClass(), action, screenshotId, isSmartAction));
180             }
181             provider.notifyAction(screenshotId, action, isSmartAction, intent);
182         } catch (Throwable e) {
183             Log.e(TAG, "Error in notifyScreenshotAction: ", e);
184         }
185     }
186 }
187