Merge "Paste popup window is displayed on the side when it would be clipped on top of screen." into honeycomb
This commit is contained in:
committed by
Android (Google) Code Review
commit
4569f1a561
@@ -9926,6 +9926,28 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="textEditSideNoPasteWindowLayout"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="16843615"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="textEditSidePasteWindowLayout"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="16843614"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="textFilterEnabled"
|
||||
type="int"
|
||||
transient="false"
|
||||
|
||||
@@ -307,8 +307,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
int mTextSelectHandleLeftRes;
|
||||
int mTextSelectHandleRightRes;
|
||||
int mTextSelectHandleRes;
|
||||
int mTextEditPasteWindowLayout;
|
||||
int mTextEditNoPasteWindowLayout;
|
||||
int mTextEditPasteWindowLayout, mTextEditSidePasteWindowLayout;
|
||||
int mTextEditNoPasteWindowLayout, mTextEditSideNoPasteWindowLayout;
|
||||
|
||||
Drawable mSelectHandleLeft;
|
||||
Drawable mSelectHandleRight;
|
||||
@@ -762,6 +762,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
mTextEditNoPasteWindowLayout = a.getResourceId(attr, 0);
|
||||
break;
|
||||
|
||||
case com.android.internal.R.styleable.TextView_textEditSidePasteWindowLayout:
|
||||
mTextEditSidePasteWindowLayout = a.getResourceId(attr, 0);
|
||||
break;
|
||||
|
||||
case com.android.internal.R.styleable.TextView_textEditSideNoPasteWindowLayout:
|
||||
mTextEditSideNoPasteWindowLayout = a.getResourceId(attr, 0);
|
||||
break;
|
||||
|
||||
case com.android.internal.R.styleable.TextView_textIsSelectable:
|
||||
mTextIsSelectable = a.getBoolean(attr, false);
|
||||
break;
|
||||
@@ -8422,8 +8430,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
private final PopupWindow mContainer;
|
||||
private int mPositionX;
|
||||
private int mPositionY;
|
||||
private View mPasteView, mNoPasteView;
|
||||
|
||||
private final View[] mPasteViews = new View[4];
|
||||
private final int[] mPasteViewLayouts = new int[] {
|
||||
mTextEditPasteWindowLayout, mTextEditNoPasteWindowLayout,
|
||||
mTextEditSidePasteWindowLayout, mTextEditSideNoPasteWindowLayout };
|
||||
|
||||
public PastePopupMenu() {
|
||||
mContainer = new PopupWindow(TextView.this.mContext, null,
|
||||
com.android.internal.R.attr.textSelectHandleWindowStyle);
|
||||
@@ -8435,12 +8446,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
private void updateContent() {
|
||||
View view = canPaste() ? mPasteView : mNoPasteView;
|
||||
private int viewIndex(boolean onTop) {
|
||||
return (onTop ? 0 : 1<<1) + (canPaste() ? 0 : 1<<0);
|
||||
}
|
||||
|
||||
private void updateContent(boolean onTop) {
|
||||
final int viewIndex = viewIndex(onTop);
|
||||
View view = mPasteViews[viewIndex];
|
||||
|
||||
if (view == null) {
|
||||
final int layout = canPaste() ? mTextEditPasteWindowLayout :
|
||||
mTextEditNoPasteWindowLayout;
|
||||
final int layout = mPasteViewLayouts[viewIndex];
|
||||
LayoutInflater inflater = (LayoutInflater)TextView.this.mContext.
|
||||
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
if (inflater != null) {
|
||||
@@ -8457,26 +8472,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
view.measure(size, size);
|
||||
|
||||
view.setOnClickListener(this);
|
||||
|
||||
if (canPaste()) mPasteView = view;
|
||||
else mNoPasteView = view;
|
||||
|
||||
mPasteViews[viewIndex] = view;
|
||||
}
|
||||
|
||||
mContainer.setContentView(view);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
updateContent();
|
||||
final int[] coords = mTempCoords;
|
||||
TextView.this.getLocationInWindow(coords);
|
||||
updateContent(true);
|
||||
positionAtCursor();
|
||||
coords[0] += mPositionX;
|
||||
coords[1] += mPositionY;
|
||||
coords[0] = Math.max(0, coords[0]);
|
||||
final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
|
||||
coords[0] = Math.min(screenWidth - mContainer.getContentView().getMeasuredWidth(),
|
||||
coords[0]);
|
||||
mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
@@ -8496,15 +8501,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
}
|
||||
|
||||
void positionAtCursor() {
|
||||
final int offset = TextView.this.getSelectionStart();
|
||||
View contentView = mContainer.getContentView();
|
||||
final int width = contentView.getMeasuredWidth();
|
||||
final int height = contentView.getMeasuredHeight();
|
||||
int width = contentView.getMeasuredWidth();
|
||||
int height = contentView.getMeasuredHeight();
|
||||
final int offset = TextView.this.getSelectionStart();
|
||||
final int line = mLayout.getLineForOffset(offset);
|
||||
final int lineTop = mLayout.getLineTop(line);
|
||||
float primaryHorizontal = mLayout.getPrimaryHorizontal(offset);
|
||||
|
||||
final Rect bounds = sCursorControllerTempRect;
|
||||
bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0f);
|
||||
bounds.left = (int) (primaryHorizontal - width / 2.0f);
|
||||
bounds.top = lineTop - height;
|
||||
|
||||
bounds.right = bounds.left + width;
|
||||
@@ -8514,6 +8520,44 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
|
||||
mPositionX = bounds.left;
|
||||
mPositionY = bounds.top;
|
||||
|
||||
|
||||
final int[] coords = mTempCoords;
|
||||
TextView.this.getLocationInWindow(coords);
|
||||
coords[0] += mPositionX;
|
||||
coords[1] += mPositionY;
|
||||
|
||||
final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
|
||||
if (coords[1] < 0) {
|
||||
updateContent(false);
|
||||
// Update dimensions from new view
|
||||
contentView = mContainer.getContentView();
|
||||
width = contentView.getMeasuredWidth();
|
||||
height = contentView.getMeasuredHeight();
|
||||
|
||||
// Vertical clipping, move under edited line and to the side of insertion cursor
|
||||
// TODO bottom clipping in case there is no system bar
|
||||
coords[1] += height;
|
||||
final int lineBottom = mLayout.getLineBottom(line);
|
||||
final int lineHeight = lineBottom - lineTop;
|
||||
coords[1] += lineHeight;
|
||||
|
||||
// Move to right hand side of insertion cursor by default. TODO RTL text.
|
||||
final Drawable handle = mContext.getResources().getDrawable(mTextSelectHandleRes);
|
||||
final int handleHalfWidth = handle.getIntrinsicWidth() / 2;
|
||||
|
||||
if (primaryHorizontal + handleHalfWidth + width < screenWidth) {
|
||||
coords[0] += handleHalfWidth + width / 2;
|
||||
} else {
|
||||
coords[0] -= handleHalfWidth + width / 2;
|
||||
}
|
||||
} else {
|
||||
// Horizontal clipping
|
||||
coords[0] = Math.max(0, coords[0]);
|
||||
coords[0] = Math.min(screenWidth - width, coords[0]);
|
||||
}
|
||||
|
||||
mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8915,11 +8959,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
hideDelayed();
|
||||
getHandle().show();
|
||||
removePastePopupCallback();
|
||||
if (canPaste()) {
|
||||
final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime;
|
||||
if (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION) {
|
||||
delayBeforePaste = 0;
|
||||
}
|
||||
final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime;
|
||||
if (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION) {
|
||||
delayBeforePaste = 0;
|
||||
}
|
||||
if (delayBeforePaste == 0 || canPaste()) {
|
||||
if (mPastePopupShower == null) {
|
||||
mPastePopupShower = new Runnable() {
|
||||
public void run() {
|
||||
|
||||
BIN
core/res/res/drawable-hdpi/text_edit_side_paste_window.9.png
Normal file
BIN
core/res/res/drawable-hdpi/text_edit_side_paste_window.9.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 892 B |
BIN
core/res/res/drawable-mdpi/text_edit_side_paste_window.9.png
Normal file
BIN
core/res/res/drawable-mdpi/text_edit_side_paste_window.9.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 426 B |
38
core/res/res/layout/text_edit_side_no_paste_window.xml
Normal file
38
core/res/res/layout/text_edit_side_no_paste_window.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dip"
|
||||
android:paddingRight="16dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingBottom="8dip"
|
||||
android:drawableLeft="@android:drawable/ic_menu_paste_dark"
|
||||
android:drawablePadding="8dip"
|
||||
android:gravity="center"
|
||||
android:textAppearance="?android:attr/textAppearanceMediumInverse"
|
||||
android:textColor="@android:color/dim_foreground_dark_inverse_disabled"
|
||||
android:background="@android:drawable/text_edit_side_paste_window"
|
||||
android:text="@android:string/pasteDisabled"
|
||||
android:layout_marginBottom="12dip"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
38
core/res/res/layout/text_edit_side_paste_window.xml
Normal file
38
core/res/res/layout/text_edit_side_paste_window.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dip"
|
||||
android:paddingRight="16dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingBottom="8dip"
|
||||
android:drawableLeft="@android:drawable/ic_menu_paste_light"
|
||||
android:drawablePadding="8dip"
|
||||
android:gravity="center"
|
||||
android:textAppearance="?android:attr/textAppearanceMediumInverse"
|
||||
android:textColor="@android:color/black"
|
||||
android:background="@android:drawable/text_edit_side_paste_window"
|
||||
android:text="@android:string/paste"
|
||||
android:layout_marginBottom="12dip"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -649,6 +649,11 @@
|
||||
<attr name="textEditPasteWindowLayout" format="reference" />
|
||||
<!-- Variation of textEditPasteWindowLayout displayed when the clipboard is empty. -->
|
||||
<attr name="textEditNoPasteWindowLayout" format="reference" />
|
||||
<!-- Used instead of textEditPasteWindowLayout when the window is moved on the side of the
|
||||
insertion cursor because it would be clipped if it were positioned on top. -->
|
||||
<attr name="textEditSidePasteWindowLayout" format="reference" />
|
||||
<!-- Variation of textEditSidePasteWindowLayout displayed when the clipboard is empty. -->
|
||||
<attr name="textEditSideNoPasteWindowLayout" format="reference" />
|
||||
|
||||
<!-- Theme to use for dialogs spawned from this theme. -->
|
||||
<attr name="dialogTheme" format="reference" />
|
||||
@@ -2741,6 +2746,12 @@
|
||||
<attr name="textEditPasteWindowLayout" />
|
||||
<!-- Variation of textEditPasteWindowLayout displayed when the clipboard is empty. -->
|
||||
<attr name="textEditNoPasteWindowLayout" />
|
||||
<!-- Used instead of textEditPasteWindowLayout when the window is moved on the side of the
|
||||
insertion cursor because it would be clipped if it were positioned on top. -->
|
||||
<attr name="textEditSidePasteWindowLayout" />
|
||||
<!-- Variation of textEditSidePasteWindowLayout displayed when the clipboard is empty. -->
|
||||
<attr name="textEditSideNoPasteWindowLayout" />
|
||||
|
||||
<!-- Indicates that the content of a non-editable text can be selected. -->
|
||||
<attr name="textIsSelectable" />
|
||||
</declare-styleable>
|
||||
|
||||
@@ -1633,6 +1633,8 @@
|
||||
<public type="style" name="Widget.Holo.Light.CalendarView" />
|
||||
<public type="style" name="Widget.DatePicker" />
|
||||
<public type="style" name="Widget.Holo.DatePicker" />
|
||||
<public type="attr" name="textEditSidePasteWindowLayout" />
|
||||
<public type="attr" name="textEditSideNoPasteWindowLayout" />
|
||||
|
||||
<public type="string" name="selectTextMode" />
|
||||
|
||||
|
||||
@@ -419,6 +419,8 @@
|
||||
<item name="android:textSelectHandle">?android:attr/textSelectHandle</item>
|
||||
<item name="android:textEditPasteWindowLayout">?android:attr/textEditPasteWindowLayout</item>
|
||||
<item name="android:textEditNoPasteWindowLayout">?android:attr/textEditNoPasteWindowLayout</item>
|
||||
<item name="android:textEditSidePasteWindowLayout">?android:attr/textEditSidePasteWindowLayout</item>
|
||||
<item name="android:textEditSideNoPasteWindowLayout">?android:attr/textEditSideNoPasteWindowLayout</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.TextView.ListSeparator">
|
||||
|
||||
@@ -174,6 +174,8 @@
|
||||
<item name="textSelectHandleWindowStyle">@android:style/Widget.TextSelectHandle</item>
|
||||
<item name="textEditPasteWindowLayout">@android:layout/text_edit_paste_window</item>
|
||||
<item name="textEditNoPasteWindowLayout">@android:layout/text_edit_no_paste_window</item>
|
||||
<item name="textEditSidePasteWindowLayout">@android:layout/text_edit_side_paste_window</item>
|
||||
<item name="textEditSideNoPasteWindowLayout">@android:layout/text_edit_side_no_paste_window</item>
|
||||
|
||||
<!-- Widget styles -->
|
||||
<item name="absListViewStyle">@android:style/Widget.AbsListView</item>
|
||||
|
||||
Reference in New Issue
Block a user