Draw a default focus highlight if needed.
am: 8062949ece
Change-Id: Ia06126f29168df05fe851746d86e15846ceca1b8
This commit is contained in:
@@ -3920,6 +3920,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
private int mBackgroundResource;
|
||||
private boolean mBackgroundSizeChanged;
|
||||
|
||||
/** The default focus highlight.
|
||||
* @see #mDefaultFocusHighlightEnabled
|
||||
* @see Drawable#hasFocusStateSpecified()
|
||||
*/
|
||||
private Drawable mDefaultFocusHighlight;
|
||||
private Drawable mDefaultFocusHighlightCache;
|
||||
private boolean mDefaultFocusHighlightSizeChanged;
|
||||
|
||||
private String mTransitionName;
|
||||
|
||||
static class TintInfo {
|
||||
@@ -6811,6 +6819,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
|
||||
}
|
||||
|
||||
// Here we check whether we still need the default focus highlight, and switch it on/off.
|
||||
switchDefaultFocusHighlight();
|
||||
|
||||
InputMethodManager imm = InputMethodManager.peekInstance();
|
||||
if (!gainFocus) {
|
||||
if (isPressed()) {
|
||||
@@ -11790,6 +11801,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
if (dr != null && isVisible != dr.isVisible()) {
|
||||
dr.setVisible(isVisible, false);
|
||||
}
|
||||
final Drawable hl = mDefaultFocusHighlight;
|
||||
if (hl != null && isVisible != hl.isVisible()) {
|
||||
hl.setVisible(isVisible, false);
|
||||
}
|
||||
final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
|
||||
if (fg != null && isVisible != fg.isVisible()) {
|
||||
fg.setVisible(isVisible, false);
|
||||
@@ -13003,6 +13018,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
if ((changed & DRAW_MASK) != 0) {
|
||||
if ((mViewFlags & WILL_NOT_DRAW) != 0) {
|
||||
if (mBackground != null
|
||||
|| mDefaultFocusHighlight != null
|
||||
|| (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) {
|
||||
mPrivateFlags &= ~PFLAG_SKIP_DRAW;
|
||||
} else {
|
||||
@@ -13074,6 +13090,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
|
||||
mBackgroundSizeChanged = true;
|
||||
mDefaultFocusHighlightSizeChanged = true;
|
||||
if (mForegroundInfo != null) {
|
||||
mForegroundInfo.mBoundsChanged = true;
|
||||
}
|
||||
@@ -13965,6 +13982,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
invalidate(true);
|
||||
}
|
||||
mBackgroundSizeChanged = true;
|
||||
mDefaultFocusHighlightSizeChanged = true;
|
||||
if (mForegroundInfo != null) {
|
||||
mForegroundInfo.mBoundsChanged = true;
|
||||
}
|
||||
@@ -14033,6 +14051,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
invalidate(true);
|
||||
}
|
||||
mBackgroundSizeChanged = true;
|
||||
mDefaultFocusHighlightSizeChanged = true;
|
||||
if (mForegroundInfo != null) {
|
||||
mForegroundInfo.mBoundsChanged = true;
|
||||
}
|
||||
@@ -14095,6 +14114,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
invalidate(true);
|
||||
}
|
||||
mBackgroundSizeChanged = true;
|
||||
mDefaultFocusHighlightSizeChanged = true;
|
||||
if (mForegroundInfo != null) {
|
||||
mForegroundInfo.mBoundsChanged = true;
|
||||
}
|
||||
@@ -14154,6 +14174,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
invalidate(true);
|
||||
}
|
||||
mBackgroundSizeChanged = true;
|
||||
mDefaultFocusHighlightSizeChanged = true;
|
||||
if (mForegroundInfo != null) {
|
||||
mForegroundInfo.mBoundsChanged = true;
|
||||
}
|
||||
@@ -18758,6 +18779,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
// Step 6, draw decorations (foreground, scrollbars)
|
||||
onDrawForeground(canvas);
|
||||
|
||||
// Step 7, draw the default focus highlight
|
||||
drawDefaultFocusHighlight(canvas);
|
||||
|
||||
if (debugDraw()) {
|
||||
debugDrawFocus(canvas);
|
||||
}
|
||||
@@ -19316,6 +19340,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
mPrivateFlags |= drawn;
|
||||
|
||||
mBackgroundSizeChanged = true;
|
||||
mDefaultFocusHighlightSizeChanged = true;
|
||||
if (mForegroundInfo != null) {
|
||||
mForegroundInfo.mBoundsChanged = true;
|
||||
}
|
||||
@@ -19467,6 +19492,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
|
||||
mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection);
|
||||
}
|
||||
if (mDefaultFocusHighlight != null) {
|
||||
mDefaultFocusHighlight.setLayoutDirection(layoutDirection);
|
||||
}
|
||||
mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED;
|
||||
onResolveDrawables(layoutDirection);
|
||||
}
|
||||
@@ -19525,7 +19553,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
// Avoid verifying the scroll bar drawable so that we don't end up in
|
||||
// an invalidation loop. This effectively prevents the scroll bar
|
||||
// drawable from triggering invalidations and scheduling runnables.
|
||||
return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who);
|
||||
return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who)
|
||||
|| (mDefaultFocusHighlight == who);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -19549,6 +19578,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
changed |= bg.setState(state);
|
||||
}
|
||||
|
||||
final Drawable hl = mDefaultFocusHighlight;
|
||||
if (hl != null && hl.isStateful()) {
|
||||
changed |= hl.setState(state);
|
||||
}
|
||||
|
||||
final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
|
||||
if (fg != null && fg.isStateful()) {
|
||||
changed |= fg.setState(state);
|
||||
@@ -19588,6 +19622,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
if (mBackground != null) {
|
||||
mBackground.setHotspot(x, y);
|
||||
}
|
||||
if (mDefaultFocusHighlight != null) {
|
||||
mDefaultFocusHighlight.setHotspot(x, y);
|
||||
}
|
||||
if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
|
||||
mForegroundInfo.mDrawable.setHotspot(x, y);
|
||||
}
|
||||
@@ -19623,6 +19660,104 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default focus highlight if it doesn't exist.
|
||||
* @return a default focus highlight.
|
||||
*/
|
||||
private Drawable getDefaultFocusHighlightDrawable() {
|
||||
if (mDefaultFocusHighlightCache == null) {
|
||||
if (mContext != null) {
|
||||
final int[] attrs = new int[] { android.R.attr.selectableItemBackground };
|
||||
final TypedArray ta = mContext.obtainStyledAttributes(attrs);
|
||||
mDefaultFocusHighlightCache = ta.getDrawable(0);
|
||||
ta.recycle();
|
||||
}
|
||||
}
|
||||
return mDefaultFocusHighlightCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current default focus highlight.
|
||||
* @param highlight the highlight drawable, or {@code null} if it's no longer needed.
|
||||
*/
|
||||
private void setDefaultFocusHighlight(Drawable highlight) {
|
||||
mDefaultFocusHighlight = highlight;
|
||||
mDefaultFocusHighlightSizeChanged = true;
|
||||
if (highlight != null) {
|
||||
if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
|
||||
mPrivateFlags &= ~PFLAG_SKIP_DRAW;
|
||||
}
|
||||
highlight.setLayoutDirection(getLayoutDirection());
|
||||
if (highlight.isStateful()) {
|
||||
highlight.setState(getDrawableState());
|
||||
}
|
||||
if (isAttachedToWindow()) {
|
||||
highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
|
||||
}
|
||||
// Set callback last, since the view may still be initializing.
|
||||
highlight.setCallback(this);
|
||||
} else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null
|
||||
&& (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) {
|
||||
mPrivateFlags |= PFLAG_SKIP_DRAW;
|
||||
}
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we need to draw a default focus highlight when this view gets focused,
|
||||
* which requires:
|
||||
* <ul>
|
||||
* <li>In the background, {@link android.R.attr#state_focused} is not defined.</li>
|
||||
* <li>This view is not in touch mode.</li>
|
||||
* <li>This view doesn't opt out for a default focus highlight, via
|
||||
* {@link #setDefaultFocusHighlightEnabled(boolean)}.</li>
|
||||
* </ul>
|
||||
* @return {@code true} if a default focus highlight is needed.
|
||||
*/
|
||||
private boolean isDefaultFocusHighlightNeeded(Drawable background) {
|
||||
final boolean hasFocusStateSpecified = background == null || !background.isStateful()
|
||||
|| !background.hasFocusStateSpecified();
|
||||
return !isInTouchMode() && getDefaultFocusHighlightEnabled() && hasFocusStateSpecified;
|
||||
}
|
||||
|
||||
/**
|
||||
* When this view is focused, switches on/off the default focused highlight.
|
||||
* <p>
|
||||
* This always happens when this view is focused, and only at this moment the default focus
|
||||
* highlight can be visible.
|
||||
*/
|
||||
private void switchDefaultFocusHighlight() {
|
||||
if (isFocused()) {
|
||||
final boolean needed = isDefaultFocusHighlightNeeded(mBackground);
|
||||
final boolean active = mDefaultFocusHighlight != null;
|
||||
if (needed && !active) {
|
||||
setDefaultFocusHighlight(getDefaultFocusHighlightDrawable());
|
||||
} else if (!needed && active) {
|
||||
// The highlight is no longer needed, so tear it down.
|
||||
setDefaultFocusHighlight(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the default focus highlight onto the canvas.
|
||||
* @param canvas the canvas where we're drawing the highlight.
|
||||
*/
|
||||
private void drawDefaultFocusHighlight(Canvas canvas) {
|
||||
if (mDefaultFocusHighlight != null) {
|
||||
if (mDefaultFocusHighlightSizeChanged) {
|
||||
mDefaultFocusHighlightSizeChanged = false;
|
||||
final int l = mScrollX;
|
||||
final int r = l + mRight - mLeft;
|
||||
final int t = mScrollY;
|
||||
final int b = t + mBottom - mTop;
|
||||
mDefaultFocusHighlight.setBounds(l, t, r, b);
|
||||
}
|
||||
mDefaultFocusHighlight.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of resource IDs of the drawable states representing the
|
||||
* current state of the view.
|
||||
@@ -19763,6 +19898,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
if (mStateListAnimator != null) {
|
||||
mStateListAnimator.jumpToCurrentState();
|
||||
}
|
||||
if (mDefaultFocusHighlight != null) {
|
||||
mDefaultFocusHighlight.jumpToCurrentState();
|
||||
}
|
||||
if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
|
||||
mForegroundInfo.mDrawable.jumpToCurrentState();
|
||||
}
|
||||
@@ -19907,6 +20045,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
/* Remove the background */
|
||||
mBackground = null;
|
||||
if ((mViewFlags & WILL_NOT_DRAW) != 0
|
||||
&& (mDefaultFocusHighlight == null)
|
||||
&& (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) {
|
||||
mPrivateFlags |= PFLAG_SKIP_DRAW;
|
||||
}
|
||||
@@ -20098,7 +20237,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
// Set callback last, since the view may still be initializing.
|
||||
foreground.setCallback(this);
|
||||
} else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) {
|
||||
} else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null
|
||||
&& (mDefaultFocusHighlight == null)) {
|
||||
mPrivateFlags |= PFLAG_SKIP_DRAW;
|
||||
}
|
||||
requestLayout();
|
||||
@@ -21913,6 +22053,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
// Similarly, we remove the foreground drawable's non-transparent parts.
|
||||
applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region);
|
||||
}
|
||||
if (mDefaultFocusHighlight != null
|
||||
&& mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) {
|
||||
// Similarly, we remove the default focus highlight's non-transparent parts.
|
||||
applyDrawableToTransparentRegion(mDefaultFocusHighlight, region);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user