Merge "Add action chips to corner screenshot flow"
This commit is contained in:
committed by
Android (Google) Code Review
commit
d4edbdcb14
27
packages/SystemUI/res/drawable/action_chip_background.xml
Normal file
27
packages/SystemUI/res/drawable/action_chip_background.xml
Normal file
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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"/>
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user