Merge "Rearrange/rename GlobalScreenshot methods" into rvc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1785587c24
@@ -214,9 +214,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
private Animator mScreenshotAnimation;
|
private Animator mScreenshotAnimation;
|
||||||
private Runnable mOnCompleteRunnable;
|
private Runnable mOnCompleteRunnable;
|
||||||
private Animator mDismissAnimation;
|
private Animator mDismissAnimation;
|
||||||
private boolean mInDarkMode = false;
|
private boolean mInDarkMode;
|
||||||
private boolean mDirectionLTR = true;
|
private boolean mDirectionLTR;
|
||||||
private boolean mOrientationPortrait = true;
|
private boolean mOrientationPortrait;
|
||||||
|
|
||||||
private float mCornerSizeX;
|
private float mCornerSizeX;
|
||||||
private float mDismissDeltaY;
|
private float mDismissDeltaY;
|
||||||
@@ -245,9 +245,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context everything needs a context :(
|
|
||||||
*/
|
|
||||||
@Inject
|
@Inject
|
||||||
public GlobalScreenshot(
|
public GlobalScreenshot(
|
||||||
Context context, @Main Resources resources,
|
Context context, @Main Resources resources,
|
||||||
@@ -320,6 +317,104 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
inoutInfo.touchableRegion.set(touchRegion);
|
inoutInfo.touchableRegion.set(touchRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void takeScreenshotFullscreen(Consumer<Uri> finisher, Runnable onComplete) {
|
||||||
|
mOnCompleteRunnable = onComplete;
|
||||||
|
|
||||||
|
mDisplay.getRealMetrics(mDisplayMetrics);
|
||||||
|
takeScreenshotInternal(
|
||||||
|
finisher,
|
||||||
|
new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
|
||||||
|
Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
|
||||||
|
Consumer<Uri> finisher, Runnable onComplete) {
|
||||||
|
// TODO: use task Id, userId, topComponent for smart handler
|
||||||
|
|
||||||
|
mOnCompleteRunnable = onComplete;
|
||||||
|
if (aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
|
||||||
|
saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, false);
|
||||||
|
} else {
|
||||||
|
saveScreenshot(screenshot, finisher,
|
||||||
|
new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()), Insets.NONE,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a screenshot selector
|
||||||
|
*/
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
void takeScreenshotPartial(final Consumer<Uri> finisher, Runnable onComplete) {
|
||||||
|
dismissScreenshot("new screenshot requested", true);
|
||||||
|
mOnCompleteRunnable = onComplete;
|
||||||
|
|
||||||
|
mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
|
||||||
|
mScreenshotSelectorView.setOnTouchListener((v, event) -> {
|
||||||
|
ScreenshotSelectorView view = (ScreenshotSelectorView) v;
|
||||||
|
switch (event.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
view.startSelection((int) event.getX(), (int) event.getY());
|
||||||
|
return true;
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
view.updateSelection((int) event.getX(), (int) event.getY());
|
||||||
|
return true;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
view.setVisibility(View.GONE);
|
||||||
|
mWindowManager.removeView(mScreenshotLayout);
|
||||||
|
final Rect rect = view.getSelectionRect();
|
||||||
|
if (rect != null) {
|
||||||
|
if (rect.width() != 0 && rect.height() != 0) {
|
||||||
|
// Need mScreenshotLayout to handle it after the view disappears
|
||||||
|
mScreenshotLayout.post(() -> takeScreenshotInternal(finisher, rect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view.stopSelection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
mScreenshotLayout.post(() -> {
|
||||||
|
mScreenshotSelectorView.setVisibility(View.VISIBLE);
|
||||||
|
mScreenshotSelectorView.requestFocus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels screenshot request
|
||||||
|
*/
|
||||||
|
void stopScreenshot() {
|
||||||
|
// If the selector layer still presents on screen, we remove it and resets its state.
|
||||||
|
if (mScreenshotSelectorView.getSelectionRect() != null) {
|
||||||
|
mWindowManager.removeView(mScreenshotLayout);
|
||||||
|
mScreenshotSelectorView.stopSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears current screenshot
|
||||||
|
*/
|
||||||
|
void dismissScreenshot(String reason, boolean immediate) {
|
||||||
|
Log.v(TAG, "clearing screenshot: " + reason);
|
||||||
|
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
|
||||||
|
mScreenshotLayout.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
|
||||||
|
if (!immediate) {
|
||||||
|
mDismissAnimation = createScreenshotDismissAnimation();
|
||||||
|
mDismissAnimation.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
super.onAnimationEnd(animation);
|
||||||
|
clearScreenshot();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mDismissAnimation.start();
|
||||||
|
} else {
|
||||||
|
clearScreenshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onConfigChanged(Configuration newConfig) {
|
private void onConfigChanged(Configuration newConfig) {
|
||||||
boolean needsUpdate = false;
|
boolean needsUpdate = false;
|
||||||
// dark mode
|
// dark mode
|
||||||
@@ -408,15 +503,12 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
}
|
}
|
||||||
return mScreenshotLayout.onApplyWindowInsets(insets);
|
return mScreenshotLayout.onApplyWindowInsets(insets);
|
||||||
});
|
});
|
||||||
mScreenshotLayout.setOnKeyListener(new View.OnKeyListener() {
|
mScreenshotLayout.setOnKeyListener((v, keyCode, event) -> {
|
||||||
@Override
|
|
||||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
dismissScreenshot("back pressed", true);
|
dismissScreenshot("back pressed", true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// Get focus so that the key events go to the layout.
|
// Get focus so that the key events go to the layout.
|
||||||
mScreenshotLayout.setFocusableInTouchMode(true);
|
mScreenshotLayout.setFocusableInTouchMode(true);
|
||||||
@@ -470,60 +562,20 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the window focusability. If the window is already showing, then it updates the
|
|
||||||
* window immediately, otherwise the layout params will be applied when the window is next
|
|
||||||
* shown.
|
|
||||||
*/
|
|
||||||
private void setWindowFocusable(boolean focusable) {
|
|
||||||
if (focusable) {
|
|
||||||
mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
|
|
||||||
} else {
|
|
||||||
mWindowLayoutParams.flags |= FLAG_NOT_FOCUSABLE;
|
|
||||||
}
|
|
||||||
if (mScreenshotLayout.isAttachedToWindow()) {
|
|
||||||
mWindowManager.updateViewLayout(mScreenshotLayout, mWindowLayoutParams);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new worker thread and saves the screenshot to the media store.
|
|
||||||
*/
|
|
||||||
private void saveScreenshotInWorkerThread(
|
|
||||||
Consumer<Uri> finisher, @Nullable ActionsReadyListener actionsReadyListener) {
|
|
||||||
SaveImageInBackgroundData data = new SaveImageInBackgroundData();
|
|
||||||
data.image = mScreenBitmap;
|
|
||||||
data.finisher = finisher;
|
|
||||||
data.mActionsReadyListener = actionsReadyListener;
|
|
||||||
|
|
||||||
if (mSaveInBgTask != null) {
|
|
||||||
// just log success/failure for the pre-existing screenshot
|
|
||||||
mSaveInBgTask.setActionsReadyListener(new ActionsReadyListener() {
|
|
||||||
@Override
|
|
||||||
void onActionsReady(SavedImageData imageData) {
|
|
||||||
logSuccessOnActionsReady(imageData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data);
|
|
||||||
mSaveInBgTask.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a screenshot of the current display and shows an animation.
|
* Takes a screenshot of the current display and shows an animation.
|
||||||
*/
|
*/
|
||||||
private void takeScreenshot(Consumer<Uri> finisher, Rect crop) {
|
private void takeScreenshotInternal(Consumer<Uri> finisher, Rect crop) {
|
||||||
// copy the input Rect, since SurfaceControl.screenshot can mutate it
|
// copy the input Rect, since SurfaceControl.screenshot can mutate it
|
||||||
Rect screenRect = new Rect(crop);
|
Rect screenRect = new Rect(crop);
|
||||||
int rot = mDisplay.getRotation();
|
int rot = mDisplay.getRotation();
|
||||||
int width = crop.width();
|
int width = crop.width();
|
||||||
int height = crop.height();
|
int height = crop.height();
|
||||||
takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect,
|
saveScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect,
|
||||||
Insets.NONE, true);
|
Insets.NONE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
|
private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
|
||||||
Insets screenInsets, boolean showFlash) {
|
Insets screenInsets, boolean showFlash) {
|
||||||
dismissScreenshot("new screenshot requested", true);
|
dismissScreenshot("new screenshot requested", true);
|
||||||
|
|
||||||
@@ -561,85 +613,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
startAnimation(finisher, screenRect, screenInsets, showFlash);
|
startAnimation(finisher, screenRect, screenInsets, showFlash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void takeScreenshot(Consumer<Uri> finisher, Runnable onComplete) {
|
|
||||||
mOnCompleteRunnable = onComplete;
|
|
||||||
|
|
||||||
mDisplay.getRealMetrics(mDisplayMetrics);
|
|
||||||
takeScreenshot(
|
|
||||||
finisher,
|
|
||||||
new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
|
|
||||||
Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
|
|
||||||
Consumer<Uri> finisher, Runnable onComplete) {
|
|
||||||
// TODO: use task Id, userId, topComponent for smart handler
|
|
||||||
|
|
||||||
mOnCompleteRunnable = onComplete;
|
|
||||||
if (aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
|
|
||||||
takeScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, false);
|
|
||||||
} else {
|
|
||||||
takeScreenshot(screenshot, finisher,
|
|
||||||
new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()), Insets.NONE,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays a screenshot selector
|
|
||||||
*/
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
void takeScreenshotPartial(final Consumer<Uri> finisher, Runnable onComplete) {
|
|
||||||
dismissScreenshot("new screenshot requested", true);
|
|
||||||
mOnCompleteRunnable = onComplete;
|
|
||||||
|
|
||||||
mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
|
|
||||||
mScreenshotSelectorView.setOnTouchListener(new View.OnTouchListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
ScreenshotSelectorView view = (ScreenshotSelectorView) v;
|
|
||||||
switch (event.getAction()) {
|
|
||||||
case MotionEvent.ACTION_DOWN:
|
|
||||||
view.startSelection((int) event.getX(), (int) event.getY());
|
|
||||||
return true;
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
view.updateSelection((int) event.getX(), (int) event.getY());
|
|
||||||
return true;
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
view.setVisibility(View.GONE);
|
|
||||||
mWindowManager.removeView(mScreenshotLayout);
|
|
||||||
final Rect rect = view.getSelectionRect();
|
|
||||||
if (rect != null) {
|
|
||||||
if (rect.width() != 0 && rect.height() != 0) {
|
|
||||||
// Need mScreenshotLayout to handle it after the view disappears
|
|
||||||
mScreenshotLayout.post(() -> takeScreenshot(finisher, rect));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view.stopSelection();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mScreenshotLayout.post(() -> {
|
|
||||||
mScreenshotSelectorView.setVisibility(View.VISIBLE);
|
|
||||||
mScreenshotSelectorView.requestFocus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels screenshot request
|
|
||||||
*/
|
|
||||||
void stopScreenshot() {
|
|
||||||
// If the selector layer still presents on screen, we remove it and resets its state.
|
|
||||||
if (mScreenshotSelectorView.getSelectionRect() != null) {
|
|
||||||
mWindowManager.removeView(mScreenshotLayout);
|
|
||||||
mScreenshotSelectorView.stopSelection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
|
* Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
|
||||||
* failure).
|
* failure).
|
||||||
@@ -670,104 +643,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isUserSetupComplete() {
|
|
||||||
return Settings.Secure.getInt(mContext.getContentResolver(),
|
|
||||||
SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears current screenshot
|
|
||||||
*/
|
|
||||||
void dismissScreenshot(String reason, boolean immediate) {
|
|
||||||
Log.v(TAG, "clearing screenshot: " + reason);
|
|
||||||
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
|
|
||||||
mScreenshotLayout.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
|
|
||||||
if (!immediate) {
|
|
||||||
mDismissAnimation = createScreenshotDismissAnimation();
|
|
||||||
mDismissAnimation.addListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
super.onAnimationEnd(animation);
|
|
||||||
clearScreenshot();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mDismissAnimation.start();
|
|
||||||
} else {
|
|
||||||
clearScreenshot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearScreenshot() {
|
|
||||||
if (mScreenshotLayout.isAttachedToWindow()) {
|
|
||||||
mWindowManager.removeView(mScreenshotLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear any references to the bitmap
|
|
||||||
mScreenshotPreview.setImageDrawable(null);
|
|
||||||
mScreenshotAnimatedView.setImageDrawable(null);
|
|
||||||
mScreenshotAnimatedView.setVisibility(View.GONE);
|
|
||||||
mActionsContainerBackground.setVisibility(View.GONE);
|
|
||||||
mActionsContainer.setVisibility(View.GONE);
|
|
||||||
mBackgroundProtection.setAlpha(0f);
|
|
||||||
mDismissButton.setVisibility(View.GONE);
|
|
||||||
mScreenshotPreview.setVisibility(View.GONE);
|
|
||||||
mScreenshotPreview.setLayerType(View.LAYER_TYPE_NONE, null);
|
|
||||||
mScreenshotPreview.setContentDescription(
|
|
||||||
mContext.getResources().getString(R.string.screenshot_preview_description));
|
|
||||||
mScreenshotLayout.setAlpha(1);
|
|
||||||
mDismissButton.setTranslationY(0);
|
|
||||||
mActionsContainer.setTranslationY(0);
|
|
||||||
mActionsContainerBackground.setTranslationY(0);
|
|
||||||
mScreenshotPreview.setTranslationY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up the action shade and its entrance animation, once we get the screenshot URI.
|
|
||||||
*/
|
|
||||||
private void showUiOnActionsReady(SavedImageData imageData) {
|
|
||||||
logSuccessOnActionsReady(imageData);
|
|
||||||
|
|
||||||
AccessibilityManager accessibilityManager = (AccessibilityManager)
|
|
||||||
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
|
|
||||||
long timeoutMs = accessibilityManager.getRecommendedTimeoutMillis(
|
|
||||||
SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
|
|
||||||
AccessibilityManager.FLAG_CONTENT_CONTROLS);
|
|
||||||
|
|
||||||
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
|
|
||||||
mScreenshotHandler.sendMessageDelayed(
|
|
||||||
mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
|
|
||||||
timeoutMs);
|
|
||||||
|
|
||||||
if (imageData.uri != null) {
|
|
||||||
mScreenshotHandler.post(() -> {
|
|
||||||
if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
|
|
||||||
mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
super.onAnimationEnd(animation);
|
|
||||||
createScreenshotActionsShadeAnimation(imageData).start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
createScreenshotActionsShadeAnimation(imageData).start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs success/failure of the screenshot saving task, and shows an error if it failed.
|
|
||||||
*/
|
|
||||||
private void logSuccessOnActionsReady(SavedImageData imageData) {
|
|
||||||
if (imageData.uri == null) {
|
|
||||||
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED);
|
|
||||||
mNotificationsController.notifyScreenshotError(
|
|
||||||
R.string.screenshot_failed_to_capture_text);
|
|
||||||
} else {
|
|
||||||
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the animation after taking the screenshot
|
* Starts the animation after taking the screenshot
|
||||||
*/
|
*/
|
||||||
@@ -818,6 +693,77 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new worker thread and saves the screenshot to the media store.
|
||||||
|
*/
|
||||||
|
private void saveScreenshotInWorkerThread(
|
||||||
|
Consumer<Uri> finisher, @Nullable ActionsReadyListener actionsReadyListener) {
|
||||||
|
SaveImageInBackgroundData data = new SaveImageInBackgroundData();
|
||||||
|
data.image = mScreenBitmap;
|
||||||
|
data.finisher = finisher;
|
||||||
|
data.mActionsReadyListener = actionsReadyListener;
|
||||||
|
|
||||||
|
if (mSaveInBgTask != null) {
|
||||||
|
// just log success/failure for the pre-existing screenshot
|
||||||
|
mSaveInBgTask.setActionsReadyListener(new ActionsReadyListener() {
|
||||||
|
@Override
|
||||||
|
void onActionsReady(SavedImageData imageData) {
|
||||||
|
logSuccessOnActionsReady(imageData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data);
|
||||||
|
mSaveInBgTask.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the action shade and its entrance animation, once we get the screenshot URI.
|
||||||
|
*/
|
||||||
|
private void showUiOnActionsReady(SavedImageData imageData) {
|
||||||
|
logSuccessOnActionsReady(imageData);
|
||||||
|
|
||||||
|
AccessibilityManager accessibilityManager = (AccessibilityManager)
|
||||||
|
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
|
||||||
|
long timeoutMs = accessibilityManager.getRecommendedTimeoutMillis(
|
||||||
|
SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
|
||||||
|
AccessibilityManager.FLAG_CONTENT_CONTROLS);
|
||||||
|
|
||||||
|
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
|
||||||
|
mScreenshotHandler.sendMessageDelayed(
|
||||||
|
mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
|
||||||
|
timeoutMs);
|
||||||
|
|
||||||
|
if (imageData.uri != null) {
|
||||||
|
mScreenshotHandler.post(() -> {
|
||||||
|
if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
|
||||||
|
mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
super.onAnimationEnd(animation);
|
||||||
|
createScreenshotActionsShadeAnimation(imageData).start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
createScreenshotActionsShadeAnimation(imageData).start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs success/failure of the screenshot saving task, and shows an error if it failed.
|
||||||
|
*/
|
||||||
|
private void logSuccessOnActionsReady(SavedImageData imageData) {
|
||||||
|
if (imageData.uri == null) {
|
||||||
|
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED);
|
||||||
|
mNotificationsController.notifyScreenshotError(
|
||||||
|
R.string.screenshot_failed_to_capture_text);
|
||||||
|
} else {
|
||||||
|
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash) {
|
private AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash) {
|
||||||
Rect previewBounds = new Rect();
|
Rect previewBounds = new Rect();
|
||||||
mScreenshotPreview.getBoundsOnScreen(previewBounds);
|
mScreenshotPreview.getBoundsOnScreen(previewBounds);
|
||||||
@@ -1070,6 +1016,30 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
return animSet;
|
return animSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearScreenshot() {
|
||||||
|
if (mScreenshotLayout.isAttachedToWindow()) {
|
||||||
|
mWindowManager.removeView(mScreenshotLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear any references to the bitmap
|
||||||
|
mScreenshotPreview.setImageDrawable(null);
|
||||||
|
mScreenshotAnimatedView.setImageDrawable(null);
|
||||||
|
mScreenshotAnimatedView.setVisibility(View.GONE);
|
||||||
|
mActionsContainerBackground.setVisibility(View.GONE);
|
||||||
|
mActionsContainer.setVisibility(View.GONE);
|
||||||
|
mBackgroundProtection.setAlpha(0f);
|
||||||
|
mDismissButton.setVisibility(View.GONE);
|
||||||
|
mScreenshotPreview.setVisibility(View.GONE);
|
||||||
|
mScreenshotPreview.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||||
|
mScreenshotPreview.setContentDescription(
|
||||||
|
mContext.getResources().getString(R.string.screenshot_preview_description));
|
||||||
|
mScreenshotLayout.setAlpha(1);
|
||||||
|
mDismissButton.setTranslationY(0);
|
||||||
|
mActionsContainer.setTranslationY(0);
|
||||||
|
mActionsContainerBackground.setTranslationY(0);
|
||||||
|
mScreenshotPreview.setTranslationY(0);
|
||||||
|
}
|
||||||
|
|
||||||
private void setAnimatedViewSize(int width, int height) {
|
private void setAnimatedViewSize(int width, int height) {
|
||||||
ViewGroup.LayoutParams layoutParams = mScreenshotAnimatedView.getLayoutParams();
|
ViewGroup.LayoutParams layoutParams = mScreenshotAnimatedView.getLayoutParams();
|
||||||
layoutParams.width = width;
|
layoutParams.width = width;
|
||||||
@@ -1077,6 +1047,27 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
|
|||||||
mScreenshotAnimatedView.setLayoutParams(layoutParams);
|
mScreenshotAnimatedView.setLayoutParams(layoutParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the window focusability. If the window is already showing, then it updates the
|
||||||
|
* window immediately, otherwise the layout params will be applied when the window is next
|
||||||
|
* shown.
|
||||||
|
*/
|
||||||
|
private void setWindowFocusable(boolean focusable) {
|
||||||
|
if (focusable) {
|
||||||
|
mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
|
||||||
|
} else {
|
||||||
|
mWindowLayoutParams.flags |= FLAG_NOT_FOCUSABLE;
|
||||||
|
}
|
||||||
|
if (mScreenshotLayout.isAttachedToWindow()) {
|
||||||
|
mWindowManager.updateViewLayout(mScreenshotLayout, mWindowLayoutParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUserSetupComplete() {
|
||||||
|
return Settings.Secure.getInt(mContext.getContentResolver(),
|
||||||
|
SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
/** Does the aspect ratio of the bitmap with insets removed match the bounds. */
|
/** Does the aspect ratio of the bitmap with insets removed match the bounds. */
|
||||||
private boolean aspectRatiosMatch(Bitmap bitmap, Insets bitmapInsets, Rect screenBounds) {
|
private boolean aspectRatiosMatch(Bitmap bitmap, Insets bitmapInsets, Rect screenBounds) {
|
||||||
int insettedWidth = bitmap.getWidth() - bitmapInsets.left - bitmapInsets.right;
|
int insettedWidth = bitmap.getWidth() - bitmapInsets.left - bitmapInsets.right;
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public class TakeScreenshotService extends Service {
|
|||||||
|
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
|
case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
|
||||||
mScreenshot.takeScreenshot(uriConsumer, onComplete);
|
mScreenshot.takeScreenshotFullscreen(uriConsumer, onComplete);
|
||||||
break;
|
break;
|
||||||
case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
|
case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
|
||||||
mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);
|
mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);
|
||||||
|
|||||||
Reference in New Issue
Block a user