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 android.os.AsyncTask.THREAD_POOL_EXECUTOR; 20 21 import android.app.ActivityManager; 22 import android.app.Notification; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.graphics.Bitmap; 26 import android.net.Uri; 27 import android.os.Handler; 28 import android.os.SystemClock; 29 import android.os.UserHandle; 30 import android.util.Slog; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.systemui.SystemUIFactory; 34 import com.android.systemui.shared.system.ActivityManagerWrapper; 35 36 import java.util.Collections; 37 import java.util.List; 38 import java.util.concurrent.CompletableFuture; 39 import java.util.concurrent.TimeUnit; 40 import java.util.concurrent.TimeoutException; 41 42 /** 43 * Collects the static functions for retrieving and acting on smart actions. 44 */ 45 public class ScreenshotSmartActions { 46 private static final String TAG = "ScreenshotSmartActions"; 47 48 @VisibleForTesting getSmartActionsFuture( String screenshotId, Uri screenshotUri, Bitmap image, ScreenshotNotificationSmartActionsProvider smartActionsProvider, boolean smartActionsEnabled, UserHandle userHandle)49 static CompletableFuture<List<Notification.Action>> getSmartActionsFuture( 50 String screenshotId, Uri screenshotUri, Bitmap image, 51 ScreenshotNotificationSmartActionsProvider smartActionsProvider, 52 boolean smartActionsEnabled, UserHandle userHandle) { 53 if (!smartActionsEnabled) { 54 Slog.i(TAG, "Screenshot Intelligence not enabled, returning empty list."); 55 return CompletableFuture.completedFuture(Collections.emptyList()); 56 } 57 if (image.getConfig() != Bitmap.Config.HARDWARE) { 58 Slog.w(TAG, String.format( 59 "Bitmap expected: Hardware, Bitmap found: %s. Returning empty list.", 60 image.getConfig())); 61 return CompletableFuture.completedFuture(Collections.emptyList()); 62 } 63 64 Slog.d(TAG, "Screenshot from user profile: " + userHandle.getIdentifier()); 65 CompletableFuture<List<Notification.Action>> smartActionsFuture; 66 long startTimeMs = SystemClock.uptimeMillis(); 67 try { 68 ActivityManager.RunningTaskInfo runningTask = 69 ActivityManagerWrapper.getInstance().getRunningTask(); 70 ComponentName componentName = 71 (runningTask != null && runningTask.topActivity != null) 72 ? runningTask.topActivity 73 : new ComponentName("", ""); 74 smartActionsFuture = smartActionsProvider.getActions( 75 screenshotId, screenshotUri, image, componentName, userHandle); 76 } catch (Throwable e) { 77 long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; 78 smartActionsFuture = CompletableFuture.completedFuture(Collections.emptyList()); 79 Slog.e(TAG, "Failed to get future for screenshot notification smart actions.", e); 80 notifyScreenshotOp(screenshotId, smartActionsProvider, 81 ScreenshotNotificationSmartActionsProvider.ScreenshotOp.REQUEST_SMART_ACTIONS, 82 ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR, 83 waitTimeMs); 84 } 85 return smartActionsFuture; 86 } 87 88 @VisibleForTesting getSmartActions(String screenshotId, CompletableFuture<List<Notification.Action>> smartActionsFuture, int timeoutMs, ScreenshotNotificationSmartActionsProvider smartActionsProvider)89 static List<Notification.Action> getSmartActions(String screenshotId, 90 CompletableFuture<List<Notification.Action>> smartActionsFuture, int timeoutMs, 91 ScreenshotNotificationSmartActionsProvider smartActionsProvider) { 92 long startTimeMs = SystemClock.uptimeMillis(); 93 try { 94 List<Notification.Action> actions = smartActionsFuture.get(timeoutMs, 95 TimeUnit.MILLISECONDS); 96 long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; 97 Slog.d(TAG, String.format("Got %d smart actions. Wait time: %d ms", 98 actions.size(), waitTimeMs)); 99 notifyScreenshotOp(screenshotId, smartActionsProvider, 100 ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS, 101 ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.SUCCESS, 102 waitTimeMs); 103 return actions; 104 } catch (Throwable e) { 105 long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; 106 Slog.e(TAG, String.format("Error getting smart actions. Wait time: %d ms", waitTimeMs), 107 e); 108 ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status = 109 (e instanceof TimeoutException) 110 ? ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.TIMEOUT 111 : ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR; 112 notifyScreenshotOp(screenshotId, smartActionsProvider, 113 ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS, 114 status, waitTimeMs); 115 return Collections.emptyList(); 116 } 117 } 118 notifyScreenshotOp(String screenshotId, ScreenshotNotificationSmartActionsProvider smartActionsProvider, ScreenshotNotificationSmartActionsProvider.ScreenshotOp op, ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status, long durationMs)119 static void notifyScreenshotOp(String screenshotId, 120 ScreenshotNotificationSmartActionsProvider smartActionsProvider, 121 ScreenshotNotificationSmartActionsProvider.ScreenshotOp op, 122 ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status, long durationMs) { 123 try { 124 smartActionsProvider.notifyOp(screenshotId, op, status, durationMs); 125 } catch (Throwable e) { 126 Slog.e(TAG, "Error in notifyScreenshotOp: ", e); 127 } 128 } 129 notifyScreenshotAction(Context context, String screenshotId, String action, boolean isSmartAction)130 static void notifyScreenshotAction(Context context, String screenshotId, String action, 131 boolean isSmartAction) { 132 try { 133 ScreenshotNotificationSmartActionsProvider provider = 134 SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider( 135 context, THREAD_POOL_EXECUTOR, new Handler()); 136 provider.notifyAction(screenshotId, action, isSmartAction); 137 } catch (Throwable e) { 138 Slog.e(TAG, "Error in notifyScreenshotAction: ", e); 139 } 140 } 141 } 142