From b08013c312e3d849029a2f4c11889274c00f438d Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Thu, 16 Sep 2010 16:28:11 -0700 Subject: [PATCH] Added overlay support for drawing/responding to text anchors. Overlays let views draw and respond to touch events outside of their bounds. This allows selection anchors to be friendlier and easier to grab. This is currently private API, pending further evaluation. Added themes/styles for text selection anchors. Added assets for text selection anchors as provided by UX. The left/right anchors are currently not suitable for use. They are here for bookkeeping and replacement later. The theme currently uses the 'middle' anchor asset for all three. This will be changed once assets are ready. Change-Id: I01b21e5ae90cab201f86f38f2f5eeaf2bd7f6bcd --- api/current.xml | 79 ++++++++------ core/java/android/view/View.java | 57 ++++++++++ core/java/android/view/ViewGroup.java | 101 +++++++++++++++++- core/java/android/view/ViewParent.java | 7 ++ core/java/android/view/ViewRoot.java | 18 ++++ core/java/android/widget/TextView.java | 100 +++++++++++++++-- .../drawable-hdpi/text_select_handle_left.png | Bin 0 -> 620 bytes .../text_select_handle_middle.png | Bin 0 -> 718 bytes .../text_select_handle_right.png | Bin 0 -> 697 bytes core/res/res/values/attrs.xml | 25 +++++ core/res/res/values/public.xml | 3 + core/res/res/values/styles.xml | 3 + core/res/res/values/themes.xml | 5 + 13 files changed, 354 insertions(+), 44 deletions(-) create mode 100644 core/res/res/drawable-hdpi/text_select_handle_left.png create mode 100644 core/res/res/drawable-hdpi/text_select_handle_middle.png create mode 100644 core/res/res/drawable-hdpi/text_select_handle_right.png diff --git a/api/current.xml b/api/current.xml index aff615c95a085..8651c4d7e6e97 100644 --- a/api/current.xml +++ b/api/current.xml @@ -5828,28 +5828,6 @@ visibility="public" > - - - - - - + + + + + + + + Warning: Views that use this feature should take care to disable/enable overlay + * appropriately when they are attached/detached from their window. All overlays should be + * disabled when detached. + * + * @param enabled true if overlay drawing should be enabled for this view, false otherwise + * + * @see #onDrawOverlay(Canvas) + * + * @hide + */ + protected void setOverlayEnabled(boolean enabled) { + final boolean oldValue = (mPrivateFlags & HAS_OVERLAY) == HAS_OVERLAY; + mPrivateFlags = (mPrivateFlags & ~HAS_OVERLAY) | (enabled ? HAS_OVERLAY : 0); + if (enabled != oldValue) { + final ViewParent parent = getParent(); + if (parent != null) { + try { + parent.childOverlayStateChanged(this); + } catch (AbstractMethodError e) { + Log.e(VIEW_LOG_TAG, "Could not propagate hasOverlay state", e); + } + } + } + } + + /** + * @return true if this View has an overlay enabled. + * + * @see #setOverlayEnabled(boolean) + * @see #onDrawOverlay(Canvas) + * + * @hide + */ + public boolean isOverlayEnabled() { + return (mPrivateFlags & HAS_OVERLAY) == HAS_OVERLAY; + } + + /** + * Override this method to draw on an overlay layer above all other views in the window + * after the standard drawing pass is complete. This allows a view to draw outside its + * normal boundaries. + * @hide + */ + public void onDrawOverlay(Canvas canvas) { + } + private void resetPressedState() { if ((mViewFlags & ENABLED_MASK) == DISABLED) { return; diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 28bed3a0d4896..fd6769ca64006 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -227,6 +227,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000; + /** + * When set, at least one child of this ViewGroup will return true from hasOverlay. + */ + private static final int FLAG_CHILD_HAS_OVERLAY = 0x100000; + /** * Indicates which types of drawing caches are to be kept in memory. * This field should be made private, so it is hidden from the SDK. @@ -854,6 +859,34 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int scrolledYInt = (int) scrolledYFloat; final View[] children = mChildren; final int count = mChildrenCount; + + // Check for children with overlays first. They don't rely on hit rects to determine + // if they can accept a new touch event. + if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) { + for (int i = count - 1; i >= 0; i--) { + final View child = children[i]; + // Don't let children respond to events as an overlay during an animation. + if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE + && child.getAnimation() == null + && child.isOverlayEnabled()) { + // offset the event to the view's coordinate system + final float xc = scrolledXFloat - child.mLeft; + final float yc = scrolledYFloat - child.mTop; + ev.setLocation(xc, yc); + child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; + if (child.dispatchTouchEvent(ev)) { + // Event handled, we have a target now. + mMotionTarget = child; + return true; + } + // The event didn't get handled, try the next view. + // Don't reset the event's location, it's not + // necessary here. + } + } + } + + // Now check views normally. for (int i = count - 1; i >= 0; i--) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE @@ -2312,6 +2345,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (clearChildFocus != null) { clearChildFocus(clearChildFocus); } + + mGroupFlags &= ~FLAG_CHILD_HAS_OVERLAY; } /** @@ -2534,7 +2569,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int left = mLeft; final int top = mTop; - if (dirty.intersect(0, 0, mRight - left, mBottom - top) || + if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY || + dirty.intersect(0, 0, mRight - left, mBottom - top) || (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) { mPrivateFlags &= ~DRAWING_CACHE_VALID; @@ -3452,6 +3488,69 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mAnimationListener = animationListener; } + /** + * Called when a child's overlay state changes between enabled/disabled. + * @param child Child view whose state has changed or null + * @hide + */ + public void childOverlayStateChanged(View child) { + boolean childHasOverlay = false; + if (child != null) { + childHasOverlay = child.isOverlayEnabled(); + } else { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + if (childHasOverlay |= getChildAt(i).isOverlayEnabled()) { + break; + } + } + } + + final boolean hasChildWithOverlay = childHasOverlay || + (mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY; + + final boolean oldValue = isOverlayEnabled(); + mGroupFlags = (mGroupFlags & ~FLAG_CHILD_HAS_OVERLAY) | + (hasChildWithOverlay ? FLAG_CHILD_HAS_OVERLAY : 0); + if (isOverlayEnabled() != oldValue) { + final ViewParent parent = getParent(); + if (parent != null) { + try { + parent.childOverlayStateChanged(this); + } catch (AbstractMethodError e) { + Log.e("ViewGroup", "Could not propagate hasOverlay state", e); + } + } + } + } + + /** + * @hide + */ + public boolean isOverlayEnabled() { + return super.isOverlayEnabled() || + ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY); + } + + /** + * @hide + */ + @Override + public void onDrawOverlay(Canvas canvas) { + if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (child.isOverlayEnabled()) { + canvas.translate(child.mLeft + child.mScrollX, child.mTop + child.mScrollY); + child.onDrawOverlay(canvas); + canvas.translate(-(child.mLeft + child.mScrollX), + -(child.mTop + child.mScrollY)); + } + } + } + } + /** * LayoutParams are used by views to tell their parents how they want to be * laid out. See diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index b456c5d108d41..a0d3618486f08 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -208,4 +208,11 @@ public interface ViewParent { */ public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate); + + /** + * Called when a child view's overlay state changes between enabled/disabled. + * @param child Child view whose state changed or null. + * @hide + */ + public void childOverlayStateChanged(View child); } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 57c9055552b08..acec4762adf13 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -222,6 +222,8 @@ public final class ViewRoot extends Handler implements ViewParent, private final int mDensity; + private boolean mHasOverlay; + public static IWindowSession getWindowSession(Looper mainLooper) { synchronized (mStaticInit) { if (!mInitialized) { @@ -1518,6 +1520,9 @@ public final class ViewRoot extends Handler implements ViewParent, canvas.setScreenDensity(scalingRequired ? DisplayMetrics.DENSITY_DEVICE : 0); mView.draw(canvas); + if (mHasOverlay) { + mView.onDrawOverlay(canvas); + } } finally { mAttachInfo.mIgnoreDirtyState = false; canvas.restoreToCount(saveCount); @@ -2914,6 +2919,19 @@ public final class ViewRoot extends Handler implements ViewParent, return scrollToRectOrFocus(rectangle, immediate); } + /** + * @hide + */ + public void childOverlayStateChanged(View child) { + final boolean oldState = mHasOverlay; + mHasOverlay = child.isOverlayEnabled(); + // Invalidate the whole thing when we change overlay states just in case + // something left chunks of data drawn someplace it shouldn't have. + if (mHasOverlay != oldState) { + child.invalidate(); + } + } + class TakenSurfaceHolder extends BaseSurfaceHolder { @Override public boolean onAllowLockCanvas() { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index e97bbfb891165..cc8c1fde7e6b8 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -285,6 +285,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } InputMethodState mInputMethodState; + private int mTextSelectHandleLeftRes; + private int mTextSelectHandleRightRes; + private int mTextSelectHandleRes; + /* * Kick-start the font cache for the zygote process (to pay the cost of * initializing freetype for our default font only once). @@ -705,6 +709,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Log.w(LOG_TAG, "Failure reading input extras", e); } break; + + case com.android.internal.R.styleable.TextView_textSelectHandleLeft: + mTextSelectHandleLeftRes = a.getResourceId(attr, 0); + break; + + case com.android.internal.R.styleable.TextView_textSelectHandleRight: + mTextSelectHandleRightRes = a.getResourceId(attr, 0); + break; + + case com.android.internal.R.styleable.TextView_textSelectHandle: + mTextSelectHandleRes = a.getResourceId(attr, 0); + break; } } a.recycle(); @@ -3733,6 +3749,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener showError(); mShowErrorAfterAttach = false; } + + updateOverlay(); } @Override @@ -3750,6 +3768,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mError != null) { hideError(); } + + setOverlayEnabled(false); } @Override @@ -4100,7 +4120,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ canvas.restore(); + } + /** + * @hide + */ + @Override + public void onDrawOverlay(Canvas canvas) { if (mInsertionPointCursorController != null) { mInsertionPointCursorController.draw(canvas); } @@ -6679,10 +6705,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public boolean onTouchEvent(MotionEvent event) { final int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { + // Check to see if we're testing for our anchor overlay. + boolean handled = false; + final float x = event.getX(); + final float y = event.getY(); + if (x < mLeft || x > mRight || y < mTop || y > mBottom) { + if (mInsertionPointCursorController != null) { + handled |= mInsertionPointCursorController.onTouchEvent(event); + } + if (mSelectionModifierCursorController != null) { + handled |= mSelectionModifierCursorController.onTouchEvent(event); + } + + if (!handled) { + return false; + } + } + // Reset this state; it will be re-set if super.onTouchEvent // causes focus to move to the view. mTouchFocusSelected = false; mScrolled = false; + + if (handled) { + return true; + } } final boolean superResult = super.onTouchEvent(event); @@ -7571,6 +7618,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + private void updateOverlay() { + boolean enableOverlay = false; + if (mSelectionModifierCursorController != null) { + enableOverlay |= mSelectionModifierCursorController.isShowing(); + } + if (mInsertionPointCursorController != null) { + enableOverlay |= mInsertionPointCursorController.isShowing(); + } + setOverlayEnabled(enableOverlay); + } + /** * A CursorController instance can be used to control a cursor in the text. * @@ -7593,6 +7651,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ public void hide(); + /** + * @return true if the CursorController is currently visible + */ + public boolean isShowing(); + /** * Update the controller's position. */ @@ -7615,7 +7678,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * a chance to become active and/or visible. * @param event The touch event */ - public void onTouchEvent(MotionEvent event); + public boolean onTouchEvent(MotionEvent event); /** * Draws a visual representation of the controller on the canvas. @@ -7649,10 +7712,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final Rect bounds = sCursorControllerTempRect; bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - drawableWidth / 2.0) + mScrollX; - bounds.top = (bottom ? lineBottom : lineTop) - drawableHeight / 2 + mScrollY; + bounds.top = (bottom ? lineBottom : lineTop) + mScrollY; mTopExtension = bottom ? 0 : drawableHeight / 2; - mBottomExtension = drawableHeight; + mBottomExtension = 0; //drawableHeight / 4; // Extend touch region up when editing the last line of text (or a single line) so that // it is easier to grab. @@ -7710,7 +7773,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener InsertionPointCursorController() { Resources res = mContext.getResources(); - mHandle = new Handle(res.getDrawable(com.android.internal.R.drawable.text_select_handle)); + mHandle = new Handle(res.getDrawable(mTextSelectHandleRes)); } public void show() { @@ -7718,6 +7781,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Has to be done after updateDrawablePosition, so that previous position invalidate // in only done if necessary. mIsVisible = true; + updateOverlay(); } public void hide() { @@ -7731,6 +7795,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + public boolean isShowing() { + return mIsVisible; + } + public void draw(Canvas canvas) { if (mIsVisible) { int time = (int) (System.currentTimeMillis() - mFadeOutTimerStart); @@ -7746,6 +7814,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { mHandle.mDrawable.setAlpha(0); mIsVisible = false; + updateOverlay(); } } mHandle.mDrawable.draw(canvas); @@ -7774,6 +7843,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Should never happen, safety check. Log.w(LOG_TAG, "Update cursor controller position called with no cursor"); mIsVisible = false; + updateOverlay(); return; } @@ -7783,7 +7853,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mHandle.mDrawable.setAlpha(255); } - public void onTouchEvent(MotionEvent event) { + public boolean onTouchEvent(MotionEvent event) { if (isFocused() && isTextEditable() && mIsVisible) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN : { @@ -7811,8 +7881,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mOffsetY += viewportToContentVerticalOffset(); mOnDownTimerStart = event.getEventTime(); + return true; } - break; + return false; } case MotionEvent.ACTION_UP : { @@ -7830,6 +7901,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } } + return false; } public float getOffsetX() { @@ -7859,8 +7931,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener SelectionModifierCursorController() { Resources res = mContext.getResources(); - mStartHandle = new Handle(res.getDrawable(com.android.internal.R.drawable.text_select_handle)); - mEndHandle = new Handle(res.getDrawable(com.android.internal.R.drawable.text_select_handle)); + mStartHandle = new Handle(res.getDrawable(mTextSelectHandleLeftRes)); + mEndHandle = new Handle(res.getDrawable(mTextSelectHandleRightRes)); } public void show() { @@ -7868,6 +7940,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Has to be done after updateDrawablePositions, so that previous position invalidate // in only done if necessary. mIsVisible = true; + updateOverlay(); mFadeOutTimerStart = -1; hideInsertionPointCursorController(); } @@ -7880,8 +7953,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + public boolean isShowing() { + return mIsVisible; + } + public void cancelFadeOutAnimation() { mIsVisible = false; + updateOverlay(); mStartHandle.postInvalidate(); mEndHandle.postInvalidate(); } @@ -7900,6 +7978,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mStartHandle.mDrawable.setAlpha(0); mEndHandle.mDrawable.setAlpha(0); mIsVisible = false; + updateOverlay(); } } mStartHandle.mDrawable.draw(canvas); @@ -7957,6 +8036,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Should never happen, safety check. Log.w(LOG_TAG, "Update selection controller position called with no cursor"); mIsVisible = false; + updateOverlay(); return; } @@ -7969,7 +8049,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mEndHandle.mDrawable.setAlpha(255); } - public void onTouchEvent(MotionEvent event) { + public boolean onTouchEvent(MotionEvent event) { if (isTextEditable()) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: @@ -8004,6 +8084,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mOnDownTimerStart = event.getEventTime(); ((ArrowKeyMovementMethod)mMovement).setCursorController(this); + return true; } } } @@ -8029,6 +8110,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener break; } } + return false; } /** diff --git a/core/res/res/drawable-hdpi/text_select_handle_left.png b/core/res/res/drawable-hdpi/text_select_handle_left.png new file mode 100644 index 0000000000000000000000000000000000000000..271a6d031e1f4142bc7b7e565d8d14c860b8930a GIT binary patch literal 620 zcmeAS@N?(olHy`uVBq!ia0vp^9zYzy!3HG5tT)~PQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07?}7xT^vIyZoRqf?RO|Z+AmKrQWsNyMsHo`By-5Te#knGkq(kBp>>?t#7+oS<$ptr<~R6{Mdb0g@5m= zjP|@P@$dEZmkKKrFRxy6BTFUo+5UR}*L+qhrpZVK<=zgNx_;Y5u@&*hz=_V#-B8Q0KP)-N_Z>l2^(In7tiI^&j7@N2$T*X|SwoIau-@vVF*U&e(G ze|}`$*Lkh+w(Z7~totw47X)2)Y%l$OyxS+YL8YU)>B-qe{`Xh1-&()xvFkFH!q@iw z$`c)GIUjA^BdPcK%iLQNrb&Ku5}P@bb(7Ckze^trZnG;iFfeg|hzzopr010dlQ~&?~ literal 0 HcmV?d00001 diff --git a/core/res/res/drawable-hdpi/text_select_handle_middle.png b/core/res/res/drawable-hdpi/text_select_handle_middle.png new file mode 100644 index 0000000000000000000000000000000000000000..5a83c6cab4f364616700461e59f48f6a02dc3d66 GIT binary patch literal 718 zcmeAS@N?(olHy`uVBq!ia0vp^9zYzy!3HG5tT)~PQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07?=t?T^vIyZoRp^H}7(S$g#rPp1p^H%G(w)Eiv=i*AnMc z%&6P4G>BXE?u`a*j`DzMVj(S)8byVs_HT`hyrdvDORV5l&F}8yE-e)mh2GA&AM7VB z)#zG#-G2V(7rj$f?0c^rIBnIc^!47^#oe*D&&zL})4OzS*2nyF|F6Fef6VYDtMuHC z30FSNT6O13ily!G;C)-}9%onocI?(?{%iHTUw--B@=?3e^yT84o4%(X?$~$f#jdS~ zm(AVzbxT+$mq)kI^SgIn^Dh&6b?>~z{rR(GKJ7D_>~$v2?91M_OSN~Nu(Ijm)4D&; z{7XyNgo#l_Pj3cgkQa#nG__XS_s+rj&`&2|5}?6U#KhfaoDQx&H9+?ajo8|M{283TDogi;7+>XUvP6#mDp~D^JHdV}gQQ+LI>R z$yW=zOJ6RVI(L?-n8T*+krO6r@kkwczBb{>EZgf=IhHe@uFbN%rmR*yd(VR@Zmo;| z+%WcCKB=uICiD5Rtu;E<8fO&b%nsPg-k$pEdEB>q-Tlt&6-H~0zEplU>ptrb*I47! z^`dLi)%=vjG|#P%Z#o>=zbt@(kww4(Oo%`z5StY$1Y)zGsxbM)^)~&0yRN#K`PCOY zyzYN}%=%^Dy literal 0 HcmV?d00001 diff --git a/core/res/res/drawable-hdpi/text_select_handle_right.png b/core/res/res/drawable-hdpi/text_select_handle_right.png new file mode 100644 index 0000000000000000000000000000000000000000..dfdf899c3b3f783e28cc14685ec728338be72854 GIT binary patch literal 697 zcmeAS@N?(olHy`uVBq!ia0vp^9zYzy!3HG5tT)~PQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07?`3xT^vIyZoRp6+FLqMv84kio9Cf|Np?dm}6_TADeaf9#E5de$iU+){VY} znTvOxtKpAf+RSmd{l4WLW@Wq7_w{u@KlG_uh0J@NS=)0k&eHHw`n$bzJ^MLd^&1I& zoUvijrCoE4wqKLGTg`RyXIHMi{fAe9;mgyi7uDpv7wLa<^5<5khpVD|UbFn2613d= zm`i>C8J_60e}C`XJ^p05qGRvVRqE>7wE48pO@DMTv#hXqzsOIPxz#HkU72feWUcg9 z#(DL|lh3)7dBjWTmi}S9H+{-t=anx1oL$%}61rKp#+)s5-TA5}l-XwYhI{)M>vW@a zHauOT$X4}qhW&y2XP2pa1WYyw^^g6yHfeuAX4SSYAOEveXb63&o>k>zdLUn|D61iV z?>sr)uMFn@G|OJi_{u1Eeueao`t(y5lYFDj?KhsfD!qJ}y7bzuF)yNYRy>{b>Rd>C zm2Pojw&Lcc-8&*RT7;|I)f}hDUNN0uCY$42(buM6g0A1ba#B$>#Ul#PoyKSuJ|@;=5+g9bLKX zk4koaOP^)2i(LN8tk%H5#G%lj0ii%_E(I9710(~MW?%xdtwQWsBp6O*o$rxN6)6Fx OMFvk-KbLh*2~7Z!JuWc- literal 0 HcmV?d00001 diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 13c3e7eacab95..ac1c0dd0fa955 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -451,6 +451,21 @@ + + + + + + + + + + + + @@ -2152,6 +2167,16 @@ EditorInfo.extras} field when the input method is connected. --> + + + + + + + + @android:drawable/text_select_handle_middle + @android:drawable/text_select_handle_middle + @android:drawable/text_select_handle_middle + @android:style/Widget.AbsListView @android:style/Widget.AutoCompleteTextView