Merge "Add action chips to clipboard overlay"

This commit is contained in:
Miranda Kephart
2022-01-27 17:44:51 +00:00
committed by Android (Google) Code Review
4 changed files with 74 additions and 15 deletions

View File

@@ -17,6 +17,7 @@
<com.android.systemui.clipboardoverlay.DraggableConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:alpha="0"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView

View File

@@ -60,8 +60,8 @@ public class ClipboardListener extends CoreStartable
return;
}
if (mClipboardOverlayController == null) {
mClipboardOverlayController = new ClipboardOverlayController(mContext,
new TimeoutHandler(mContext));
mClipboardOverlayController =
new ClipboardOverlayController(mContext, new TimeoutHandler(mContext));
}
mClipboardOverlayController.setClipData(mClipboardManager.getPrimaryClip());
mClipboardOverlayController.setOnSessionCompleteListener(() -> {

View File

@@ -28,6 +28,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.MainThread;
import android.app.RemoteAction;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ComponentName;
@@ -43,6 +44,7 @@ import android.graphics.drawable.Icon;
import android.hardware.display.DisplayManager;
import android.hardware.input.InputManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
@@ -60,8 +62,13 @@ import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.policy.PhoneWindow;
@@ -71,6 +78,7 @@ import com.android.systemui.screenshot.ScreenshotActionChip;
import com.android.systemui.screenshot.TimeoutHandler;
import java.io.IOException;
import java.util.ArrayList;
/**
* Controls state and UI for the overlay that appears when something is added to the clipboard
@@ -93,6 +101,7 @@ public class ClipboardOverlayController {
private final PhoneWindow mWindow;
private final TimeoutHandler mTimeoutHandler;
private final AccessibilityManager mAccessibilityManager;
private final TextClassifier mTextClassifier;
private final DraggableConstraintLayout mView;
private final ImageView mImagePreview;
@@ -101,9 +110,13 @@ public class ClipboardOverlayController {
private final ScreenshotActionChip mRemoteCopyChip;
private final View mActionContainerBackground;
private final View mDismissButton;
private final LinearLayout mActionContainer;
private final ArrayList<ScreenshotActionChip> mActionChips = new ArrayList<>();
private Runnable mOnSessionCompleteListener;
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
private BroadcastReceiver mCloseDialogsReceiver;
@@ -117,6 +130,8 @@ public class ClipboardOverlayController {
mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null);
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
mTextClassifier = requireNonNull(context.getSystemService(TextClassificationManager.class))
.getTextClassifier();
mWindowManager = mContext.getSystemService(WindowManager.class);
@@ -134,8 +149,9 @@ public class ClipboardOverlayController {
mView = (DraggableConstraintLayout)
LayoutInflater.from(mContext).inflate(R.layout.clipboard_overlay, null);
mActionContainerBackground = requireNonNull(
mView.findViewById(R.id.actions_container_background));
mActionContainerBackground =
requireNonNull(mView.findViewById(R.id.actions_container_background));
mActionContainer = requireNonNull(mView.findViewById(R.id.actions));
mImagePreview = requireNonNull(mView.findViewById(R.id.image_preview));
mTextPreview = requireNonNull(mView.findViewById(R.id.text_preview));
mEditChip = requireNonNull(mView.findViewById(R.id.edit_chip));
@@ -143,7 +159,7 @@ public class ClipboardOverlayController {
mDismissButton = requireNonNull(mView.findViewById(R.id.dismiss_button));
mView.setOnDismissCallback(this::hideImmediate);
mView.setOnInteractionCallback(() -> mTimeoutHandler.resetTimeout());
mView.setOnInteractionCallback(mTimeoutHandler::resetTimeout);
mDismissButton.setOnClickListener(view -> animateOut());
@@ -166,7 +182,7 @@ public class ClipboardOverlayController {
withWindowAttached(() -> {
mWindow.setContentView(mView);
updateInsets(mWindowManager.getCurrentWindowMetrics().getWindowInsets());
mView.post(() -> getEnterAnimation().start());
mView.post(this::animateIn);
});
mTimeoutHandler.setOnTimeoutRunnable(this::animateOut);
@@ -199,12 +215,15 @@ public class ClipboardOverlayController {
void setClipData(ClipData clipData) {
reset();
if (clipData == null || clipData.getItemCount() == 0) {
showTextPreview(
mContext.getResources().getString(R.string.clipboard_overlay_text_copied));
showTextPreview(mContext.getResources().getString(
R.string.clipboard_overlay_text_copied));
} else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
showEditableText(clipData.getItemAt(0).getText());
ClipData.Item item = clipData.getItemAt(0);
if (item.getTextLinks() != null) {
AsyncTask.execute(() -> classifyText(clipData.getItemAt(0)));
}
showEditableText(item.getText());
} else if (clipData.getItemAt(0).getUri() != null) {
// How to handle non-image URIs?
showEditableImage(clipData.getItemAt(0).getUri());
@@ -212,7 +231,6 @@ public class ClipboardOverlayController {
showTextPreview(
mContext.getResources().getString(R.string.clipboard_overlay_text_copied));
}
mTimeoutHandler.resetTimeout();
}
@@ -220,10 +238,40 @@ public class ClipboardOverlayController {
mOnSessionCompleteListener = runnable;
}
private void classifyText(ClipData.Item item) {
ArrayList<RemoteAction> actions = new ArrayList<>();
for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
TextClassification classification = mTextClassifier.classifyText(
item.getText(), link.getStart(), link.getEnd(), null);
actions.addAll(classification.getActions());
}
mView.post(() -> {
for (ScreenshotActionChip chip : mActionChips) {
mActionContainer.removeView(chip);
}
mActionChips.clear();
for (RemoteAction action : actions) {
ScreenshotActionChip chip = constructActionChip(action);
mActionContainer.addView(chip);
mActionChips.add(chip);
}
});
}
private ScreenshotActionChip constructActionChip(RemoteAction action) {
ScreenshotActionChip chip = (ScreenshotActionChip) LayoutInflater.from(mContext).inflate(
R.layout.screenshot_action_chip, mActionContainer, false);
chip.setText(action.getTitle());
chip.setIcon(action.getIcon(), false);
chip.setPendingIntent(action.getActionIntent(), this::animateOut);
chip.setAlpha(1);
return chip;
}
private void monitorOutsideTouches() {
InputManager inputManager = mContext.getSystemService(InputManager.class);
InputMonitor monitor = inputManager.monitorGestureInput("clipboard overlay", 0);
mInputEventReceiver = new InputEventReceiver(monitor.getInputChannel(),
mInputMonitor = inputManager.monitorGestureInput("clipboard overlay", 0);
mInputEventReceiver = new InputEventReceiver(mInputMonitor.getInputChannel(),
Looper.getMainLooper()) {
@Override
public void onInputEvent(InputEvent event) {
@@ -311,6 +359,10 @@ public class ClipboardOverlayController {
return nearbyIntent;
}
private void animateIn() {
getEnterAnimation().start();
}
private void animateOut() {
getExitAnimation().start();
}
@@ -390,6 +442,10 @@ public class ClipboardOverlayController {
mInputEventReceiver.dispose();
mInputEventReceiver = null;
}
if (mInputMonitor != null) {
mInputMonitor.dispose();
mInputMonitor = null;
}
if (mOnSessionCompleteListener != null) {
mOnSessionCompleteListener.run();
}
@@ -398,6 +454,10 @@ public class ClipboardOverlayController {
private void reset() {
mView.setTranslationX(0);
mView.setAlpha(0);
for (ScreenshotActionChip chip : mActionChips) {
mActionContainer.removeView(chip);
}
mActionChips.clear();
mTimeoutHandler.cancelTimeout();
}

View File

@@ -21,7 +21,6 @@ import android.content.Context;
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -129,7 +128,6 @@ public class ScreenshotActionChip extends FrameLayout {
iconParams.setMarginStart(paddingHorizontal);
iconParams.setMarginEnd(paddingHorizontal);
}
mTextView.setVisibility(hasText ? View.VISIBLE : View.GONE);
mIconView.setLayoutParams(iconParams);
mTextView.setLayoutParams(textParams);
}