Merge "Copy/Paste on RemoteInputView" into nyc-dev

am: 237be37

* commit '237be37fadda27be2bbb66aafb3e39ad0eefdc3b':
  Copy/Paste on RemoteInputView
This commit is contained in:
Adrian Roos
2016-03-17 20:02:46 +00:00
committed by android-build-merger
9 changed files with 459 additions and 13 deletions

View File

@@ -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() {

View File

@@ -43,6 +43,7 @@
android:singleLine="true"
android:ellipsize="start"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
android:textIsSelectable="true"
android:imeOptions="actionSend|flagNoExtractUi" />
<FrameLayout

View File

@@ -1111,6 +1111,7 @@ public abstract class BaseStatusBar extends SystemUI implements
});
a.start();
guts.setExposed(true);
row.closeRemoteInput();
mStackScroller.onHeightChanged(null, true /* needsAnimation */);
mNotificationGutsExposed = guts;
}

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -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() {
}
};
}

View File

@@ -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.

View File

@@ -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();
}

View File

@@ -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();
}