Skip to content

Commit f8419a0

Browse files
committed
Fix bugs around overlay action modes.
Multiple focusable windows cause undesired behavior around selection modes. TextView isn't sure how to behave when it loses window focus with regard to selection handles and action modes need to be focusable for WebView find on page since it uses an EditText as a custom view. For now: * Use a layered window decor for overlay action mode when there is no action bar requested. This eliminates an extra window and avoids the issue described for full-screen UIs. * Disable WebView's find-on-page mode when the action mode's UI will not be focusable. This only affects WebViews in floating windows. Also remove the "Text Selection" title for WebView's selection mode at UX's request, as it is inconsistent with TextView's selection mode and the string does not fit on phones in portrait even on wide devices. This now uses the same mechanism used in TextView to decide whether to use title text. Change-Id: I80caeecea9b47728cf26bb0a388153ca0bdeafe1
1 parent 1401935 commit f8419a0

File tree

6 files changed

+89
-11
lines changed

6 files changed

+89
-11
lines changed

core/java/android/view/ActionMode.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ public Object getTag() {
152152
*/
153153
public abstract MenuInflater getMenuInflater();
154154

155+
/**
156+
* Returns whether the UI presenting this action mode can take focus or not.
157+
* This is used by internal components within the framework that would otherwise
158+
* present an action mode UI that requires focus, such as an EditText as a custom view.
159+
*
160+
* @return true if the UI used to show this action mode can take focus
161+
* @hide Internal use only
162+
*/
163+
public boolean isUiFocusable() {
164+
return true;
165+
}
166+
155167
/**
156168
* Callback interface for action modes. Supplied to
157169
* {@link View#startActionMode(Callback)}, a Callback

core/java/android/webkit/FindActionModeCallback.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ public void onClick(View v) {
180180

181181
@Override
182182
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
183+
if (!mode.isUiFocusable()) {
184+
// If the action mode we're running in is not focusable the user
185+
// will not be able to type into the find on page field. This
186+
// should only come up when we're running in a dialog which is
187+
// already less than ideal; disable the option for now.
188+
return false;
189+
}
190+
183191
mode.setCustomView(mCustomView);
184192
mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_find,
185193
menu);

core/java/android/webkit/SelectActionModeCallback.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@
1717
package android.webkit;
1818

1919
import android.app.SearchManager;
20+
import android.content.Context;
2021
import android.content.Intent;
2122
import android.provider.Browser;
22-
import android.webkit.WebView;
2323
import android.view.ActionMode;
2424
import android.view.Menu;
2525
import android.view.MenuItem;
26-
import android.view.View;
2726

2827
class SelectActionModeCallback implements ActionMode.Callback {
2928
private WebView mWebView;
@@ -45,9 +44,25 @@ void finish() {
4544

4645
@Override
4746
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
48-
mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_copy,
49-
menu);
50-
mode.setTitle(com.android.internal.R.string.textSelectionCABTitle);
47+
mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_copy, menu);
48+
49+
final Context context = mWebView.getContext();
50+
boolean allowText = context.getResources().getBoolean(
51+
com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
52+
mode.setTitle(allowText ?
53+
context.getString(com.android.internal.R.string.textSelectionCABTitle) : null);
54+
55+
if (!mode.isUiFocusable()) {
56+
// If the action mode UI we're running in isn't capable of taking window focus
57+
// the user won't be able to type into the find on page UI. Disable this functionality.
58+
// (Note that this should only happen in floating dialog windows.)
59+
// This can be removed once we can handle multiple focusable windows at a time
60+
// in a better way.
61+
final MenuItem findOnPageItem = menu.findItem(com.android.internal.R.id.find);
62+
if (findOnPageItem != null) {
63+
findOnPageItem.setVisible(false);
64+
}
65+
}
5166
mActionMode = mode;
5267
return true;
5368
}

core/java/com/android/internal/view/StandaloneActionMode.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,19 @@ public class StandaloneActionMode extends ActionMode implements MenuBuilder.Call
3636
private ActionMode.Callback mCallback;
3737
private WeakReference<View> mCustomView;
3838
private boolean mFinished;
39+
private boolean mFocusable;
3940

4041
private MenuBuilder mMenu;
4142

4243
public StandaloneActionMode(Context context, ActionBarContextView view,
43-
ActionMode.Callback callback) {
44+
ActionMode.Callback callback, boolean isFocusable) {
4445
mContext = context;
4546
mContextView = view;
4647
mCallback = callback;
4748

4849
mMenu = new MenuBuilder(context).setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
4950
mMenu.setCallback(this);
51+
mFocusable = isFocusable;
5052
}
5153

5254
@Override
@@ -139,4 +141,8 @@ public void onMenuModeChange(MenuBuilder menu) {
139141
invalidate();
140142
mContextView.showOverflowMenu();
141143
}
144+
145+
public boolean isUiFocusable() {
146+
return mFocusable;
147+
}
142148
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
/*
4+
** Copyright 2011, The Android Open Source Project
5+
**
6+
** Licensed under the Apache License, Version 2.0 (the "License");
7+
** you may not use this file except in compliance with the License.
8+
** You may obtain a copy of the License at
9+
**
10+
** http://www.apache.org/licenses/LICENSE-2.0
11+
**
12+
** Unless required by applicable law or agreed to in writing, software
13+
** distributed under the License is distributed on an "AS IS" BASIS,
14+
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
** See the License for the specific language governing permissions and
16+
** limitations under the License.
17+
*/
18+
19+
This is an optimized layout for a screen, with the minimum set of features
20+
enabled.
21+
-->
22+
23+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
24+
android:fitsSystemWindows="true">
25+
<FrameLayout
26+
android:id="@android:id/content"
27+
android:layout_width="match_parent"
28+
android:layout_height="match_parent"
29+
android:foregroundInsidePadding="false"
30+
android:foregroundGravity="fill_horizontal|top"
31+
android:foreground="?android:attr/windowContentOverlay" />
32+
<ViewStub android:id="@+id/action_mode_bar_stub"
33+
android:inflatedId="@+id/action_mode_bar"
34+
android:layout="@layout/action_mode_bar"
35+
android:layout_width="match_parent"
36+
android:layout_height="wrap_content" />
37+
</FrameLayout>

policy/src/com/android/internal/policy/impl/PhoneWindow.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2147,15 +2147,12 @@ public ActionMode startActionMode(ActionMode.Callback callback) {
21472147
mActionMode = mode;
21482148
} else {
21492149
if (mActionModeView == null) {
2150-
if (hasFeature(FEATURE_ACTION_MODE_OVERLAY)) {
2150+
if (isFloating()) {
21512151
mActionModeView = new ActionBarContextView(mContext);
21522152
mActionModePopup = new PopupWindow(mContext, null,
21532153
com.android.internal.R.attr.actionModePopupWindowStyle);
21542154
mActionModePopup.setLayoutInScreenEnabled(true);
21552155
mActionModePopup.setLayoutInsetDecor(true);
2156-
mActionModePopup.setFocusable(true);
2157-
mActionModePopup.setOutsideTouchable(false);
2158-
mActionModePopup.setTouchModal(false);
21592156
mActionModePopup.setWindowLayoutType(
21602157
WindowManager.LayoutParams.TYPE_APPLICATION);
21612158
mActionModePopup.setContentView(mActionModeView);
@@ -2186,7 +2183,8 @@ public void run() {
21862183

21872184
if (mActionModeView != null) {
21882185
mActionModeView.killMode();
2189-
mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback);
2186+
mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback,
2187+
mActionModePopup == null);
21902188
if (callback.onCreateActionMode(mode, mode.getMenu())) {
21912189
mode.invalidate();
21922190
mActionModeView.initForMode(mode);
@@ -2664,6 +2662,8 @@ protected ViewGroup generateLayout(DecorView decor) {
26642662
layoutResource = com.android.internal.R.layout.screen_title;
26652663
}
26662664
// System.out.println("Title!");
2665+
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
2666+
layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode;
26672667
} else {
26682668
// Embedded, so no decoration is needed.
26692669
layoutResource = com.android.internal.R.layout.screen_simple;

0 commit comments

Comments
 (0)