summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorFabrice Di Meglio <fdimeglio@google.com>2011-08-31 19:46:15 -0700
committerFabrice Di Meglio <fdimeglio@google.com>2011-09-02 18:03:21 -0700
commit34d2eba560f83f4eb665cdc039cf02bf96c201da (patch)
tree7afe896e6af294db1a0294c0204f34a7d5519365 /core
parentfead8f976700906101714b3265e64e30c0a80180 (diff)
downloadframeworks_base-34d2eba560f83f4eb665cdc039cf02bf96c201da.zip
frameworks_base-34d2eba560f83f4eb665cdc039cf02bf96c201da.tar.gz
frameworks_base-34d2eba560f83f4eb665cdc039cf02bf96c201da.tar.bz2
Fix bug #5243493 TextView selection is not working correctly when there is some RTL run into it
Part 2 - make selection handles aware of the run direction Change-Id: Idf41036de53d8968e7ae27eb87aea09e86bcd652
Diffstat (limited to 'core')
-rw-r--r--core/java/android/text/Layout.java29
-rw-r--r--core/java/android/widget/TextView.java99
2 files changed, 102 insertions, 26 deletions
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 768071f..bdfe940 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -673,6 +673,35 @@ public abstract class Layout {
return false;
}
+ /**
+ * Returns true if the character at offset is right to left (RTL).
+ * @param offset the offset
+ * @return true if the character is RTL, false if it is LTR
+ */
+ public boolean isRtlCharAt(int offset) {
+ int line = getLineForOffset(offset);
+ Directions dirs = getLineDirections(line);
+ if (dirs == DIRS_ALL_LEFT_TO_RIGHT) {
+ return false;
+ }
+ if (dirs == DIRS_ALL_RIGHT_TO_LEFT) {
+ return true;
+ }
+ int[] runs = dirs.mDirections;
+ int lineStart = getLineStart(line);
+ for (int i = 0; i < runs.length; i += 2) {
+ int start = lineStart + (runs[i] & RUN_LENGTH_MASK);
+ // No need to test the end as an offset after the last run should return the value
+ // corresponding of the last run
+ if (offset >= start) {
+ int level = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK;
+ return ((level & 1) != 0);
+ }
+ }
+ // Should happen only if the offset is "out of bounds"
+ return false;
+ }
+
private boolean primaryIsTrailingPrevious(int offset) {
int line = getLineForOffset(offset);
int lineStart = getLineStart(line);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index abf1281..0f30734 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10333,6 +10333,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private abstract class HandleView extends View implements TextViewPositionListener {
protected Drawable mDrawable;
+ protected Drawable mDrawableLtr;
+ protected Drawable mDrawableRtl;
private final PopupWindow mContainer;
// Position with respect to the parent TextView
private int mPositionX, mPositionY;
@@ -10355,7 +10357,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Used to delay the appearance of the action popup window
private Runnable mActionPopupShower;
- public HandleView() {
+ public HandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(TextView.this.mContext);
mContainer = new PopupWindow(TextView.this.mContext, null,
com.android.internal.R.attr.textSelectHandleWindowStyle);
@@ -10364,14 +10366,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
mContainer.setContentView(this);
- initDrawable();
+ mDrawableLtr = drawableLtr;
+ mDrawableRtl = drawableRtl;
+
+ updateDrawable();
final int handleHeight = mDrawable.getIntrinsicHeight();
mTouchOffsetY = -0.3f * handleHeight;
mIdealVerticalOffset = 0.7f * handleHeight;
}
- protected abstract void initDrawable();
+ protected void updateDrawable() {
+ final int offset = getCurrentCursorOffset();
+ final boolean isRtlCharAtOffset = mLayout.isRtlCharAt(offset);
+ mDrawable = isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr;
+ mHotspotX = getHotspotX(mDrawable, isRtlCharAtOffset);
+ }
+
+ protected abstract int getHotspotX(Drawable drawable, boolean isRtlRun);
// Touch-up filter: number of previous positions remembered
private static final int HISTORY_SIZE = 5;
@@ -10487,7 +10499,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public abstract int getCurrentCursorOffset();
- public abstract void updateSelection(int offset);
+ protected void updateSelection(int offset) {
+ updateDrawable();
+ }
public abstract void updatePosition(float x, float y);
@@ -10629,6 +10643,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private float mDownPositionX, mDownPositionY;
private Runnable mHider;
+ public InsertionHandleView(Drawable drawable) {
+ super(drawable, drawable);
+ }
+
@Override
public void show() {
super.show();
@@ -10665,13 +10683,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
@Override
- protected void initDrawable() {
- if (mSelectHandleCenter == null) {
- mSelectHandleCenter = mContext.getResources().getDrawable(
- mTextSelectHandleRes);
- }
- mDrawable = mSelectHandleCenter;
- mHotspotX = mDrawable.getIntrinsicWidth() / 2;
+ protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
+ return drawable.getIntrinsicWidth() / 2;
}
@Override
@@ -10741,14 +10754,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private class SelectionStartHandleView extends HandleView {
+
+ public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
+ super(drawableLtr, drawableRtl);
+ }
+
@Override
- protected void initDrawable() {
- if (mSelectHandleLeft == null) {
- mSelectHandleLeft = mContext.getResources().getDrawable(
- mTextSelectHandleLeftRes);
+ protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
+ if (isRtlRun) {
+ return drawable.getIntrinsicWidth() / 4;
+ } else {
+ return (drawable.getIntrinsicWidth() * 3) / 4;
}
- mDrawable = mSelectHandleLeft;
- mHotspotX = (mDrawable.getIntrinsicWidth() * 3) / 4;
}
@Override
@@ -10758,6 +10775,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void updateSelection(int offset) {
+ super.updateSelection(offset);
Selection.setSelection((Spannable) mText, offset, getSelectionEnd());
}
@@ -10778,14 +10796,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private class SelectionEndHandleView extends HandleView {
+
+ public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
+ super(drawableLtr, drawableRtl);
+ }
+
@Override
- protected void initDrawable() {
- if (mSelectHandleRight == null) {
- mSelectHandleRight = mContext.getResources().getDrawable(
- mTextSelectHandleRightRes);
+ protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
+ if (isRtlRun) {
+ return (drawable.getIntrinsicWidth() * 3) / 4;
+ } else {
+ return drawable.getIntrinsicWidth() / 4;
}
- mDrawable = mSelectHandleRight;
- mHotspotX = mDrawable.getIntrinsicWidth() / 4;
}
@Override
@@ -10795,6 +10817,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void updateSelection(int offset) {
+ super.updateSelection(offset);
Selection.setSelection((Spannable) mText, getSelectionStart(), offset);
}
@@ -10864,8 +10887,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private InsertionHandleView getHandle() {
+ if (mSelectHandleCenter == null) {
+ mSelectHandleCenter = mContext.getResources().getDrawable(
+ mTextSelectHandleRes);
+ }
if (mHandle == null) {
- mHandle = new InsertionHandleView();
+ mHandle = new InsertionHandleView(mSelectHandleCenter);
}
return mHandle;
}
@@ -10899,10 +10926,30 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (isInBatchEditMode()) {
return;
}
+ initDrawables();
+ initHandles();
+ hideInsertionPointCursorController();
+ }
+ private void initDrawables() {
+ if (mSelectHandleLeft == null) {
+ mSelectHandleLeft = mContext.getResources().getDrawable(
+ mTextSelectHandleLeftRes);
+ }
+ if (mSelectHandleRight == null) {
+ mSelectHandleRight = mContext.getResources().getDrawable(
+ mTextSelectHandleRightRes);
+ }
+ }
+
+ private void initHandles() {
// Lazy object creation has to be done before updatePosition() is called.
- if (mStartHandle == null) mStartHandle = new SelectionStartHandleView();
- if (mEndHandle == null) mEndHandle = new SelectionEndHandleView();
+ if (mStartHandle == null) {
+ mStartHandle = new SelectionStartHandleView(mSelectHandleLeft, mSelectHandleRight);
+ }
+ if (mEndHandle == null) {
+ mEndHandle = new SelectionEndHandleView(mSelectHandleRight, mSelectHandleLeft);
+ }
mStartHandle.show();
mEndHandle.show();