Loading packages/SystemUI/AndroidManifest.xml +3 −7 Original line number Diff line number Diff line Loading @@ -395,19 +395,15 @@ <!-- Springboard for launching the share and edit activity. This needs to be in the main system ui process since we need to notify the status bar to dismiss the keyguard --> <receiver android:name=".screenshot.GlobalScreenshot$ActionProxyReceiver" android:exported="false" /> <!-- Callback for dismissing screenshot notification after a share target is picked --> <receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver" <receiver android:name=".screenshot.ActionProxyReceiver" android:exported="false" /> <!-- Callback for deleting screenshot notification --> <receiver android:name=".screenshot.GlobalScreenshot$DeleteScreenshotReceiver" <receiver android:name=".screenshot.DeleteScreenshotReceiver" android:exported="false" /> <!-- Callback for invoking a smart action from the screenshot notification. --> <receiver android:name=".screenshot.GlobalScreenshot$SmartActionsReceiver" <receiver android:name=".screenshot.SmartActionsReceiver" android:exported="false"/> <!-- started from UsbDeviceSettingsManager --> Loading packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java +25 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,9 @@ package com.android.systemui.dagger; import android.content.BroadcastReceiver; import com.android.systemui.screenshot.GlobalScreenshot.ActionProxyReceiver; import com.android.systemui.screenshot.ActionProxyReceiver; import com.android.systemui.screenshot.DeleteScreenshotReceiver; import com.android.systemui.screenshot.SmartActionsReceiver; import dagger.Binds; import dagger.Module; Loading @@ -30,10 +32,31 @@ import dagger.multibindings.IntoMap; */ @Module public abstract class DefaultBroadcastReceiverBinder { /** */ /** * */ @Binds @IntoMap @ClassKey(ActionProxyReceiver.class) public abstract BroadcastReceiver bindActionProxyReceiver( ActionProxyReceiver broadcastReceiver); /** * */ @Binds @IntoMap @ClassKey(DeleteScreenshotReceiver.class) public abstract BroadcastReceiver bindDeleteScreenshotReceiver( DeleteScreenshotReceiver broadcastReceiver); /** * */ @Binds @IntoMap @ClassKey(SmartActionsReceiver.class) public abstract BroadcastReceiver bindSmartActionsReceiver( SmartActionsReceiver broadcastReceiver); } packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java 0 → 100644 +105 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.screenshot; import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_EDIT; import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_SHARE; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_INTENT; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED; import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; import android.app.ActivityOptions; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.phone.StatusBar; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.inject.Inject; /** * Receiver to proxy the share or edit intent, used to clean up the notification and send * appropriate signals to the system (ie. to dismiss the keyguard if necessary). */ public class ActionProxyReceiver extends BroadcastReceiver { private static final String TAG = "ActionProxyReceiver"; private static final int CLOSE_WINDOWS_TIMEOUT_MILLIS = 3000; private final StatusBar mStatusBar; private final ActivityManagerWrapper mActivityManagerWrapper; private final ScreenshotSmartActions mScreenshotSmartActions; @Inject public ActionProxyReceiver(Optional<StatusBar> statusBar, ActivityManagerWrapper activityManagerWrapper, ScreenshotSmartActions screenshotSmartActions) { mStatusBar = statusBar.orElse(null); mActivityManagerWrapper = activityManagerWrapper; mScreenshotSmartActions = screenshotSmartActions; } @Override public void onReceive(Context context, final Intent intent) { Runnable startActivityRunnable = () -> { try { mActivityManagerWrapper.closeSystemWindows( SYSTEM_DIALOG_REASON_SCREENSHOT).get( CLOSE_WINDOWS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } catch (TimeoutException | InterruptedException | ExecutionException e) { Log.e(TAG, "Unable to share screenshot", e); return; } PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); ActivityOptions opts = ActivityOptions.makeBasic(); opts.setDisallowEnterPictureInPictureWhileLaunching( intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false)); try { actionIntent.send(context, 0, null, null, null, null, opts.toBundle()); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Pending intent canceled", e); } }; if (mStatusBar != null) { mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */); } else { startActivityRunnable.run(); } if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { String actionType = Intent.ACTION_EDIT.equals(intent.getAction()) ? ACTION_TYPE_EDIT : ACTION_TYPE_SHARE; mScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), actionType, false); } } } packages/SystemUI/src/com/android/systemui/screenshot/DeleteImageInBackgroundTask.java→packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java +68 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. Loading @@ -16,28 +16,53 @@ package com.android.systemui.screenshot; import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_DELETE; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED; import static com.android.systemui.screenshot.GlobalScreenshot.SCREENSHOT_URI_ID; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import com.android.systemui.dagger.qualifiers.Background; import java.util.concurrent.Executor; import javax.inject.Inject; /** * An AsyncTask that deletes an image from the media store in the background. * Removes the file at a provided URI. */ class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> { private Context mContext; public class DeleteScreenshotReceiver extends BroadcastReceiver { DeleteImageInBackgroundTask(Context context) { mContext = context; private final ScreenshotSmartActions mScreenshotSmartActions; private final Executor mBackgroundExecutor; @Inject public DeleteScreenshotReceiver(ScreenshotSmartActions screenshotSmartActions, @Background Executor backgroundExecutor) { mScreenshotSmartActions = screenshotSmartActions; mBackgroundExecutor = backgroundExecutor; } @Override protected Void doInBackground(Uri... params) { if (params.length != 1) return null; public void onReceive(Context context, Intent intent) { if (!intent.hasExtra(SCREENSHOT_URI_ID)) { return; } Uri screenshotUri = params[0]; ContentResolver resolver = mContext.getContentResolver(); resolver.delete(screenshotUri, null, null); return null; // And delete the image from the media store final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID)); mBackgroundExecutor.execute(() -> { ContentResolver resolver = context.getContentResolver(); resolver.delete(uri, null, null); }); if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { mScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false); } } } packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +4 −130 Original line number Diff line number Diff line Loading @@ -21,8 +21,6 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; Loading @@ -30,13 +28,10 @@ import android.animation.ValueAnimator; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.Notification; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; Loading @@ -62,7 +57,6 @@ import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Log; import android.util.MathUtils; import android.util.Slog; import android.view.Display; import android.view.KeyEvent; import android.view.LayoutInflater; Loading @@ -87,23 +81,15 @@ import android.widget.Toast; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.phone.StatusBar; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Singleton; import dagger.Lazy; /** * Class for handling device screen shots */ Loading Loading @@ -192,6 +178,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private final UiEventLogger mUiEventLogger; private final Context mContext; private final ScreenshotSmartActions mScreenshotSmartActions; private final WindowManager mWindowManager; private final WindowManager.LayoutParams mWindowLayoutParams; private final Display mDisplay; Loading Loading @@ -247,9 +234,11 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset @Inject public GlobalScreenshot( Context context, @Main Resources resources, ScreenshotSmartActions screenshotSmartActions, ScreenshotNotificationsController screenshotNotificationsController, UiEventLogger uiEventLogger) { mContext = context; mScreenshotSmartActions = screenshotSmartActions; mNotificationsController = screenshotNotificationsController; mUiEventLogger = uiEventLogger; Loading Loading @@ -704,7 +693,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset }); } mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data); mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data); mSaveInBgTask.execute(); } Loading Loading @@ -1116,119 +1105,4 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset return insetDrawable; } } /** * Receiver to proxy the share or edit intent, used to clean up the notification and send * appropriate signals to the system (ie. to dismiss the keyguard if necessary). */ public static class ActionProxyReceiver extends BroadcastReceiver { static final int CLOSE_WINDOWS_TIMEOUT_MILLIS = 3000; private final StatusBar mStatusBar; @Inject public ActionProxyReceiver(Optional<Lazy<StatusBar>> statusBarLazy) { Lazy<StatusBar> statusBar = statusBarLazy.orElse(null); mStatusBar = statusBar != null ? statusBar.get() : null; } @Override public void onReceive(Context context, final Intent intent) { Runnable startActivityRunnable = () -> { try { ActivityManagerWrapper.getInstance().closeSystemWindows( SYSTEM_DIALOG_REASON_SCREENSHOT).get( CLOSE_WINDOWS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } catch (TimeoutException | InterruptedException | ExecutionException e) { Slog.e(TAG, "Unable to share screenshot", e); return; } PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); if (intent.getBooleanExtra(EXTRA_CANCEL_NOTIFICATION, false)) { ScreenshotNotificationsController.cancelScreenshotNotification(context); } ActivityOptions opts = ActivityOptions.makeBasic(); opts.setDisallowEnterPictureInPictureWhileLaunching( intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false)); try { actionIntent.send(context, 0, null, null, null, null, opts.toBundle()); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Pending intent canceled", e); } }; if (mStatusBar != null) { mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */); } else { startActivityRunnable.run(); } if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { String actionType = Intent.ACTION_EDIT.equals(intent.getAction()) ? ACTION_TYPE_EDIT : ACTION_TYPE_SHARE; ScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), actionType, false); } } } /** * Removes the notification for a screenshot after a share target is chosen. */ public static class TargetChosenReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // Clear the notification only after the user has chosen a share action ScreenshotNotificationsController.cancelScreenshotNotification(context); } } /** * Removes the last screenshot. */ public static class DeleteScreenshotReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (!intent.hasExtra(SCREENSHOT_URI_ID)) { return; } // Clear the notification when the image is deleted ScreenshotNotificationsController.cancelScreenshotNotification(context); // And delete the image from the media store final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID)); new DeleteImageInBackgroundTask(context).execute(uri); if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { ScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false); } } } /** * Executes the smart action tapped by the user in the notification. */ public static class SmartActionsReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE); Slog.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent()); ActivityOptions opts = ActivityOptions.makeBasic(); try { pendingIntent.send(context, 0, null, null, null, null, opts.toBundle()); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Pending intent canceled", e); } ScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), actionType, true); } } } Loading
packages/SystemUI/AndroidManifest.xml +3 −7 Original line number Diff line number Diff line Loading @@ -395,19 +395,15 @@ <!-- Springboard for launching the share and edit activity. This needs to be in the main system ui process since we need to notify the status bar to dismiss the keyguard --> <receiver android:name=".screenshot.GlobalScreenshot$ActionProxyReceiver" android:exported="false" /> <!-- Callback for dismissing screenshot notification after a share target is picked --> <receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver" <receiver android:name=".screenshot.ActionProxyReceiver" android:exported="false" /> <!-- Callback for deleting screenshot notification --> <receiver android:name=".screenshot.GlobalScreenshot$DeleteScreenshotReceiver" <receiver android:name=".screenshot.DeleteScreenshotReceiver" android:exported="false" /> <!-- Callback for invoking a smart action from the screenshot notification. --> <receiver android:name=".screenshot.GlobalScreenshot$SmartActionsReceiver" <receiver android:name=".screenshot.SmartActionsReceiver" android:exported="false"/> <!-- started from UsbDeviceSettingsManager --> Loading
packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java +25 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,9 @@ package com.android.systemui.dagger; import android.content.BroadcastReceiver; import com.android.systemui.screenshot.GlobalScreenshot.ActionProxyReceiver; import com.android.systemui.screenshot.ActionProxyReceiver; import com.android.systemui.screenshot.DeleteScreenshotReceiver; import com.android.systemui.screenshot.SmartActionsReceiver; import dagger.Binds; import dagger.Module; Loading @@ -30,10 +32,31 @@ import dagger.multibindings.IntoMap; */ @Module public abstract class DefaultBroadcastReceiverBinder { /** */ /** * */ @Binds @IntoMap @ClassKey(ActionProxyReceiver.class) public abstract BroadcastReceiver bindActionProxyReceiver( ActionProxyReceiver broadcastReceiver); /** * */ @Binds @IntoMap @ClassKey(DeleteScreenshotReceiver.class) public abstract BroadcastReceiver bindDeleteScreenshotReceiver( DeleteScreenshotReceiver broadcastReceiver); /** * */ @Binds @IntoMap @ClassKey(SmartActionsReceiver.class) public abstract BroadcastReceiver bindSmartActionsReceiver( SmartActionsReceiver broadcastReceiver); }
packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java 0 → 100644 +105 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.screenshot; import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_EDIT; import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_SHARE; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_INTENT; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED; import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; import android.app.ActivityOptions; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.phone.StatusBar; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.inject.Inject; /** * Receiver to proxy the share or edit intent, used to clean up the notification and send * appropriate signals to the system (ie. to dismiss the keyguard if necessary). */ public class ActionProxyReceiver extends BroadcastReceiver { private static final String TAG = "ActionProxyReceiver"; private static final int CLOSE_WINDOWS_TIMEOUT_MILLIS = 3000; private final StatusBar mStatusBar; private final ActivityManagerWrapper mActivityManagerWrapper; private final ScreenshotSmartActions mScreenshotSmartActions; @Inject public ActionProxyReceiver(Optional<StatusBar> statusBar, ActivityManagerWrapper activityManagerWrapper, ScreenshotSmartActions screenshotSmartActions) { mStatusBar = statusBar.orElse(null); mActivityManagerWrapper = activityManagerWrapper; mScreenshotSmartActions = screenshotSmartActions; } @Override public void onReceive(Context context, final Intent intent) { Runnable startActivityRunnable = () -> { try { mActivityManagerWrapper.closeSystemWindows( SYSTEM_DIALOG_REASON_SCREENSHOT).get( CLOSE_WINDOWS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } catch (TimeoutException | InterruptedException | ExecutionException e) { Log.e(TAG, "Unable to share screenshot", e); return; } PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); ActivityOptions opts = ActivityOptions.makeBasic(); opts.setDisallowEnterPictureInPictureWhileLaunching( intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false)); try { actionIntent.send(context, 0, null, null, null, null, opts.toBundle()); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Pending intent canceled", e); } }; if (mStatusBar != null) { mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */); } else { startActivityRunnable.run(); } if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { String actionType = Intent.ACTION_EDIT.equals(intent.getAction()) ? ACTION_TYPE_EDIT : ACTION_TYPE_SHARE; mScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), actionType, false); } } }
packages/SystemUI/src/com/android/systemui/screenshot/DeleteImageInBackgroundTask.java→packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java +68 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. Loading @@ -16,28 +16,53 @@ package com.android.systemui.screenshot; import static com.android.systemui.screenshot.GlobalScreenshot.ACTION_TYPE_DELETE; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ID; import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED; import static com.android.systemui.screenshot.GlobalScreenshot.SCREENSHOT_URI_ID; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import com.android.systemui.dagger.qualifiers.Background; import java.util.concurrent.Executor; import javax.inject.Inject; /** * An AsyncTask that deletes an image from the media store in the background. * Removes the file at a provided URI. */ class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> { private Context mContext; public class DeleteScreenshotReceiver extends BroadcastReceiver { DeleteImageInBackgroundTask(Context context) { mContext = context; private final ScreenshotSmartActions mScreenshotSmartActions; private final Executor mBackgroundExecutor; @Inject public DeleteScreenshotReceiver(ScreenshotSmartActions screenshotSmartActions, @Background Executor backgroundExecutor) { mScreenshotSmartActions = screenshotSmartActions; mBackgroundExecutor = backgroundExecutor; } @Override protected Void doInBackground(Uri... params) { if (params.length != 1) return null; public void onReceive(Context context, Intent intent) { if (!intent.hasExtra(SCREENSHOT_URI_ID)) { return; } Uri screenshotUri = params[0]; ContentResolver resolver = mContext.getContentResolver(); resolver.delete(screenshotUri, null, null); return null; // And delete the image from the media store final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID)); mBackgroundExecutor.execute(() -> { ContentResolver resolver = context.getContentResolver(); resolver.delete(uri, null, null); }); if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { mScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false); } } }
packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +4 −130 Original line number Diff line number Diff line Loading @@ -21,8 +21,6 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; Loading @@ -30,13 +28,10 @@ import android.animation.ValueAnimator; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.Notification; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; Loading @@ -62,7 +57,6 @@ import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Log; import android.util.MathUtils; import android.util.Slog; import android.view.Display; import android.view.KeyEvent; import android.view.LayoutInflater; Loading @@ -87,23 +81,15 @@ import android.widget.Toast; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.phone.StatusBar; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Singleton; import dagger.Lazy; /** * Class for handling device screen shots */ Loading Loading @@ -192,6 +178,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private final UiEventLogger mUiEventLogger; private final Context mContext; private final ScreenshotSmartActions mScreenshotSmartActions; private final WindowManager mWindowManager; private final WindowManager.LayoutParams mWindowLayoutParams; private final Display mDisplay; Loading Loading @@ -247,9 +234,11 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset @Inject public GlobalScreenshot( Context context, @Main Resources resources, ScreenshotSmartActions screenshotSmartActions, ScreenshotNotificationsController screenshotNotificationsController, UiEventLogger uiEventLogger) { mContext = context; mScreenshotSmartActions = screenshotSmartActions; mNotificationsController = screenshotNotificationsController; mUiEventLogger = uiEventLogger; Loading Loading @@ -704,7 +693,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset }); } mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data); mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data); mSaveInBgTask.execute(); } Loading Loading @@ -1116,119 +1105,4 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset return insetDrawable; } } /** * Receiver to proxy the share or edit intent, used to clean up the notification and send * appropriate signals to the system (ie. to dismiss the keyguard if necessary). */ public static class ActionProxyReceiver extends BroadcastReceiver { static final int CLOSE_WINDOWS_TIMEOUT_MILLIS = 3000; private final StatusBar mStatusBar; @Inject public ActionProxyReceiver(Optional<Lazy<StatusBar>> statusBarLazy) { Lazy<StatusBar> statusBar = statusBarLazy.orElse(null); mStatusBar = statusBar != null ? statusBar.get() : null; } @Override public void onReceive(Context context, final Intent intent) { Runnable startActivityRunnable = () -> { try { ActivityManagerWrapper.getInstance().closeSystemWindows( SYSTEM_DIALOG_REASON_SCREENSHOT).get( CLOSE_WINDOWS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } catch (TimeoutException | InterruptedException | ExecutionException e) { Slog.e(TAG, "Unable to share screenshot", e); return; } PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); if (intent.getBooleanExtra(EXTRA_CANCEL_NOTIFICATION, false)) { ScreenshotNotificationsController.cancelScreenshotNotification(context); } ActivityOptions opts = ActivityOptions.makeBasic(); opts.setDisallowEnterPictureInPictureWhileLaunching( intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false)); try { actionIntent.send(context, 0, null, null, null, null, opts.toBundle()); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Pending intent canceled", e); } }; if (mStatusBar != null) { mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */); } else { startActivityRunnable.run(); } if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { String actionType = Intent.ACTION_EDIT.equals(intent.getAction()) ? ACTION_TYPE_EDIT : ACTION_TYPE_SHARE; ScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), actionType, false); } } } /** * Removes the notification for a screenshot after a share target is chosen. */ public static class TargetChosenReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // Clear the notification only after the user has chosen a share action ScreenshotNotificationsController.cancelScreenshotNotification(context); } } /** * Removes the last screenshot. */ public static class DeleteScreenshotReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (!intent.hasExtra(SCREENSHOT_URI_ID)) { return; } // Clear the notification when the image is deleted ScreenshotNotificationsController.cancelScreenshotNotification(context); // And delete the image from the media store final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID)); new DeleteImageInBackgroundTask(context).execute(uri); if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { ScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false); } } } /** * Executes the smart action tapped by the user in the notification. */ public static class SmartActionsReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE); Slog.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent()); ActivityOptions opts = ActivityOptions.makeBasic(); try { pendingIntent.send(context, 0, null, null, null, null, opts.toBundle()); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Pending intent canceled", e); } ScreenshotSmartActions.notifyScreenshotAction( context, intent.getStringExtra(EXTRA_ID), actionType, true); } } }