Merge "Hide sensitive clipboard content" into tm-dev am: f87bf04abd
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17891363 Change-Id: Ic46b99ee011adf1de0e42dd0c7cc9cabac78fa97 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -121,6 +121,30 @@
|
|||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/hidden_text_preview"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:textFontWeight="500"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:text="@string/clipboard_text_hidden"
|
||||||
|
android:textColor="?attr/overlayButtonTextColor"
|
||||||
|
android:background="?androidprv:attr/colorAccentSecondary"
|
||||||
|
android:layout_width="@dimen/clipboard_preview_size"
|
||||||
|
android:layout_height="@dimen/clipboard_preview_size"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/hidden_image_preview"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:textFontWeight="500"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:text="@string/clipboard_text_hidden"
|
||||||
|
android:textColor="#ffffff"
|
||||||
|
android:background="#000000"
|
||||||
|
android:layout_width="@dimen/clipboard_preview_size"
|
||||||
|
android:layout_height="@dimen/clipboard_preview_size"/>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/dismiss_button"
|
android:id="@+id/dismiss_button"
|
||||||
@@ -141,4 +165,4 @@
|
|||||||
android:layout_margin="@dimen/overlay_dismiss_button_margin"
|
android:layout_margin="@dimen/overlay_dismiss_button_margin"
|
||||||
android:src="@drawable/overlay_cancel"/>
|
android:src="@drawable/overlay_cancel"/>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</com.android.systemui.screenshot.DraggableConstraintLayout>
|
</com.android.systemui.screenshot.DraggableConstraintLayout>
|
||||||
@@ -2495,6 +2495,8 @@
|
|||||||
<string name="clipboard_edit_image_description">Edit copied image</string>
|
<string name="clipboard_edit_image_description">Edit copied image</string>
|
||||||
<!-- Label for button to send copied content to a nearby device [CHAR LIMIT=NONE] -->
|
<!-- Label for button to send copied content to a nearby device [CHAR LIMIT=NONE] -->
|
||||||
<string name="clipboard_send_nearby_description">Send to nearby device</string>
|
<string name="clipboard_send_nearby_description">Send to nearby device</string>
|
||||||
|
<!-- Text informing user that copied content is hidden [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="clipboard_text_hidden">Tap to view</string>
|
||||||
|
|
||||||
<!-- Generic "add" string [CHAR LIMIT=NONE] -->
|
<!-- Generic "add" string [CHAR LIMIT=NONE] -->
|
||||||
<string name="add">Add</string>
|
<string name="add">Add</string>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import android.annotation.MainThread;
|
|||||||
import android.app.RemoteAction;
|
import android.app.RemoteAction;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipDescription;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -128,6 +129,8 @@ public class ClipboardOverlayController {
|
|||||||
private final View mClipboardPreview;
|
private final View mClipboardPreview;
|
||||||
private final ImageView mImagePreview;
|
private final ImageView mImagePreview;
|
||||||
private final TextView mTextPreview;
|
private final TextView mTextPreview;
|
||||||
|
private final TextView mHiddenTextPreview;
|
||||||
|
private final TextView mHiddenImagePreview;
|
||||||
private final View mPreviewBorder;
|
private final View mPreviewBorder;
|
||||||
private final OverlayActionChip mEditChip;
|
private final OverlayActionChip mEditChip;
|
||||||
private final OverlayActionChip mRemoteCopyChip;
|
private final OverlayActionChip mRemoteCopyChip;
|
||||||
@@ -186,6 +189,8 @@ public class ClipboardOverlayController {
|
|||||||
mClipboardPreview = requireNonNull(mView.findViewById(R.id.clipboard_preview));
|
mClipboardPreview = requireNonNull(mView.findViewById(R.id.clipboard_preview));
|
||||||
mImagePreview = requireNonNull(mView.findViewById(R.id.image_preview));
|
mImagePreview = requireNonNull(mView.findViewById(R.id.image_preview));
|
||||||
mTextPreview = requireNonNull(mView.findViewById(R.id.text_preview));
|
mTextPreview = requireNonNull(mView.findViewById(R.id.text_preview));
|
||||||
|
mHiddenTextPreview = requireNonNull(mView.findViewById(R.id.hidden_text_preview));
|
||||||
|
mHiddenImagePreview = requireNonNull(mView.findViewById(R.id.hidden_image_preview));
|
||||||
mPreviewBorder = requireNonNull(mView.findViewById(R.id.preview_border));
|
mPreviewBorder = requireNonNull(mView.findViewById(R.id.preview_border));
|
||||||
mEditChip = requireNonNull(mView.findViewById(R.id.edit_chip));
|
mEditChip = requireNonNull(mView.findViewById(R.id.edit_chip));
|
||||||
mRemoteCopyChip = requireNonNull(mView.findViewById(R.id.remote_copy_chip));
|
mRemoteCopyChip = requireNonNull(mView.findViewById(R.id.remote_copy_chip));
|
||||||
@@ -270,21 +275,32 @@ public class ClipboardOverlayController {
|
|||||||
mExitAnimator.cancel();
|
mExitAnimator.cancel();
|
||||||
}
|
}
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
boolean isSensitive = clipData != null && clipData.getDescription().getExtras() != null
|
||||||
|
&& clipData.getDescription().getExtras()
|
||||||
|
.getBoolean(ClipDescription.EXTRA_IS_SENSITIVE);
|
||||||
if (clipData == null || clipData.getItemCount() == 0) {
|
if (clipData == null || clipData.getItemCount() == 0) {
|
||||||
showTextPreview(mContext.getResources().getString(
|
showTextPreview(
|
||||||
R.string.clipboard_overlay_text_copied));
|
mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
|
||||||
|
mTextPreview);
|
||||||
} else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
|
} else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
|
||||||
ClipData.Item item = clipData.getItemAt(0);
|
ClipData.Item item = clipData.getItemAt(0);
|
||||||
if (item.getTextLinks() != null) {
|
if (item.getTextLinks() != null) {
|
||||||
AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource));
|
AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource));
|
||||||
}
|
}
|
||||||
showEditableText(item.getText());
|
if (isSensitive) {
|
||||||
|
showEditableText(
|
||||||
|
mContext.getResources().getString(R.string.clipboard_text_hidden), true);
|
||||||
|
} else {
|
||||||
|
showEditableText(item.getText(), false);
|
||||||
|
}
|
||||||
} else if (clipData.getItemAt(0).getUri() != null) {
|
} else if (clipData.getItemAt(0).getUri() != null) {
|
||||||
// How to handle non-image URIs?
|
// How to handle non-image URIs?
|
||||||
showEditableImage(clipData.getItemAt(0).getUri());
|
showEditableImage(clipData.getItemAt(0).getUri(), isSensitive);
|
||||||
} else {
|
} else {
|
||||||
showTextPreview(
|
showTextPreview(
|
||||||
mContext.getResources().getString(R.string.clipboard_overlay_text_copied));
|
mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
|
||||||
|
mTextPreview);
|
||||||
}
|
}
|
||||||
Intent remoteCopyIntent = getRemoteCopyIntent(clipData);
|
Intent remoteCopyIntent = getRemoteCopyIntent(clipData);
|
||||||
// Only show remote copy if it's available.
|
// Only show remote copy if it's available.
|
||||||
@@ -406,15 +422,23 @@ public class ClipboardOverlayController {
|
|||||||
animateOut();
|
animateOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showTextPreview(CharSequence text) {
|
private void showSinglePreview(View v) {
|
||||||
mTextPreview.setVisibility(View.VISIBLE);
|
mTextPreview.setVisibility(View.GONE);
|
||||||
mImagePreview.setVisibility(View.GONE);
|
mImagePreview.setVisibility(View.GONE);
|
||||||
mTextPreview.setText(text.subSequence(0, Math.min(500, text.length())));
|
mHiddenTextPreview.setVisibility(View.GONE);
|
||||||
|
mHiddenImagePreview.setVisibility(View.GONE);
|
||||||
|
v.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showTextPreview(CharSequence text, TextView textView) {
|
||||||
|
showSinglePreview(textView);
|
||||||
|
textView.setText(text.subSequence(0, Math.min(500, text.length())));
|
||||||
mEditChip.setVisibility(View.GONE);
|
mEditChip.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showEditableText(CharSequence text) {
|
private void showEditableText(CharSequence text, boolean hidden) {
|
||||||
showTextPreview(text);
|
TextView textView = hidden ? mHiddenTextPreview : mTextPreview;
|
||||||
|
showTextPreview(text, textView);
|
||||||
mEditChip.setVisibility(View.VISIBLE);
|
mEditChip.setVisibility(View.VISIBLE);
|
||||||
mActionContainerBackground.setVisibility(View.VISIBLE);
|
mActionContainerBackground.setVisibility(View.VISIBLE);
|
||||||
mEditChip.setAlpha(1f);
|
mEditChip.setAlpha(1f);
|
||||||
@@ -422,32 +446,36 @@ public class ClipboardOverlayController {
|
|||||||
mContext.getString(R.string.clipboard_edit_text_description));
|
mContext.getString(R.string.clipboard_edit_text_description));
|
||||||
View.OnClickListener listener = v -> editText();
|
View.OnClickListener listener = v -> editText();
|
||||||
mEditChip.setOnClickListener(listener);
|
mEditChip.setOnClickListener(listener);
|
||||||
mTextPreview.setOnClickListener(listener);
|
textView.setOnClickListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showEditableImage(Uri uri) {
|
private void showEditableImage(Uri uri, boolean isSensitive) {
|
||||||
ContentResolver resolver = mContext.getContentResolver();
|
|
||||||
try {
|
|
||||||
int size = mContext.getResources().getDimensionPixelSize(R.dimen.overlay_x_scale);
|
|
||||||
// The width of the view is capped, height maintains aspect ratio, so allow it to be
|
|
||||||
// taller if needed.
|
|
||||||
Bitmap thumbnail = resolver.loadThumbnail(uri, new Size(size, size * 4), null);
|
|
||||||
mImagePreview.setImageBitmap(thumbnail);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Thumbnail loading failed", e);
|
|
||||||
showTextPreview(
|
|
||||||
mContext.getResources().getString(R.string.clipboard_overlay_text_copied));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mTextPreview.setVisibility(View.GONE);
|
|
||||||
mImagePreview.setVisibility(View.VISIBLE);
|
|
||||||
mEditChip.setAlpha(1f);
|
mEditChip.setAlpha(1f);
|
||||||
mActionContainerBackground.setVisibility(View.VISIBLE);
|
mActionContainerBackground.setVisibility(View.VISIBLE);
|
||||||
View.OnClickListener listener = v -> editImage(uri);
|
View.OnClickListener listener = v -> editImage(uri);
|
||||||
|
if (isSensitive) {
|
||||||
|
showSinglePreview(mHiddenImagePreview);
|
||||||
|
mHiddenImagePreview.setOnClickListener(listener);
|
||||||
|
} else {
|
||||||
|
showSinglePreview(mImagePreview);
|
||||||
|
ContentResolver resolver = mContext.getContentResolver();
|
||||||
|
try {
|
||||||
|
int size = mContext.getResources().getDimensionPixelSize(R.dimen.overlay_x_scale);
|
||||||
|
// The width of the view is capped, height maintains aspect ratio, so allow it to be
|
||||||
|
// taller if needed.
|
||||||
|
Bitmap thumbnail = resolver.loadThumbnail(uri, new Size(size, size * 4), null);
|
||||||
|
mImagePreview.setImageBitmap(thumbnail);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Thumbnail loading failed", e);
|
||||||
|
showTextPreview(
|
||||||
|
mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
|
||||||
|
mTextPreview);
|
||||||
|
}
|
||||||
|
mImagePreview.setOnClickListener(listener);
|
||||||
|
}
|
||||||
mEditChip.setOnClickListener(listener);
|
mEditChip.setOnClickListener(listener);
|
||||||
mEditChip.setContentDescription(
|
mEditChip.setContentDescription(
|
||||||
mContext.getString(R.string.clipboard_edit_image_description));
|
mContext.getString(R.string.clipboard_edit_image_description));
|
||||||
mImagePreview.setOnClickListener(listener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent getRemoteCopyIntent(ClipData clipData) {
|
private Intent getRemoteCopyIntent(ClipData clipData) {
|
||||||
|
|||||||
@@ -20,10 +20,12 @@ import static java.util.Objects.requireNonNull;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipDescription;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
@@ -41,6 +43,7 @@ public class EditTextActivity extends Activity
|
|||||||
private EditText mEditText;
|
private EditText mEditText;
|
||||||
private ClipboardManager mClipboardManager;
|
private ClipboardManager mClipboardManager;
|
||||||
private TextView mAttribution;
|
private TextView mAttribution;
|
||||||
|
private boolean mSensitive;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -72,6 +75,9 @@ public class EditTextActivity extends Activity
|
|||||||
}
|
}
|
||||||
mEditText.setText(clip.getItemAt(0).getText());
|
mEditText.setText(clip.getItemAt(0).getText());
|
||||||
mEditText.requestFocus();
|
mEditText.requestFocus();
|
||||||
|
mSensitive = clip.getDescription().getExtras() != null
|
||||||
|
&& clip.getDescription().getExtras()
|
||||||
|
.getBoolean(ClipDescription.EXTRA_IS_SENSITIVE);
|
||||||
mClipboardManager.addPrimaryClipChangedListener(this);
|
mClipboardManager.addPrimaryClipChangedListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +94,9 @@ public class EditTextActivity extends Activity
|
|||||||
|
|
||||||
private void saveToClipboard() {
|
private void saveToClipboard() {
|
||||||
ClipData clip = ClipData.newPlainText("text", mEditText.getText());
|
ClipData clip = ClipData.newPlainText("text", mEditText.getText());
|
||||||
|
PersistableBundle extras = new PersistableBundle();
|
||||||
|
extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, mSensitive);
|
||||||
|
clip.getDescription().setExtras(extras);
|
||||||
mClipboardManager.setPrimaryClip(clip);
|
mClipboardManager.setPrimaryClip(clip);
|
||||||
hideImeAndFinish();
|
hideImeAndFinish();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user