diff --git a/packages/SystemUI/res/drawable/action_chip_background.xml b/packages/SystemUI/res/drawable/action_chip_background.xml new file mode 100644 index 0000000000000..fc3dfeb9c1fd5 --- /dev/null +++ b/packages/SystemUI/res/drawable/action_chip_background.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/action_chip_container_background.xml b/packages/SystemUI/res/drawable/action_chip_container_background.xml new file mode 100644 index 0000000000000..095213e38e92d --- /dev/null +++ b/packages/SystemUI/res/drawable/action_chip_container_background.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index 59952e09555fd..6ac9da4291c6b 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -39,4 +39,13 @@ android:layout_height="match_parent" android:visibility="gone" android:pointerIcon="crosshair"/> + diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml new file mode 100644 index 0000000000000..6b424002d7fff --- /dev/null +++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml @@ -0,0 +1,25 @@ + + + diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index 0febc8ed42621..9a66e8bc87917 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -78,6 +78,11 @@ @color/GM2_red_300 + + @color/GM2_grey_900 + #42FFFFFF + @color/GM2_blue_300 + #ff888888 #ff80cbc4 diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index bda1c52f27c0d..92c74770a3c4b 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -180,6 +180,11 @@ #ffffffff + + #F5F5F5 + #1f000000 + @color/GM2_blue_500 + #F8F9FA #F1F3F4 diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 64b2892efc9a7..f7b92b564dac1 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -285,8 +285,18 @@ 3dp + + 20dp + 10dp + 20dp + + 20dp + 10dp + 10dp + 15dp + 70dp diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 66cd91996cea4..fedd855a858e1 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -19,6 +19,7 @@ package com.android.systemui.screenshot; import static android.content.Context.NOTIFICATION_SERVICE; import static android.os.AsyncTask.THREAD_POOL_EXECUTOR; import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; +import static android.view.View.VISIBLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_CORNER_FLOW; @@ -69,6 +70,8 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.animation.Interpolator; import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; @@ -89,7 +92,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import java.util.function.Function; import javax.inject.Inject; import javax.inject.Singleton; @@ -110,7 +112,7 @@ public class GlobalScreenshot { public Bitmap image; public Uri imageUri; public Consumer finisher; - public Function onEditReady; + public GlobalScreenshot.ActionsReadyListener mActionsReadyListener; public int iconSize; public int previewWidth; public int previewheight; @@ -127,6 +129,10 @@ public class GlobalScreenshot { } } + abstract static class ActionsReadyListener { + abstract void onActionsReady(PendingIntent shareAction, PendingIntent editAction); + } + // These strings are used for communicating the action invoked to // ScreenshotNotificationSmartActionsProvider. static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type"; @@ -175,6 +181,10 @@ public class GlobalScreenshot { private ImageView mBackgroundView; private ImageView mScreenshotView; private ImageView mScreenshotFlash; + private LinearLayout mActionsView; + private TextView mShareAction; + private TextView mEditAction; + private TextView mScrollAction; private AnimatorSet mScreenshotAnimation; @@ -211,17 +221,31 @@ public class GlobalScreenshot { mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null); mBackgroundView = mScreenshotLayout.findViewById(R.id.global_screenshot_background); mScreenshotView = mScreenshotLayout.findViewById(R.id.global_screenshot); + mActionsView = mScreenshotLayout.findViewById(R.id.global_screenshot_actions); + + mShareAction = (TextView) layoutInflater.inflate( + R.layout.global_screenshot_action_chip, mActionsView, false); + mEditAction = (TextView) layoutInflater.inflate( + R.layout.global_screenshot_action_chip, mActionsView, false); + mScrollAction = (TextView) layoutInflater.inflate( + R.layout.global_screenshot_action_chip, mActionsView, false); + + mShareAction.setText(com.android.internal.R.string.share); + mEditAction.setText(com.android.internal.R.string.screenshot_edit); + mScrollAction.setText("Scroll"); // TODO (mkephart): Add to resources and translate + + mActionsView.addView(mShareAction); + mActionsView.addView(mEditAction); + mActionsView.addView(mScrollAction); + mScreenshotFlash = mScreenshotLayout.findViewById(R.id.global_screenshot_flash); mScreenshotSelectorView = mScreenshotLayout.findViewById(R.id.global_screenshot_selector); mScreenshotLayout.setFocusable(true); mScreenshotSelectorView.setFocusable(true); mScreenshotSelectorView.setFocusableInTouchMode(true); - mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - // Intercept and ignore all touch events - return true; - } + mScreenshotLayout.setOnTouchListener((v, event) -> { + // Intercept and ignore all touch events + return true; }); // Setup the window that we are going to use @@ -271,13 +295,13 @@ public class GlobalScreenshot { * Creates a new worker thread and saves the screenshot to the media store. */ private void saveScreenshotInWorkerThread( - Consumer finisher, @Nullable Function onEditReady) { + Consumer finisher, @Nullable ActionsReadyListener actionsReadyListener) { SaveImageInBackgroundData data = new SaveImageInBackgroundData(); data.context = mContext; data.image = mScreenBitmap; data.iconSize = mNotificationIconSize; data.finisher = finisher; - data.onEditReady = onEditReady; + data.mActionsReadyListener = actionsReadyListener; data.previewWidth = mPreviewWidth; data.previewheight = mPreviewHeight; if (mSaveInBgTask != null) { @@ -395,6 +419,7 @@ public class GlobalScreenshot { // Clear any references to the bitmap mScreenBitmap = null; mScreenshotView.setImageBitmap(null); + mActionsView.setVisibility(View.GONE); mBackgroundView.setVisibility(View.GONE); mScreenshotView.setVisibility(View.GONE); mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null); @@ -441,24 +466,13 @@ public class GlobalScreenshot { saveScreenshotInWorkerThread(finisher); clearScreenshot(); } else { - mScreenshotView.requestFocus(); - mScreenshotView.setOnClickListener((v) -> { - // TODO: remove once we have a better UI to show that we aren't ready yet - Toast notReadyToast = Toast.makeText( - mContext, "Screenshot is not ready yet", Toast.LENGTH_SHORT); - notReadyToast.show(); - }); - saveScreenshotInWorkerThread(finisher, intent -> { - mScreenshotHandler.post(() -> mScreenshotView.setOnClickListener(v -> { - try { - intent.send(); - clearScreenshot(); - } catch (PendingIntent.CanceledException e) { - Log.e(TAG, "Edit intent cancelled", e); - } - mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT); - })); - return null; + saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() { + @Override + void onActionsReady(PendingIntent shareAction, PendingIntent editAction) { + mScreenshotHandler.post(() -> + createScreenshotActionsShadeAnimation(shareAction, editAction) + .start()); + } }); mScreenshotHandler.sendMessageDelayed( mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT), @@ -664,6 +678,49 @@ public class GlobalScreenshot { return anim; } + private ValueAnimator createScreenshotActionsShadeAnimation( + PendingIntent shareAction, PendingIntent editAction) { + ValueAnimator animator = ValueAnimator.ofFloat(0, 1); + mActionsView.setY(mDisplayMetrics.heightPixels); + mActionsView.setVisibility(VISIBLE); + mActionsView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + float actionsViewHeight = mActionsView.getMeasuredHeight(); + float screenshotStartHeight = mScreenshotView.getTranslationY(); + + animator.addUpdateListener(animation -> { + float t = animation.getAnimatedFraction(); + mScreenshotView.setTranslationY(screenshotStartHeight - actionsViewHeight * t); + mActionsView.setY(mDisplayMetrics.heightPixels - actionsViewHeight * t); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mScreenshotView.requestFocus(); + mShareAction.setOnClickListener(v -> { + try { + shareAction.send(); + clearScreenshot(); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Share intent cancelled", e); + } + }); + mEditAction.setOnClickListener(v -> { + try { + editAction.send(); + clearScreenshot(); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Edit intent cancelled", e); + } + }); + Toast scrollNotImplemented = Toast.makeText( + mContext, "Not implemented", Toast.LENGTH_SHORT); + mScrollAction.setOnClickListener(v -> scrollNotImplemented.show()); + } + }); + return animator; + } + static void notifyScreenshotError(Context context, NotificationManager nManager, int msgResId) { Resources r = context.getResources(); String errorMsg = r.getString(msgResId); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java index 5e5cf743b4685..d2268e12c6620 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java @@ -434,8 +434,8 @@ class SaveImageInBackgroundTask extends AsyncTask { R.drawable.ic_screenshot_edit, r.getString(com.android.internal.R.string.screenshot_edit), editAction); notificationBuilder.addAction(editActionBuilder.build()); - if (editAction != null && mParams.onEditReady != null) { - mParams.onEditReady.apply(editAction); + if (mParams.mActionsReadyListener != null) { + mParams.mActionsReadyListener.onActionsReady(shareAction, editAction); } // Create a delete action for the notification @@ -472,7 +472,7 @@ class SaveImageInBackgroundTask extends AsyncTask { GlobalScreenshot.notifyScreenshotError(mParams.context, mNotificationManager, mParams.errorMsgResId); } else { - if (mParams.onEditReady != null) { + if (mParams.mActionsReadyListener != null) { // Cancel the "saving screenshot" notification mNotificationManager.cancel( SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT); diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java index 3f32c66b2d037..6d85d37537ea4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java @@ -175,7 +175,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); data.iconSize = 10; data.finisher = null; - data.onEditReady = null; + data.mActionsReadyListener = null; data.previewWidth = 10; data.previewheight = 10; SaveImageInBackgroundTask task = new SaveImageInBackgroundTask(mContext, data,