Loading packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +0 −131 Original line number Diff line number Diff line Loading @@ -44,7 +44,6 @@ import android.app.ICompatCameraControlCallback; import android.app.Notification; import android.app.assist.AssistContent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading Loading @@ -525,39 +524,6 @@ public class ScreenshotController { mWindowManager.getCurrentWindowMetrics().getWindowInsets()); } @MainThread void takeScreenshotFullscreen(ComponentName topComponent, Consumer<Uri> finisher, RequestCallback requestCallback) { Assert.isMainThread(); mCurrentRequestCallback = requestCallback; takeScreenshotInternal(topComponent, finisher, getFullScreenRect()); } @MainThread void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds, Insets visibleInsets, int taskId, int userId, ComponentName topComponent, Consumer<Uri> finisher, RequestCallback requestCallback) { Assert.isMainThread(); if (screenshot == null) { Log.e(TAG, "Got null bitmap from screenshot message"); mNotificationsController.notifyScreenshotError( R.string.screenshot_failed_to_capture_text); requestCallback.reportError(); return; } boolean showFlash = false; if (screenshotScreenBounds == null || !aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) { showFlash = true; visibleInsets = Insets.NONE; screenshotScreenBounds = new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()); } mCurrentRequestCallback = requestCallback; saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, topComponent, showFlash, UserHandle.of(userId)); } /** * Clears current screenshot */ Loading Loading @@ -695,103 +661,6 @@ public class ScreenshotController { setContentView(mScreenshotView); } /** * Takes a screenshot of the current display and shows an animation. */ private void takeScreenshotInternal(ComponentName topComponent, Consumer<Uri> finisher, Rect crop) { mScreenshotTakenInPortrait = mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT; // copy the input Rect, since SurfaceControl.screenshot can mutate it Rect screenRect = new Rect(crop); Bitmap screenshot = mImageCapture.captureDisplay(mDisplayTracker.getDefaultDisplayId(), crop); if (screenshot == null) { Log.e(TAG, "takeScreenshotInternal: Screenshot bitmap was null"); mNotificationsController.notifyScreenshotError( R.string.screenshot_failed_to_capture_text); if (mCurrentRequestCallback != null) { mCurrentRequestCallback.reportError(); } return; } saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, topComponent, true, Process.myUserHandle()); mBroadcastSender.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION), ClipboardOverlayController.SELF_PERMISSION); } private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect, Insets screenInsets, ComponentName topComponent, boolean showFlash, UserHandle owner) { withWindowAttached(() -> { if (mUserManager.isManagedProfile(owner.getIdentifier())) { mScreenshotView.announceForAccessibility(mContext.getResources().getString( R.string.screenshot_saving_work_profile_title)); } else { mScreenshotView.announceForAccessibility( mContext.getResources().getString(R.string.screenshot_saving_title)); } }); mScreenshotView.reset(); if (mScreenshotView.isAttachedToWindow()) { // if we didn't already dismiss for another reason if (!mScreenshotView.isDismissing()) { mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED, 0, mPackageName); } if (DEBUG_WINDOW) { Log.d(TAG, "saveScreenshot: screenshotView is already attached, resetting. " + "(dismissing=" + mScreenshotView.isDismissing() + ")"); } } mPackageName = topComponent == null ? "" : topComponent.getPackageName(); mScreenshotView.setPackageName(mPackageName); mScreenshotView.updateOrientation( mWindowManager.getCurrentWindowMetrics().getWindowInsets()); mScreenBitmap = screenshot; if (!isUserSetupComplete(owner)) { Log.w(TAG, "User setup not complete, displaying toast only"); // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing // and sharing shouldn't be exposed to the user. saveScreenshotAndToast(owner, finisher); return; } // Optimizations mScreenBitmap.setHasAlpha(false); mScreenBitmap.prepareToDraw(); saveScreenshotInWorkerThread(owner, finisher, this::showUiOnActionsReady, this::showUiOnQuickShareActionReady); // The window is focusable by default setWindowFocusable(true); mScreenshotView.requestFocus(); enqueueScrollCaptureRequest(owner); attachWindow(); prepareAnimation(screenRect, showFlash, () -> { mMessageContainerController.onScreenshotTaken(owner); }); mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon( mContext.getDrawable(R.drawable.overlay_badge_background), owner)); mScreenshotView.setScreenshot(mScreenBitmap, screenInsets); // ignore system bar insets for the purpose of window layout mWindow.getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> WindowInsets.CONSUMED); mScreenshotHandler.cancelTimeout(); // restarted after animation } private void prepareAnimation(Rect screenRect, boolean showFlash, Runnable onAnimationComplete) { mScreenshotView.getViewTreeObserver().addOnPreDrawListener( Loading packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java +11 −61 Original line number Diff line number Diff line Loading @@ -36,9 +36,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.Rect; import android.net.Uri; import android.os.Handler; import android.os.IBinder; Loading @@ -49,7 +46,6 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import android.view.WindowManager; import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; Loading @@ -58,7 +54,6 @@ import com.android.internal.util.ScreenshotRequest; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import java.util.concurrent.Executor; import java.util.function.Consumer; Loading Loading @@ -222,7 +217,6 @@ public class TakeScreenshotService extends Service { return; } if (mFeatureFlags.isEnabled(Flags.SCREENSHOT_METADATA_REFACTOR)) { Log.d(TAG, "Processing screenshot data"); ScreenshotData screenshotData = ScreenshotData.fromRequest(request); try { Loading @@ -235,18 +229,6 @@ public class TakeScreenshotService extends Service { R.string.screenshot_failed_to_capture_text); callback.reportError(); } } else { try { mProcessor.processAsync(request, (r) -> dispatchToController(r, onSaved, callback)); } catch (IllegalStateException e) { Log.e(TAG, "Failed to process screenshot request!", e); logFailedRequest(request); mNotificationsController.notifyScreenshotError( R.string.screenshot_failed_to_capture_text); callback.reportError(); } } } private void dispatchToController(ScreenshotData screenshot, Loading @@ -257,38 +239,6 @@ public class TakeScreenshotService extends Service { mScreenshot.handleScreenshot(screenshot, uriConsumer, callback); } private void dispatchToController(ScreenshotRequest request, Consumer<Uri> uriConsumer, RequestCallback callback) { ComponentName topComponent = request.getTopComponent(); String packageName = topComponent == null ? "" : topComponent.getPackageName(); mUiEventLogger.log( ScreenshotEvent.getScreenshotSource(request.getSource()), 0, packageName); switch (request.getType()) { case WindowManager.TAKE_SCREENSHOT_FULLSCREEN: if (DEBUG_SERVICE) { Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_FULLSCREEN"); } mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, callback); break; case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE: if (DEBUG_SERVICE) { Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE"); } Bitmap screenshot = request.getBitmap(); Rect screenBounds = request.getBoundsInScreen(); Insets insets = request.getInsets(); int taskId = request.getTaskId(); int userId = request.getUserId(); mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets, taskId, userId, topComponent, uriConsumer, callback); break; default: Log.wtf(TAG, "Invalid screenshot option: " + request.getType()); } } private void logFailedRequest(ScreenshotRequest request) { ComponentName topComponent = request.getTopComponent(); String packageName = topComponent == null ? "" : topComponent.getPackageName(); Loading packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt +0 −230 Original line number Diff line number Diff line Loading @@ -23,28 +23,21 @@ import android.content.ComponentName import android.graphics.Bitmap import android.graphics.Bitmap.Config.HARDWARE import android.graphics.ColorSpace import android.graphics.Insets import android.graphics.Rect import android.hardware.HardwareBuffer import android.os.UserHandle import android.os.UserManager import android.testing.AndroidTestingRunner import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.util.ScreenshotRequest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.SCREENSHOT_METADATA_REFACTOR import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_OVERVIEW import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argThat import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever Loading @@ -61,9 +54,6 @@ import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyZeroInteractions private const val USER_ID = 1 private const val TASK_ID = 11 @RunWith(AndroidTestingRunner::class) @SmallTest class TakeScreenshotServiceTest : SysuiTestCase() { Loading Loading @@ -123,9 +113,6 @@ class TakeScreenshotServiceTest : SysuiTestCase() { .whenever(requestProcessor) .processAsync(/* screenshot= */ any(ScreenshotData::class.java), /* callback= */ any()) // Flipped in selected test cases flags.set(SCREENSHOT_METADATA_REFACTOR, false) service.attach( mContext, /* thread = */ null, Loading Loading @@ -157,39 +144,6 @@ class TakeScreenshotServiceTest : SysuiTestCase() { service.handleRequest(request, { /* onSaved */}, callback) verify(controller, times(1)) .takeScreenshotFullscreen( eq(topComponent), /* onSavedListener = */ any(), /* requestCallback = */ any() ) assertEquals("Expected one UiEvent", 1, eventLogger.numLogs()) val logEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED UiEvent", logEvent.eventId, SCREENSHOT_REQUESTED_KEY_OTHER.id ) assertEquals( "Expected supplied package name", topComponent.packageName, eventLogger.get(0).packageName ) } @Test fun takeScreenshotFullscreen_screenshotDataEnabled() { flags.set(SCREENSHOT_METADATA_REFACTOR, true) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) .build() service.handleRequest(request, { /* onSaved */}, callback) verify(controller, times(1)) .handleScreenshot( eq(ScreenshotData.fromRequest(request)), Loading @@ -212,54 +166,8 @@ class TakeScreenshotServiceTest : SysuiTestCase() { ) } @Test fun takeScreenshotProvidedImage() { val bounds = Rect(50, 50, 150, 150) val bitmap = makeHardwareBitmap(100, 100) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OVERVIEW) .setTopComponent(topComponent) .setTaskId(TASK_ID) .setUserId(USER_ID) .setBitmap(bitmap) .setBoundsOnScreen(bounds) .setInsets(Insets.NONE) .build() service.handleRequest(request, { /* onSaved */}, callback) verify(controller, times(1)) .handleImageAsScreenshot( argThat { b -> b.equalsHardwareBitmap(bitmap) }, eq(bounds), eq(Insets.NONE), eq(TASK_ID), eq(USER_ID), eq(topComponent), /* onSavedListener = */ any(), /* requestCallback = */ any() ) assertEquals("Expected one UiEvent", 1, eventLogger.numLogs()) val logEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED_* UiEvent", logEvent.eventId, SCREENSHOT_REQUESTED_OVERVIEW.id ) assertEquals( "Expected supplied package name", topComponent.packageName, eventLogger.get(0).packageName ) } @Test fun takeScreenshotFullscreen_userLocked() { flags.set(SCREENSHOT_METADATA_REFACTOR, true) whenever(userManager.isUserUnlocked).thenReturn(false) val request = Loading Loading @@ -300,100 +208,6 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshotFullscreen_screenCaptureDisabled_allUsers() { flags.set(SCREENSHOT_METADATA_REFACTOR, true) whenever(devicePolicyManager.getScreenCaptureDisabled(isNull(), eq(UserHandle.USER_ALL))) .thenReturn(true) whenever( devicePolicyResourcesManager.getString( eq(SCREENSHOT_BLOCKED_BY_ADMIN), /* Supplier<String> */ any(), ) ) .thenReturn("SCREENSHOT_BLOCKED_BY_ADMIN") val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) .build() service.handleRequest(request, { /* onSaved */}, callback) // error shown: Toast.makeText(...).show(), untestable verify(callback, times(1)).reportError() verifyZeroInteractions(controller) assertEquals("Expected two UiEvents", 2, eventLogger.numLogs()) val requestEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED_* UiEvent", SCREENSHOT_REQUESTED_KEY_OTHER.id, requestEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, requestEvent.packageName ) val failureEvent = eventLogger.get(1) assertEquals( "Expected SCREENSHOT_CAPTURE_FAILED UiEvent", SCREENSHOT_CAPTURE_FAILED.id, failureEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, failureEvent.packageName ) } @Test fun takeScreenshotFullscreen_userLocked_metadataDisabled() { flags.set(SCREENSHOT_METADATA_REFACTOR, false) whenever(userManager.isUserUnlocked).thenReturn(false) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) .build() service.handleRequest(request, { /* onSaved */}, callback) verify(notificationsController, times(1)).notifyScreenshotError(anyInt()) verify(callback, times(1)).reportError() verifyZeroInteractions(controller) assertEquals("Expected two UiEvents", 2, eventLogger.numLogs()) val requestEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED_* UiEvent", SCREENSHOT_REQUESTED_KEY_OTHER.id, requestEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, requestEvent.packageName ) val failureEvent = eventLogger.get(1) assertEquals( "Expected SCREENSHOT_CAPTURE_FAILED UiEvent", SCREENSHOT_CAPTURE_FAILED.id, failureEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, failureEvent.packageName ) } @Test fun takeScreenshotFullscreen_screenCaptureDisabled_allUsers_metadataDisabled() { flags.set(SCREENSHOT_METADATA_REFACTOR, false) whenever(devicePolicyManager.getScreenCaptureDisabled(isNull(), eq(UserHandle.USER_ALL))) .thenReturn(true) Loading Loading @@ -441,52 +255,8 @@ class TakeScreenshotServiceTest : SysuiTestCase() { ) } @Test fun takeScreenshot_workProfile_nullBitmap_metadataDisabled() { flags.set(SCREENSHOT_METADATA_REFACTOR, false) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) .build() doThrow(IllegalStateException::class.java) .whenever(requestProcessor) .processAsync(any(ScreenshotRequest::class.java), any()) service.handleRequest(request, { /* onSaved */}, callback) verify(callback, times(1)).reportError() verify(notificationsController, times(1)).notifyScreenshotError(anyInt()) verifyZeroInteractions(controller) assertEquals("Expected two UiEvents", 2, eventLogger.numLogs()) val requestEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED_* UiEvent", SCREENSHOT_REQUESTED_KEY_OTHER.id, requestEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, requestEvent.packageName ) val failureEvent = eventLogger.get(1) assertEquals( "Expected SCREENSHOT_CAPTURE_FAILED UiEvent", SCREENSHOT_CAPTURE_FAILED.id, failureEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, failureEvent.packageName ) } @Test fun takeScreenshot_workProfile_nullBitmap() { flags.set(SCREENSHOT_METADATA_REFACTOR, true) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) Loading Loading
packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +0 −131 Original line number Diff line number Diff line Loading @@ -44,7 +44,6 @@ import android.app.ICompatCameraControlCallback; import android.app.Notification; import android.app.assist.AssistContent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading Loading @@ -525,39 +524,6 @@ public class ScreenshotController { mWindowManager.getCurrentWindowMetrics().getWindowInsets()); } @MainThread void takeScreenshotFullscreen(ComponentName topComponent, Consumer<Uri> finisher, RequestCallback requestCallback) { Assert.isMainThread(); mCurrentRequestCallback = requestCallback; takeScreenshotInternal(topComponent, finisher, getFullScreenRect()); } @MainThread void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds, Insets visibleInsets, int taskId, int userId, ComponentName topComponent, Consumer<Uri> finisher, RequestCallback requestCallback) { Assert.isMainThread(); if (screenshot == null) { Log.e(TAG, "Got null bitmap from screenshot message"); mNotificationsController.notifyScreenshotError( R.string.screenshot_failed_to_capture_text); requestCallback.reportError(); return; } boolean showFlash = false; if (screenshotScreenBounds == null || !aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) { showFlash = true; visibleInsets = Insets.NONE; screenshotScreenBounds = new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()); } mCurrentRequestCallback = requestCallback; saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, topComponent, showFlash, UserHandle.of(userId)); } /** * Clears current screenshot */ Loading Loading @@ -695,103 +661,6 @@ public class ScreenshotController { setContentView(mScreenshotView); } /** * Takes a screenshot of the current display and shows an animation. */ private void takeScreenshotInternal(ComponentName topComponent, Consumer<Uri> finisher, Rect crop) { mScreenshotTakenInPortrait = mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT; // copy the input Rect, since SurfaceControl.screenshot can mutate it Rect screenRect = new Rect(crop); Bitmap screenshot = mImageCapture.captureDisplay(mDisplayTracker.getDefaultDisplayId(), crop); if (screenshot == null) { Log.e(TAG, "takeScreenshotInternal: Screenshot bitmap was null"); mNotificationsController.notifyScreenshotError( R.string.screenshot_failed_to_capture_text); if (mCurrentRequestCallback != null) { mCurrentRequestCallback.reportError(); } return; } saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, topComponent, true, Process.myUserHandle()); mBroadcastSender.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION), ClipboardOverlayController.SELF_PERMISSION); } private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect, Insets screenInsets, ComponentName topComponent, boolean showFlash, UserHandle owner) { withWindowAttached(() -> { if (mUserManager.isManagedProfile(owner.getIdentifier())) { mScreenshotView.announceForAccessibility(mContext.getResources().getString( R.string.screenshot_saving_work_profile_title)); } else { mScreenshotView.announceForAccessibility( mContext.getResources().getString(R.string.screenshot_saving_title)); } }); mScreenshotView.reset(); if (mScreenshotView.isAttachedToWindow()) { // if we didn't already dismiss for another reason if (!mScreenshotView.isDismissing()) { mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED, 0, mPackageName); } if (DEBUG_WINDOW) { Log.d(TAG, "saveScreenshot: screenshotView is already attached, resetting. " + "(dismissing=" + mScreenshotView.isDismissing() + ")"); } } mPackageName = topComponent == null ? "" : topComponent.getPackageName(); mScreenshotView.setPackageName(mPackageName); mScreenshotView.updateOrientation( mWindowManager.getCurrentWindowMetrics().getWindowInsets()); mScreenBitmap = screenshot; if (!isUserSetupComplete(owner)) { Log.w(TAG, "User setup not complete, displaying toast only"); // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing // and sharing shouldn't be exposed to the user. saveScreenshotAndToast(owner, finisher); return; } // Optimizations mScreenBitmap.setHasAlpha(false); mScreenBitmap.prepareToDraw(); saveScreenshotInWorkerThread(owner, finisher, this::showUiOnActionsReady, this::showUiOnQuickShareActionReady); // The window is focusable by default setWindowFocusable(true); mScreenshotView.requestFocus(); enqueueScrollCaptureRequest(owner); attachWindow(); prepareAnimation(screenRect, showFlash, () -> { mMessageContainerController.onScreenshotTaken(owner); }); mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon( mContext.getDrawable(R.drawable.overlay_badge_background), owner)); mScreenshotView.setScreenshot(mScreenBitmap, screenInsets); // ignore system bar insets for the purpose of window layout mWindow.getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> WindowInsets.CONSUMED); mScreenshotHandler.cancelTimeout(); // restarted after animation } private void prepareAnimation(Rect screenRect, boolean showFlash, Runnable onAnimationComplete) { mScreenshotView.getViewTreeObserver().addOnPreDrawListener( Loading
packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java +11 −61 Original line number Diff line number Diff line Loading @@ -36,9 +36,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.Rect; import android.net.Uri; import android.os.Handler; import android.os.IBinder; Loading @@ -49,7 +46,6 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import android.view.WindowManager; import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; Loading @@ -58,7 +54,6 @@ import com.android.internal.util.ScreenshotRequest; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import java.util.concurrent.Executor; import java.util.function.Consumer; Loading Loading @@ -222,7 +217,6 @@ public class TakeScreenshotService extends Service { return; } if (mFeatureFlags.isEnabled(Flags.SCREENSHOT_METADATA_REFACTOR)) { Log.d(TAG, "Processing screenshot data"); ScreenshotData screenshotData = ScreenshotData.fromRequest(request); try { Loading @@ -235,18 +229,6 @@ public class TakeScreenshotService extends Service { R.string.screenshot_failed_to_capture_text); callback.reportError(); } } else { try { mProcessor.processAsync(request, (r) -> dispatchToController(r, onSaved, callback)); } catch (IllegalStateException e) { Log.e(TAG, "Failed to process screenshot request!", e); logFailedRequest(request); mNotificationsController.notifyScreenshotError( R.string.screenshot_failed_to_capture_text); callback.reportError(); } } } private void dispatchToController(ScreenshotData screenshot, Loading @@ -257,38 +239,6 @@ public class TakeScreenshotService extends Service { mScreenshot.handleScreenshot(screenshot, uriConsumer, callback); } private void dispatchToController(ScreenshotRequest request, Consumer<Uri> uriConsumer, RequestCallback callback) { ComponentName topComponent = request.getTopComponent(); String packageName = topComponent == null ? "" : topComponent.getPackageName(); mUiEventLogger.log( ScreenshotEvent.getScreenshotSource(request.getSource()), 0, packageName); switch (request.getType()) { case WindowManager.TAKE_SCREENSHOT_FULLSCREEN: if (DEBUG_SERVICE) { Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_FULLSCREEN"); } mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, callback); break; case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE: if (DEBUG_SERVICE) { Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE"); } Bitmap screenshot = request.getBitmap(); Rect screenBounds = request.getBoundsInScreen(); Insets insets = request.getInsets(); int taskId = request.getTaskId(); int userId = request.getUserId(); mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets, taskId, userId, topComponent, uriConsumer, callback); break; default: Log.wtf(TAG, "Invalid screenshot option: " + request.getType()); } } private void logFailedRequest(ScreenshotRequest request) { ComponentName topComponent = request.getTopComponent(); String packageName = topComponent == null ? "" : topComponent.getPackageName(); Loading
packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt +0 −230 Original line number Diff line number Diff line Loading @@ -23,28 +23,21 @@ import android.content.ComponentName import android.graphics.Bitmap import android.graphics.Bitmap.Config.HARDWARE import android.graphics.ColorSpace import android.graphics.Insets import android.graphics.Rect import android.hardware.HardwareBuffer import android.os.UserHandle import android.os.UserManager import android.testing.AndroidTestingRunner import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.util.ScreenshotRequest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.SCREENSHOT_METADATA_REFACTOR import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_OVERVIEW import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argThat import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever Loading @@ -61,9 +54,6 @@ import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyZeroInteractions private const val USER_ID = 1 private const val TASK_ID = 11 @RunWith(AndroidTestingRunner::class) @SmallTest class TakeScreenshotServiceTest : SysuiTestCase() { Loading Loading @@ -123,9 +113,6 @@ class TakeScreenshotServiceTest : SysuiTestCase() { .whenever(requestProcessor) .processAsync(/* screenshot= */ any(ScreenshotData::class.java), /* callback= */ any()) // Flipped in selected test cases flags.set(SCREENSHOT_METADATA_REFACTOR, false) service.attach( mContext, /* thread = */ null, Loading Loading @@ -157,39 +144,6 @@ class TakeScreenshotServiceTest : SysuiTestCase() { service.handleRequest(request, { /* onSaved */}, callback) verify(controller, times(1)) .takeScreenshotFullscreen( eq(topComponent), /* onSavedListener = */ any(), /* requestCallback = */ any() ) assertEquals("Expected one UiEvent", 1, eventLogger.numLogs()) val logEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED UiEvent", logEvent.eventId, SCREENSHOT_REQUESTED_KEY_OTHER.id ) assertEquals( "Expected supplied package name", topComponent.packageName, eventLogger.get(0).packageName ) } @Test fun takeScreenshotFullscreen_screenshotDataEnabled() { flags.set(SCREENSHOT_METADATA_REFACTOR, true) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) .build() service.handleRequest(request, { /* onSaved */}, callback) verify(controller, times(1)) .handleScreenshot( eq(ScreenshotData.fromRequest(request)), Loading @@ -212,54 +166,8 @@ class TakeScreenshotServiceTest : SysuiTestCase() { ) } @Test fun takeScreenshotProvidedImage() { val bounds = Rect(50, 50, 150, 150) val bitmap = makeHardwareBitmap(100, 100) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OVERVIEW) .setTopComponent(topComponent) .setTaskId(TASK_ID) .setUserId(USER_ID) .setBitmap(bitmap) .setBoundsOnScreen(bounds) .setInsets(Insets.NONE) .build() service.handleRequest(request, { /* onSaved */}, callback) verify(controller, times(1)) .handleImageAsScreenshot( argThat { b -> b.equalsHardwareBitmap(bitmap) }, eq(bounds), eq(Insets.NONE), eq(TASK_ID), eq(USER_ID), eq(topComponent), /* onSavedListener = */ any(), /* requestCallback = */ any() ) assertEquals("Expected one UiEvent", 1, eventLogger.numLogs()) val logEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED_* UiEvent", logEvent.eventId, SCREENSHOT_REQUESTED_OVERVIEW.id ) assertEquals( "Expected supplied package name", topComponent.packageName, eventLogger.get(0).packageName ) } @Test fun takeScreenshotFullscreen_userLocked() { flags.set(SCREENSHOT_METADATA_REFACTOR, true) whenever(userManager.isUserUnlocked).thenReturn(false) val request = Loading Loading @@ -300,100 +208,6 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshotFullscreen_screenCaptureDisabled_allUsers() { flags.set(SCREENSHOT_METADATA_REFACTOR, true) whenever(devicePolicyManager.getScreenCaptureDisabled(isNull(), eq(UserHandle.USER_ALL))) .thenReturn(true) whenever( devicePolicyResourcesManager.getString( eq(SCREENSHOT_BLOCKED_BY_ADMIN), /* Supplier<String> */ any(), ) ) .thenReturn("SCREENSHOT_BLOCKED_BY_ADMIN") val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) .build() service.handleRequest(request, { /* onSaved */}, callback) // error shown: Toast.makeText(...).show(), untestable verify(callback, times(1)).reportError() verifyZeroInteractions(controller) assertEquals("Expected two UiEvents", 2, eventLogger.numLogs()) val requestEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED_* UiEvent", SCREENSHOT_REQUESTED_KEY_OTHER.id, requestEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, requestEvent.packageName ) val failureEvent = eventLogger.get(1) assertEquals( "Expected SCREENSHOT_CAPTURE_FAILED UiEvent", SCREENSHOT_CAPTURE_FAILED.id, failureEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, failureEvent.packageName ) } @Test fun takeScreenshotFullscreen_userLocked_metadataDisabled() { flags.set(SCREENSHOT_METADATA_REFACTOR, false) whenever(userManager.isUserUnlocked).thenReturn(false) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) .build() service.handleRequest(request, { /* onSaved */}, callback) verify(notificationsController, times(1)).notifyScreenshotError(anyInt()) verify(callback, times(1)).reportError() verifyZeroInteractions(controller) assertEquals("Expected two UiEvents", 2, eventLogger.numLogs()) val requestEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED_* UiEvent", SCREENSHOT_REQUESTED_KEY_OTHER.id, requestEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, requestEvent.packageName ) val failureEvent = eventLogger.get(1) assertEquals( "Expected SCREENSHOT_CAPTURE_FAILED UiEvent", SCREENSHOT_CAPTURE_FAILED.id, failureEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, failureEvent.packageName ) } @Test fun takeScreenshotFullscreen_screenCaptureDisabled_allUsers_metadataDisabled() { flags.set(SCREENSHOT_METADATA_REFACTOR, false) whenever(devicePolicyManager.getScreenCaptureDisabled(isNull(), eq(UserHandle.USER_ALL))) .thenReturn(true) Loading Loading @@ -441,52 +255,8 @@ class TakeScreenshotServiceTest : SysuiTestCase() { ) } @Test fun takeScreenshot_workProfile_nullBitmap_metadataDisabled() { flags.set(SCREENSHOT_METADATA_REFACTOR, false) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) .build() doThrow(IllegalStateException::class.java) .whenever(requestProcessor) .processAsync(any(ScreenshotRequest::class.java), any()) service.handleRequest(request, { /* onSaved */}, callback) verify(callback, times(1)).reportError() verify(notificationsController, times(1)).notifyScreenshotError(anyInt()) verifyZeroInteractions(controller) assertEquals("Expected two UiEvents", 2, eventLogger.numLogs()) val requestEvent = eventLogger.get(0) assertEquals( "Expected SCREENSHOT_REQUESTED_* UiEvent", SCREENSHOT_REQUESTED_KEY_OTHER.id, requestEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, requestEvent.packageName ) val failureEvent = eventLogger.get(1) assertEquals( "Expected SCREENSHOT_CAPTURE_FAILED UiEvent", SCREENSHOT_CAPTURE_FAILED.id, failureEvent.eventId ) assertEquals( "Expected supplied package name", topComponent.packageName, failureEvent.packageName ) } @Test fun takeScreenshot_workProfile_nullBitmap() { flags.set(SCREENSHOT_METADATA_REFACTOR, true) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) .setTopComponent(topComponent) Loading