diff options
10 files changed, 191 insertions, 32 deletions
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 000000000000..fc3dfeb9c1fd --- /dev/null +++ b/packages/SystemUI/res/drawable/action_chip_background.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 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. + --> +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + android:color="@color/global_screenshot_button_ripple"> + <item android:id="@android:id/background"> + <shape android:shape="rectangle"> + <stroke android:width="1dp" android:color="@color/global_screenshot_button_text"/> + <solid android:color="@color/global_screenshot_button_background"/> + <corners android:radius="@dimen/screenshot_button_corner_radius"/> + </shape> + </item> +</ripple>
\ 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 000000000000..095213e38e92 --- /dev/null +++ b/packages/SystemUI/res/drawable/action_chip_container_background.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/global_screenshot_button_background"/> + <corners android:radius="@dimen/screenshot_action_container_corner_radius"/> +</shape>
\ 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 59952e09555f..6ac9da4291c6 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"/> + <LinearLayout + android:id="@+id/global_screenshot_actions" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center" + android:gravity="center" + android:paddingVertical="@dimen/screenshot_action_container_padding" + android:visibility="gone" + android:background="@drawable/action_chip_container_background"/> </FrameLayout> 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 000000000000..6b424002d7ff --- /dev/null +++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 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. + --> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/global_screenshot_action_chip" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/screenshot_action_chip_margin_horizontal" + android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical" + android:paddingHorizontal="@dimen/screenshot_action_chip_padding_horizontal" + android:background="@drawable/action_chip_background" + android:textColor="@color/global_screenshot_button_text"/> diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index 0febc8ed4262..9a66e8bc8791 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -78,6 +78,11 @@ <!-- The color of the text in the Global Actions menu --> <color name="global_actions_alert_text">@color/GM2_red_300</color> + <!-- Global screenshot actions --> + <color name="global_screenshot_button_background">@color/GM2_grey_900</color> + <color name="global_screenshot_button_ripple">#42FFFFFF</color> + <color name="global_screenshot_button_text">@color/GM2_blue_300</color> + <!-- Biometric dialog colors --> <color name="biometric_dialog_gray">#ff888888</color> <color name="biometric_dialog_accent">#ff80cbc4</color> <!-- light teal --> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index bda1c52f27c0..92c74770a3c4 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -180,6 +180,11 @@ <!-- Color for the Assistant invocation lights --> <color name="default_invocation_lights_color">#ffffffff</color> <!-- white --> + <!-- Global screenshot actions --> + <color name="global_screenshot_button_background">#F5F5F5</color> + <color name="global_screenshot_button_ripple">#1f000000</color> + <color name="global_screenshot_button_text">@color/GM2_blue_500</color> + <!-- GM2 colors --> <color name="GM2_grey_50">#F8F9FA</color> <color name="GM2_grey_100">#F1F3F4</color> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 64b2892efc9a..f7b92b564dac 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -285,8 +285,18 @@ <!-- the padding between dots in the icon overflow --> <dimen name="overflow_icon_dot_padding">3dp</dimen> + <!-- Dimensions related to screenshots --> + <!-- The padding on the global screenshot background image --> <dimen name="global_screenshot_bg_padding">20dp</dimen> + <dimen name="screenshot_action_container_corner_radius">10dp</dimen> + <dimen name="screenshot_action_container_padding">20dp</dimen> + <!-- Radius of the chip background on global screenshot actions --> + <dimen name="screenshot_button_corner_radius">20dp</dimen> + <dimen name="screenshot_action_chip_margin_horizontal">10dp</dimen> + <dimen name="screenshot_action_chip_padding_vertical">10dp</dimen> + <dimen name="screenshot_action_chip_padding_horizontal">15dp</dimen> + <!-- The width of the view containing navigation buttons --> <dimen name="navigation_key_width">70dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 66cd91996cea..fedd855a858e 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<Uri> finisher; - public Function<PendingIntent, Void> 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<Uri> finisher, @Nullable Function<PendingIntent, Void> onEditReady) { + Consumer<Uri> 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 5e5cf743b468..d2268e12c662 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<Void, Void, Void> { 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<Void, Void, Void> { 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 3f32c66b2d03..6d85d37537ea 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, |