Loading api/current.xml +45 −1 Original line number Diff line number Diff line Loading @@ -10025,6 +10025,39 @@ visibility="public" > </field> <field name="textEditSuggestionItemLayout" type="int" transient="false" volatile="false" value="16843626" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="textEditSuggestionsBottomWindowLayout" type="int" transient="false" volatile="false" value="16843624" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="textEditSuggestionsTopWindowLayout" type="int" transient="false" volatile="false" value="16843625" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="textFilterEnabled" type="int" transient="false" Loading Loading @@ -10146,6 +10179,17 @@ visibility="public" > </field> <field name="textSuggestionsWindowStyle" type="int" transient="false" volatile="false" value="16843623" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="textViewStyle" type="int" transient="false" Loading Loading @@ -267852,7 +267896,7 @@ deprecated="not deprecated" visibility="public" > <parameter name="arg0" type="T"> <parameter name="t" type="T"> </parameter> </method> </interface> core/java/android/widget/TextView.java +225 −17 Original line number Diff line number Diff line Loading @@ -43,7 +43,6 @@ import android.inputmethodservice.ExtractEditText; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -88,6 +87,7 @@ import android.text.style.URLSpan; import android.text.style.UpdateAppearance; import android.text.util.Linkify; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.FloatMath; import android.util.Log; import android.util.TypedValue; Loading Loading @@ -311,6 +311,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mTextEditPasteWindowLayout, mTextEditSidePasteWindowLayout; private int mTextEditNoPasteWindowLayout, mTextEditSideNoPasteWindowLayout; private int mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout; private int mTextEditSuggestionItemLayout; private SuggestionsPopupWindow mSuggestionsPopupWindow; private int mCursorDrawableRes; private final Drawable[] mCursorDrawable = new Drawable[2]; private int mCursorCount; // Actual current number of used mCursorDrawable: 0, 1 or 2 Loading Loading @@ -779,6 +783,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mTextEditSideNoPasteWindowLayout = a.getResourceId(attr, 0); break; case com.android.internal.R.styleable.TextView_textEditSuggestionsBottomWindowLayout: mTextEditSuggestionsBottomWindowLayout = a.getResourceId(attr, 0); break; case com.android.internal.R.styleable.TextView_textEditSuggestionsTopWindowLayout: mTextEditSuggestionsTopWindowLayout = a.getResourceId(attr, 0); break; case com.android.internal.R.styleable.TextView_textEditSuggestionItemLayout: mTextEditSuggestionItemLayout = a.getResourceId(attr, 0); break; case com.android.internal.R.styleable.TextView_textIsSelectable: mTextIsSelectable = a.getBoolean(attr, false); break; Loading Loading @@ -7343,6 +7359,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener startSelectionActionMode(); } else { stopSelectionActionMode(); hideSuggestions(); if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) { getInsertionController().show(); } Loading Loading @@ -8221,6 +8238,201 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return ((minOffset >= selectionStart) && (maxOffset < selectionEnd)); } private class SuggestionsPopupWindow implements OnClickListener { private static final int MAX_NUMBER_SUGGESTIONS = 5; private static final long NO_SUGGESTIONS = -1L; private final PopupWindow mContainer; private final ViewGroup[] mSuggestionViews = new ViewGroup[2]; private final int[] mSuggestionViewLayouts = new int[] { mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout}; public SuggestionsPopupWindow() { mContainer = new PopupWindow(TextView.this.mContext, null, com.android.internal.R.attr.textSuggestionsWindowStyle); mContainer.setSplitTouchEnabled(true); mContainer.setClippingEnabled(false); mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL); mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); } private ViewGroup getViewGroup(boolean under) { final int viewIndex = under ? 0 : 1; ViewGroup viewGroup = mSuggestionViews[viewIndex]; if (viewGroup == null) { final int layout = mSuggestionViewLayouts[viewIndex]; LayoutInflater inflater = (LayoutInflater) TextView.this.mContext. getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (inflater == null) { throw new IllegalArgumentException( "Unable to create TextEdit suggestion window inflater"); } View view = inflater.inflate(layout, null); if (! (view instanceof ViewGroup)) { throw new IllegalArgumentException( "Inflated TextEdit suggestion window is not a ViewGroup: " + view); } viewGroup = (ViewGroup) view; // Inflate the suggestion items once and for all. for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) { View childView = inflater.inflate(mTextEditSuggestionItemLayout, viewGroup, false); if (! (childView instanceof TextView)) { throw new IllegalArgumentException( "Inflated TextEdit suggestion item is not a TextView: " + childView); } viewGroup.addView(childView); childView.setOnClickListener(this); } mSuggestionViews[viewIndex] = viewGroup; } return viewGroup; } public void show() { if (!(mText instanceof Editable)) return; final int pos = TextView.this.getSelectionStart(); Spannable spannable = (Spannable)TextView.this.mText; CorrectionSpan[] correctionSpans = spannable.getSpans(pos, pos, CorrectionSpan.class); final int nbSpans = correctionSpans.length; ViewGroup viewGroup = getViewGroup(true); mContainer.setContentView(viewGroup); int totalNbSuggestions = 0; for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) { CorrectionSpan correctionSpan = correctionSpans[spanIndex]; final int spanStart = spannable.getSpanStart(correctionSpan); final int spanEnd = spannable.getSpanEnd(correctionSpan); final Long spanRange = packRangeInLong(spanStart, spanEnd); String[] suggestions = correctionSpan.getSuggestions(); int nbSuggestions = suggestions.length; for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) { TextView textView = (TextView) viewGroup.getChildAt(totalNbSuggestions); textView.setText(suggestions[suggestionIndex]); textView.setTag(spanRange); totalNbSuggestions++; if (totalNbSuggestions == MAX_NUMBER_SUGGESTIONS) { spanIndex = nbSpans; break; } } } if (totalNbSuggestions == 0) { // TODO Replace by final text, use a dedicated layout, add a fade out timer... TextView textView = (TextView) viewGroup.getChildAt(0); textView.setText("No suggestions available"); textView.setTag(NO_SUGGESTIONS); totalNbSuggestions++; } for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) { viewGroup.getChildAt(i).setVisibility(i < totalNbSuggestions ? VISIBLE : GONE); } final int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); viewGroup.measure(size, size); positionAtCursor(); } public void hide() { mContainer.dismiss(); } @Override public void onClick(View view) { if (view instanceof TextView) { TextView textView = (TextView) view; Long range = ((Long) view.getTag()); if (range != NO_SUGGESTIONS) { final int spanStart = extractRangeStartFromLong(range); final int spanEnd = extractRangeEndFromLong(range); ((Editable) mText).replace(spanStart, spanEnd, textView.getText()); } } hide(); } void positionAtCursor() { View contentView = mContainer.getContentView(); int width = contentView.getMeasuredWidth(); int height = contentView.getMeasuredHeight(); final int offset = TextView.this.getSelectionStart(); final int line = mLayout.getLineForOffset(offset); final int lineBottom = mLayout.getLineBottom(line); float primaryHorizontal = mLayout.getPrimaryHorizontal(offset); final Rect bounds = sCursorControllerTempRect; bounds.left = (int) (primaryHorizontal - width / 2.0f); bounds.top = lineBottom; bounds.right = bounds.left + width; bounds.bottom = bounds.top + height; convertFromViewportToContentCoordinates(bounds); final int[] coords = mTempCoords; TextView.this.getLocationInWindow(coords); coords[0] += bounds.left; coords[1] += bounds.top; final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); final int screenHeight = displayMetrics.heightPixels; // Vertical clipping if (coords[1] + height > screenHeight) { // Try to position above current line instead // TODO use top layout instead, reverse suggestion order, // try full screen vertical down if it still does not fit. TBD with designers. // Update dimensions from new view contentView = mContainer.getContentView(); width = contentView.getMeasuredWidth(); height = contentView.getMeasuredHeight(); final int lineTop = mLayout.getLineTop(line); final int lineHeight = lineBottom - lineTop; coords[1] -= height + lineHeight; } // Horizontal clipping coords[0] = Math.max(0, coords[0]); coords[0] = Math.min(displayMetrics.widthPixels - width, coords[0]); mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]); } } void showSuggestions() { if (mSuggestionsPopupWindow == null) { mSuggestionsPopupWindow = new SuggestionsPopupWindow(); } hideControllers(); mSuggestionsPopupWindow.show(); } void hideSuggestions() { if (mSuggestionsPopupWindow != null) { mSuggestionsPopupWindow.hide(); } } /** * If provided, this ActionMode.Callback will be used to create the ActionMode when text * selection is initiated in this View. Loading Loading @@ -8429,16 +8641,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } private class PastePopupMenu implements OnClickListener { private class PastePopupWindow implements OnClickListener { private final PopupWindow mContainer; private int mPositionX; private int mPositionY; private final View[] mPasteViews = new View[4]; private final int[] mPasteViewLayouts = new int[] { mTextEditPasteWindowLayout, mTextEditNoPasteWindowLayout, mTextEditSidePasteWindowLayout, mTextEditSideNoPasteWindowLayout }; public PastePopupMenu() { public PastePopupWindow() { mContainer = new PopupWindow(TextView.this.mContext, null, com.android.internal.R.attr.textSelectHandleWindowStyle); mContainer.setSplitTouchEnabled(true); Loading Loading @@ -8521,14 +8731,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener convertFromViewportToContentCoordinates(bounds); mPositionX = bounds.left; mPositionY = bounds.top; final int[] coords = mTempCoords; TextView.this.getLocationInWindow(coords); coords[0] += mPositionX; coords[1] += mPositionY; coords[0] += bounds.left; coords[1] += bounds.top; final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels; if (coords[1] < 0) { Loading Loading @@ -8883,10 +9089,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private static final int DELAY_BEFORE_FADE_OUT = 4000; private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; // seconds // Used to detect taps on the insertion handle, which will affect the PastePopupMenu // Used to detect taps on the insertion handle, which will affect the PastePopupWindow private long mTouchTimer; private float mDownPositionX, mDownPositionY; private PastePopupMenu mPastePopupWindow; private PastePopupWindow mPastePopupWindow; private Runnable mHider; private Runnable mPastePopupShower; Loading Loading @@ -9026,7 +9232,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener void showAssociatedPopupWindow() { if (mPastePopupWindow == null) { // Lazy initialisation: create when actually shown only. mPastePopupWindow = new PastePopupMenu(); mPastePopupWindow = new PastePopupWindow(); } mPastePopupWindow.show(); } Loading Loading @@ -9237,6 +9443,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mEndHandle.show(); hideInsertionPointCursorController(); hideSuggestions(); } public void hide() { Loading Loading @@ -9264,7 +9471,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int deltaY = y - mPreviousTapPositionY; final int distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared < mSquaredTouchSlopDistance) { startSelectionActionMode(); showSuggestions(); mDiscardNextActionUp = true; } } Loading Loading @@ -9354,6 +9561,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private void hideControllers() { hideInsertionPointCursorController(); stopSelectionActionMode(); hideSuggestions(); } /** Loading core/res/res/drawable-mdpi/text_edit_suggestions_bottom_window.9.png 0 → 100644 +605 B Loading image diff... core/res/res/drawable-mdpi/text_edit_suggestions_top_window.9.png 0 → 100644 +585 B Loading image diff... core/res/res/layout/text_edit_suggestion_item.xml 0 → 100644 +27 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2011 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. --> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="16dip" android:paddingRight="16dip" android:paddingTop="8dip" android:paddingBottom="8dip" android:layout_gravity="center" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@android:color/black" /> Loading
api/current.xml +45 −1 Original line number Diff line number Diff line Loading @@ -10025,6 +10025,39 @@ visibility="public" > </field> <field name="textEditSuggestionItemLayout" type="int" transient="false" volatile="false" value="16843626" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="textEditSuggestionsBottomWindowLayout" type="int" transient="false" volatile="false" value="16843624" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="textEditSuggestionsTopWindowLayout" type="int" transient="false" volatile="false" value="16843625" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="textFilterEnabled" type="int" transient="false" Loading Loading @@ -10146,6 +10179,17 @@ visibility="public" > </field> <field name="textSuggestionsWindowStyle" type="int" transient="false" volatile="false" value="16843623" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> <field name="textViewStyle" type="int" transient="false" Loading Loading @@ -267852,7 +267896,7 @@ deprecated="not deprecated" visibility="public" > <parameter name="arg0" type="T"> <parameter name="t" type="T"> </parameter> </method> </interface>
core/java/android/widget/TextView.java +225 −17 Original line number Diff line number Diff line Loading @@ -43,7 +43,6 @@ import android.inputmethodservice.ExtractEditText; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -88,6 +87,7 @@ import android.text.style.URLSpan; import android.text.style.UpdateAppearance; import android.text.util.Linkify; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.FloatMath; import android.util.Log; import android.util.TypedValue; Loading Loading @@ -311,6 +311,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mTextEditPasteWindowLayout, mTextEditSidePasteWindowLayout; private int mTextEditNoPasteWindowLayout, mTextEditSideNoPasteWindowLayout; private int mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout; private int mTextEditSuggestionItemLayout; private SuggestionsPopupWindow mSuggestionsPopupWindow; private int mCursorDrawableRes; private final Drawable[] mCursorDrawable = new Drawable[2]; private int mCursorCount; // Actual current number of used mCursorDrawable: 0, 1 or 2 Loading Loading @@ -779,6 +783,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mTextEditSideNoPasteWindowLayout = a.getResourceId(attr, 0); break; case com.android.internal.R.styleable.TextView_textEditSuggestionsBottomWindowLayout: mTextEditSuggestionsBottomWindowLayout = a.getResourceId(attr, 0); break; case com.android.internal.R.styleable.TextView_textEditSuggestionsTopWindowLayout: mTextEditSuggestionsTopWindowLayout = a.getResourceId(attr, 0); break; case com.android.internal.R.styleable.TextView_textEditSuggestionItemLayout: mTextEditSuggestionItemLayout = a.getResourceId(attr, 0); break; case com.android.internal.R.styleable.TextView_textIsSelectable: mTextIsSelectable = a.getBoolean(attr, false); break; Loading Loading @@ -7343,6 +7359,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener startSelectionActionMode(); } else { stopSelectionActionMode(); hideSuggestions(); if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) { getInsertionController().show(); } Loading Loading @@ -8221,6 +8238,201 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return ((minOffset >= selectionStart) && (maxOffset < selectionEnd)); } private class SuggestionsPopupWindow implements OnClickListener { private static final int MAX_NUMBER_SUGGESTIONS = 5; private static final long NO_SUGGESTIONS = -1L; private final PopupWindow mContainer; private final ViewGroup[] mSuggestionViews = new ViewGroup[2]; private final int[] mSuggestionViewLayouts = new int[] { mTextEditSuggestionsBottomWindowLayout, mTextEditSuggestionsTopWindowLayout}; public SuggestionsPopupWindow() { mContainer = new PopupWindow(TextView.this.mContext, null, com.android.internal.R.attr.textSuggestionsWindowStyle); mContainer.setSplitTouchEnabled(true); mContainer.setClippingEnabled(false); mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL); mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); } private ViewGroup getViewGroup(boolean under) { final int viewIndex = under ? 0 : 1; ViewGroup viewGroup = mSuggestionViews[viewIndex]; if (viewGroup == null) { final int layout = mSuggestionViewLayouts[viewIndex]; LayoutInflater inflater = (LayoutInflater) TextView.this.mContext. getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (inflater == null) { throw new IllegalArgumentException( "Unable to create TextEdit suggestion window inflater"); } View view = inflater.inflate(layout, null); if (! (view instanceof ViewGroup)) { throw new IllegalArgumentException( "Inflated TextEdit suggestion window is not a ViewGroup: " + view); } viewGroup = (ViewGroup) view; // Inflate the suggestion items once and for all. for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) { View childView = inflater.inflate(mTextEditSuggestionItemLayout, viewGroup, false); if (! (childView instanceof TextView)) { throw new IllegalArgumentException( "Inflated TextEdit suggestion item is not a TextView: " + childView); } viewGroup.addView(childView); childView.setOnClickListener(this); } mSuggestionViews[viewIndex] = viewGroup; } return viewGroup; } public void show() { if (!(mText instanceof Editable)) return; final int pos = TextView.this.getSelectionStart(); Spannable spannable = (Spannable)TextView.this.mText; CorrectionSpan[] correctionSpans = spannable.getSpans(pos, pos, CorrectionSpan.class); final int nbSpans = correctionSpans.length; ViewGroup viewGroup = getViewGroup(true); mContainer.setContentView(viewGroup); int totalNbSuggestions = 0; for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) { CorrectionSpan correctionSpan = correctionSpans[spanIndex]; final int spanStart = spannable.getSpanStart(correctionSpan); final int spanEnd = spannable.getSpanEnd(correctionSpan); final Long spanRange = packRangeInLong(spanStart, spanEnd); String[] suggestions = correctionSpan.getSuggestions(); int nbSuggestions = suggestions.length; for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) { TextView textView = (TextView) viewGroup.getChildAt(totalNbSuggestions); textView.setText(suggestions[suggestionIndex]); textView.setTag(spanRange); totalNbSuggestions++; if (totalNbSuggestions == MAX_NUMBER_SUGGESTIONS) { spanIndex = nbSpans; break; } } } if (totalNbSuggestions == 0) { // TODO Replace by final text, use a dedicated layout, add a fade out timer... TextView textView = (TextView) viewGroup.getChildAt(0); textView.setText("No suggestions available"); textView.setTag(NO_SUGGESTIONS); totalNbSuggestions++; } for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) { viewGroup.getChildAt(i).setVisibility(i < totalNbSuggestions ? VISIBLE : GONE); } final int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); viewGroup.measure(size, size); positionAtCursor(); } public void hide() { mContainer.dismiss(); } @Override public void onClick(View view) { if (view instanceof TextView) { TextView textView = (TextView) view; Long range = ((Long) view.getTag()); if (range != NO_SUGGESTIONS) { final int spanStart = extractRangeStartFromLong(range); final int spanEnd = extractRangeEndFromLong(range); ((Editable) mText).replace(spanStart, spanEnd, textView.getText()); } } hide(); } void positionAtCursor() { View contentView = mContainer.getContentView(); int width = contentView.getMeasuredWidth(); int height = contentView.getMeasuredHeight(); final int offset = TextView.this.getSelectionStart(); final int line = mLayout.getLineForOffset(offset); final int lineBottom = mLayout.getLineBottom(line); float primaryHorizontal = mLayout.getPrimaryHorizontal(offset); final Rect bounds = sCursorControllerTempRect; bounds.left = (int) (primaryHorizontal - width / 2.0f); bounds.top = lineBottom; bounds.right = bounds.left + width; bounds.bottom = bounds.top + height; convertFromViewportToContentCoordinates(bounds); final int[] coords = mTempCoords; TextView.this.getLocationInWindow(coords); coords[0] += bounds.left; coords[1] += bounds.top; final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); final int screenHeight = displayMetrics.heightPixels; // Vertical clipping if (coords[1] + height > screenHeight) { // Try to position above current line instead // TODO use top layout instead, reverse suggestion order, // try full screen vertical down if it still does not fit. TBD with designers. // Update dimensions from new view contentView = mContainer.getContentView(); width = contentView.getMeasuredWidth(); height = contentView.getMeasuredHeight(); final int lineTop = mLayout.getLineTop(line); final int lineHeight = lineBottom - lineTop; coords[1] -= height + lineHeight; } // Horizontal clipping coords[0] = Math.max(0, coords[0]); coords[0] = Math.min(displayMetrics.widthPixels - width, coords[0]); mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]); } } void showSuggestions() { if (mSuggestionsPopupWindow == null) { mSuggestionsPopupWindow = new SuggestionsPopupWindow(); } hideControllers(); mSuggestionsPopupWindow.show(); } void hideSuggestions() { if (mSuggestionsPopupWindow != null) { mSuggestionsPopupWindow.hide(); } } /** * If provided, this ActionMode.Callback will be used to create the ActionMode when text * selection is initiated in this View. Loading Loading @@ -8429,16 +8641,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } private class PastePopupMenu implements OnClickListener { private class PastePopupWindow implements OnClickListener { private final PopupWindow mContainer; private int mPositionX; private int mPositionY; private final View[] mPasteViews = new View[4]; private final int[] mPasteViewLayouts = new int[] { mTextEditPasteWindowLayout, mTextEditNoPasteWindowLayout, mTextEditSidePasteWindowLayout, mTextEditSideNoPasteWindowLayout }; public PastePopupMenu() { public PastePopupWindow() { mContainer = new PopupWindow(TextView.this.mContext, null, com.android.internal.R.attr.textSelectHandleWindowStyle); mContainer.setSplitTouchEnabled(true); Loading Loading @@ -8521,14 +8731,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener convertFromViewportToContentCoordinates(bounds); mPositionX = bounds.left; mPositionY = bounds.top; final int[] coords = mTempCoords; TextView.this.getLocationInWindow(coords); coords[0] += mPositionX; coords[1] += mPositionY; coords[0] += bounds.left; coords[1] += bounds.top; final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels; if (coords[1] < 0) { Loading Loading @@ -8883,10 +9089,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private static final int DELAY_BEFORE_FADE_OUT = 4000; private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; // seconds // Used to detect taps on the insertion handle, which will affect the PastePopupMenu // Used to detect taps on the insertion handle, which will affect the PastePopupWindow private long mTouchTimer; private float mDownPositionX, mDownPositionY; private PastePopupMenu mPastePopupWindow; private PastePopupWindow mPastePopupWindow; private Runnable mHider; private Runnable mPastePopupShower; Loading Loading @@ -9026,7 +9232,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener void showAssociatedPopupWindow() { if (mPastePopupWindow == null) { // Lazy initialisation: create when actually shown only. mPastePopupWindow = new PastePopupMenu(); mPastePopupWindow = new PastePopupWindow(); } mPastePopupWindow.show(); } Loading Loading @@ -9237,6 +9443,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mEndHandle.show(); hideInsertionPointCursorController(); hideSuggestions(); } public void hide() { Loading Loading @@ -9264,7 +9471,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int deltaY = y - mPreviousTapPositionY; final int distanceSquared = deltaX * deltaX + deltaY * deltaY; if (distanceSquared < mSquaredTouchSlopDistance) { startSelectionActionMode(); showSuggestions(); mDiscardNextActionUp = true; } } Loading Loading @@ -9354,6 +9561,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private void hideControllers() { hideInsertionPointCursorController(); stopSelectionActionMode(); hideSuggestions(); } /** Loading
core/res/res/drawable-mdpi/text_edit_suggestions_bottom_window.9.png 0 → 100644 +605 B Loading image diff...
core/res/res/drawable-mdpi/text_edit_suggestions_top_window.9.png 0 → 100644 +585 B Loading image diff...
core/res/res/layout/text_edit_suggestion_item.xml 0 → 100644 +27 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2011 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. --> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="16dip" android:paddingRight="16dip" android:paddingTop="8dip" android:paddingBottom="8dip" android:layout_gravity="center" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@android:color/black" />