summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Adrian Roos <roosa@google.com> 2016-03-17 19:55:17 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2016-03-17 19:55:19 +0000
commit237be37fadda27be2bbb66aafb3e39ad0eefdc3b (patch)
tree8c933c705c95215cb27c034e1b1f502f7415dff3
parent365de1594fa969bc5fd807e452142ef15d94acb4 (diff)
parent0bd8a4b29bf92a901855d889c53186383dd2c5e7 (diff)
Merge "Copy/Paste on RemoteInputView" into nyc-dev
-rw-r--r--core/java/android/widget/TextView.java15
-rw-r--r--packages/SystemUI/res/layout/remote_input.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java361
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/LongPressCancelable.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java7
9 files changed, 459 insertions, 13 deletions
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8a1a8c554635..506035087ead 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9646,7 +9646,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
boolean canShare() {
- return canCopy() && isDeviceProvisioned();
+ if (!getContext().canStartActivityForResult() || !isDeviceProvisioned()) {
+ return false;
+ }
+ return canCopy();
}
boolean isDeviceProvisioned() {
@@ -9669,16 +9672,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
boolean canProcessText() {
- if (!getContext().canStartActivityForResult() || getId() == View.NO_ID
- || hasPasswordTransformationMethod()) {
+ if (getId() == View.NO_ID) {
return false;
}
-
- if (mText.length() > 0 && hasSelection() && mEditor != null) {
- return true;
- }
-
- return false;
+ return canShare();
}
boolean canSelectAllText() {
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index 75195c4ffbcc..a95489b33013 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -43,6 +43,7 @@
android:singleLine="true"
android:ellipsize="start"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
+ android:textIsSelectable="true"
android:imeOptions="actionSend|flagNoExtractUi" />
<FrameLayout
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 8f1517d9dfe0..bb4a771ec3d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1107,6 +1107,7 @@ public abstract class BaseStatusBar extends SystemUI implements
});
a.start();
guts.setExposed(true);
+ row.closeRemoteInput();
mStackScroller.onHeightChanged(null, true /* needsAnimation */);
mNotificationGutsExposed = guts;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 246f15ee196a..22bb8ebb2dc4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -579,6 +579,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
+ public void closeRemoteInput() {
+ mPrivateLayout.closeRemoteInput();
+ mPublicLayout.closeRemoteInput();
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 3b875774681e..c2df292c0880 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -69,6 +69,9 @@ public class NotificationContentView extends FrameLayout {
private View mHeadsUpChild;
private HybridNotificationView mSingleLineView;
+ private RemoteInputView mExpandedRemoteInput;
+ private RemoteInputView mHeadsUpRemoteInput;
+
private NotificationViewWrapper mContractedWrapper;
private NotificationViewWrapper mExpandedWrapper;
private NotificationViewWrapper mHeadsUpWrapper;
@@ -743,15 +746,19 @@ public class NotificationContentView extends FrameLayout {
View bigContentView = mExpandedChild;
if (bigContentView != null) {
- applyRemoteInput(bigContentView, entry, hasRemoteInput);
+ mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput);
+ } else {
+ mExpandedRemoteInput = null;
}
View headsUpContentView = mHeadsUpChild;
if (headsUpContentView != null) {
- applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
+ mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
+ } else {
+ mHeadsUpRemoteInput = null;
}
}
- private void applyRemoteInput(View view, NotificationData.Entry entry, boolean hasRemoteInput) {
+ private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry, boolean hasRemoteInput) {
View actionContainerCandidate = view.findViewById(
com.android.internal.R.id.actions_container);
if (actionContainerCandidate instanceof FrameLayout) {
@@ -777,7 +784,20 @@ public class NotificationContentView extends FrameLayout {
color = mContext.getColor(R.color.default_remote_input_background);
}
riv.setBackgroundColor(color);
+
+ return riv;
}
+ return existing;
+ }
+ return null;
+ }
+
+ public void closeRemoteInput() {
+ if (mHeadsUpRemoteInput != null) {
+ mHeadsUpRemoteInput.close();
+ }
+ if (mExpandedRemoteInput != null) {
+ mExpandedRemoteInput.close();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index eb5b57e4cb15..95f26d4cde87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -16,24 +16,42 @@
package com.android.systemui.statusbar.phone;
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.LayoutRes;
import android.app.StatusBarManager;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.media.session.MediaSessionLegacyHelper;
+import android.net.Uri;
+import android.os.Bundle;
import android.os.IBinder;
import android.util.AttributeSet;
+import android.view.ActionMode;
+import android.view.InputQueue;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.SurfaceHolder;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
+import com.android.internal.view.FloatingActionMode;
+import com.android.internal.widget.FloatingToolbar;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.BaseStatusBar;
@@ -57,6 +75,13 @@ public class StatusBarWindowView extends FrameLayout {
private final Paint mTransparentSrcPaint = new Paint();
private FalsingManager mFalsingManager;
+ // Implements the floating action mode for TextView's Cut/Copy/Past menu. Normally provided by
+ // DecorView, but since this is a special window we have to roll our own.
+ private View mFloatingActionModeOriginatingView;
+ private ActionMode mFloatingActionMode;
+ private FloatingToolbar mFloatingToolbar;
+ private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
+
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
setMotionEventSplittingEnabled(false);
@@ -301,5 +326,341 @@ public class StatusBarWindowView extends FrameLayout {
a.recycle();
}
}
+
+ @Override
+ public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback,
+ int type) {
+ if (type == ActionMode.TYPE_FLOATING) {
+ return startActionMode(originalView, callback, type);
+ }
+ return super.startActionModeForChild(originalView, callback, type);
+ }
+
+ private ActionMode createFloatingActionMode(
+ View originatingView, ActionMode.Callback2 callback) {
+ if (mFloatingActionMode != null) {
+ mFloatingActionMode.finish();
+ }
+ cleanupFloatingActionModeViews();
+ final FloatingActionMode mode =
+ new FloatingActionMode(mContext, callback, originatingView);
+ mFloatingActionModeOriginatingView = originatingView;
+ mFloatingToolbarPreDrawListener =
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ mode.updateViewLocationInWindow();
+ return true;
+ }
+ };
+ return mode;
+ }
+
+ private void setHandledFloatingActionMode(ActionMode mode) {
+ mFloatingActionMode = mode;
+ mFloatingToolbar = new FloatingToolbar(mContext, mFakeWindow);
+ ((FloatingActionMode) mFloatingActionMode).setFloatingToolbar(mFloatingToolbar);
+ mFloatingActionMode.invalidate(); // Will show the floating toolbar if necessary.
+ mFloatingActionModeOriginatingView.getViewTreeObserver()
+ .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
+ }
+
+ private void cleanupFloatingActionModeViews() {
+ if (mFloatingToolbar != null) {
+ mFloatingToolbar.dismiss();
+ mFloatingToolbar = null;
+ }
+ if (mFloatingActionModeOriginatingView != null) {
+ if (mFloatingToolbarPreDrawListener != null) {
+ mFloatingActionModeOriginatingView.getViewTreeObserver()
+ .removeOnPreDrawListener(mFloatingToolbarPreDrawListener);
+ mFloatingToolbarPreDrawListener = null;
+ }
+ mFloatingActionModeOriginatingView = null;
+ }
+ }
+
+ private ActionMode startActionMode(
+ View originatingView, ActionMode.Callback callback, int type) {
+ ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
+ ActionMode mode = createFloatingActionMode(originatingView, wrappedCallback);
+ if (mode != null && wrappedCallback.onCreateActionMode(mode, mode.getMenu())) {
+ setHandledFloatingActionMode(mode);
+ } else {
+ mode = null;
+ }
+ return mode;
+ }
+
+ private class ActionModeCallback2Wrapper extends ActionMode.Callback2 {
+ private final ActionMode.Callback mWrapped;
+
+ public ActionModeCallback2Wrapper(ActionMode.Callback wrapped) {
+ mWrapped = wrapped;
+ }
+
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ return mWrapped.onCreateActionMode(mode, menu);
+ }
+
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ requestFitSystemWindows();
+ return mWrapped.onPrepareActionMode(mode, menu);
+ }
+
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ return mWrapped.onActionItemClicked(mode, item);
+ }
+
+ public void onDestroyActionMode(ActionMode mode) {
+ mWrapped.onDestroyActionMode(mode);
+ if (mode == mFloatingActionMode) {
+ cleanupFloatingActionModeViews();
+ mFloatingActionMode = null;
+ }
+ requestFitSystemWindows();
+ }
+
+ @Override
+ public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
+ if (mWrapped instanceof ActionMode.Callback2) {
+ ((ActionMode.Callback2) mWrapped).onGetContentRect(mode, view, outRect);
+ } else {
+ super.onGetContentRect(mode, view, outRect);
+ }
+ }
+ }
+
+ /**
+ * Minimal window to satisfy FloatingToolbar.
+ */
+ private Window mFakeWindow = new Window(mContext) {
+ @Override
+ public void takeSurface(SurfaceHolder.Callback2 callback) {
+ }
+
+ @Override
+ public void takeInputQueue(InputQueue.Callback callback) {
+ }
+
+ @Override
+ public boolean isFloating() {
+ return false;
+ }
+
+ @Override
+ public void alwaysReadCloseOnTouchAttr() {
+ }
+
+ @Override
+ public void setContentView(@LayoutRes int layoutResID) {
+ }
+
+ @Override
+ public void setContentView(View view) {
+ }
+
+ @Override
+ public void setContentView(View view, ViewGroup.LayoutParams params) {
+ }
+
+ @Override
+ public void addContentView(View view, ViewGroup.LayoutParams params) {
+ }
+
+ @Override
+ public void clearContentView() {
+ }
+
+ @Override
+ public View getCurrentFocus() {
+ return null;
+ }
+
+ @Override
+ public LayoutInflater getLayoutInflater() {
+ return null;
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ }
+
+ @Override
+ public void setTitleColor(@ColorInt int textColor) {
+ }
+
+ @Override
+ public void openPanel(int featureId, KeyEvent event) {
+ }
+
+ @Override
+ public void closePanel(int featureId) {
+ }
+
+ @Override
+ public void togglePanel(int featureId, KeyEvent event) {
+ }
+
+ @Override
+ public void invalidatePanelMenu(int featureId) {
+ }
+
+ @Override
+ public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
+ return false;
+ }
+
+ @Override
+ public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
+ return false;
+ }
+
+ @Override
+ public void closeAllPanels() {
+ }
+
+ @Override
+ public boolean performContextMenuIdentifierAction(int id, int flags) {
+ return false;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ }
+
+ @Override
+ public void setBackgroundDrawable(Drawable drawable) {
+ }
+
+ @Override
+ public void setFeatureDrawableResource(int featureId, @DrawableRes int resId) {
+ }
+
+ @Override
+ public void setFeatureDrawableUri(int featureId, Uri uri) {
+ }
+
+ @Override
+ public void setFeatureDrawable(int featureId, Drawable drawable) {
+ }
+
+ @Override
+ public void setFeatureDrawableAlpha(int featureId, int alpha) {
+ }
+
+ @Override
+ public void setFeatureInt(int featureId, int value) {
+ }
+
+ @Override
+ public void takeKeyEvents(boolean get) {
+ }
+
+ @Override
+ public boolean superDispatchKeyEvent(KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean superDispatchTouchEvent(MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean superDispatchTrackballEvent(MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean superDispatchGenericMotionEvent(MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public View getDecorView() {
+ return StatusBarWindowView.this;
+ }
+
+ @Override
+ public View peekDecorView() {
+ return null;
+ }
+
+ @Override
+ public Bundle saveHierarchyState() {
+ return null;
+ }
+
+ @Override
+ public void restoreHierarchyState(Bundle savedInstanceState) {
+ }
+
+ @Override
+ protected void onActive() {
+ }
+
+ @Override
+ public void setChildDrawable(int featureId, Drawable drawable) {
+ }
+
+ @Override
+ public void setChildInt(int featureId, int value) {
+ }
+
+ @Override
+ public boolean isShortcutKey(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public void setVolumeControlStream(int streamType) {
+ }
+
+ @Override
+ public int getVolumeControlStream() {
+ return 0;
+ }
+
+ @Override
+ public int getStatusBarColor() {
+ return 0;
+ }
+
+ @Override
+ public void setStatusBarColor(@ColorInt int color) {
+ }
+
+ @Override
+ public int getNavigationBarColor() {
+ return 0;
+ }
+
+ @Override
+ public void setNavigationBarColor(@ColorInt int color) {
+ }
+
+ @Override
+ public void setDecorCaptionShade(int decorCaptionShade) {
+ }
+
+ @Override
+ public void setResizingCaptionDrawable(Drawable drawable) {
+ }
+
+ @Override
+ public void onMultiWindowChanged() {
+ }
+
+ @Override
+ public void reportActivityRelaunched() {
+ }
+ };
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 29b0f4b75876..3a0336bff905 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -29,8 +29,10 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewParent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -44,6 +46,7 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.stack.LongPressCancelable;
/**
* Host for the remote input.
@@ -64,6 +67,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private RemoteInputController mController;
private NotificationData.Entry mEntry;
+ private LongPressCancelable mLongPressCancelable;
public RemoteInputView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -226,6 +230,30 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
updateSendButton();
}
+ public void close() {
+ mEditText.defocusIfNeeded();
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ if (mLongPressCancelable == null) {
+ ViewParent p = getParent();
+ while (p != null) {
+ if (p instanceof LongPressCancelable) {
+ mLongPressCancelable = (LongPressCancelable) p;
+ break;
+ }
+ p = p.getParent();
+ }
+ }
+ if (mLongPressCancelable != null) {
+ mLongPressCancelable.requestDisallowLongPress();
+ }
+ }
+ return super.onInterceptTouchEvent(ev);
+ }
+
/**
* An EditText that changes appearance based on whether it's focusable and becomes
* un-focusable whenever the user navigates away from it or it becomes invisible.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/LongPressCancelable.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/LongPressCancelable.java
new file mode 100644
index 000000000000..05f0c07574bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/LongPressCancelable.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 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
+ */
+
+package com.android.systemui.statusbar.stack;
+
+/**
+ * Interface for container layouts that listen for long presses. A child that
+ * wants to handle long press can use this to cancel the parents long press logic.
+ */
+public interface LongPressCancelable {
+ /**
+ * Request that the view does not perform long press for the current touch.
+ */
+ void requestDisallowLongPress();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 59ec6112f4e1..686a71211dc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -83,7 +83,7 @@ import java.util.HashSet;
public class NotificationStackScrollLayout extends ViewGroup
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
- SettingsIconRowListener {
+ SettingsIconRowListener, LongPressCancelable {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -2627,6 +2627,11 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @Override
+ public void requestDisallowLongPress() {
+ removeLongPressCallback();
+ }
+
public void removeLongPressCallback() {
mSwipeHelper.removeLongPressCallback();
}