Add action chips to corner screenshot flow
In the corner screenshot flow, add a LinearLayout with action chips
(share/edit/scroll) that pops up once the actions are available.
Note that the 'scroll' button currently does nothing.
Bug: 144918886
Test: manual; tested that 'edit' and 'share' chips open the
appropriate apps and make the screenshot disappear; tested that
current notification flow is unchanged.
Change-Id: I6952b76aa3bb479c49b1905275d5fcdc0eeaf2df
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 0000000..fc3dfeb
--- /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 0000000..095213e
--- /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 59952e0..6ac9da4 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 0000000..6b42400
--- /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 0febc8e..9a66e8b 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 bda1c52..92c7477 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 64b2892..f7b92b5 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 66cd919..fedd855 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 @@
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.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.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 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 @@
}
}
+ 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 @@
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 @@
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 @@
* 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 @@
// 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 @@
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 @@
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 5e5cf74..d2268e1 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 @@
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 @@
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 3f32c66b..6d85d37 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 @@
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,