Merge "Add action chips to clipboard overlay"
This commit is contained in:
committed by
Android (Google) Code Review
commit
fedcd5cc38
@@ -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
|
||||
|
||||
@@ -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(() -> {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user