diff options
| author | 2016-03-17 19:55:17 +0000 | |
|---|---|---|
| committer | 2016-03-17 19:55:19 +0000 | |
| commit | 237be37fadda27be2bbb66aafb3e39ad0eefdc3b (patch) | |
| tree | 8c933c705c95215cb27c034e1b1f502f7415dff3 | |
| parent | 365de1594fa969bc5fd807e452142ef15d94acb4 (diff) | |
| parent | 0bd8a4b29bf92a901855d889c53186383dd2c5e7 (diff) | |
Merge "Copy/Paste on RemoteInputView" into nyc-dev
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();      } |