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