Merge "Alt-up moves focus to the toolbar in action bar mode."
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 72f8c77..3e6b595 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -31,9 +31,11 @@
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
+import android.view.View.OnFocusChangeListener;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewHierarchyEncoder;
+import android.view.ViewParent;
import android.view.Window;
import android.widget.SpinnerAdapter;
import java.lang.annotation.Retention;
@@ -1071,6 +1073,62 @@
}
/**
+ * Attempts to move focus to the ActionBar if it does not already contain the focus.
+ *
+ * @return {@code true} if focus changes or {@code false} if focus doesn't change.
+ * @hide
+ */
+ public boolean requestFocus() {
+ return false;
+ }
+
+ /**
+ * Common implementation for requestFocus that takes in the Toolbar and moves focus
+ * to the contents. This makes the ViewGroups containing the toolbar allow focus while it stays
+ * in the ActionBar and then prevents it again once it leaves.
+ *
+ * @param viewGroup The toolbar ViewGroup
+ * @return {@code true} if focus changes or {@code false} if focus doesn't change.
+ * @hide
+ */
+ protected boolean requestFocus(ViewGroup viewGroup) {
+ if (viewGroup != null && !viewGroup.hasFocus()) {
+ final ViewGroup toolbar = viewGroup.getTouchscreenBlocksFocus() ? viewGroup : null;
+ ViewParent parent = viewGroup.getParent();
+ ViewGroup container = null;
+ while (parent != null && parent instanceof ViewGroup) {
+ final ViewGroup vgParent = (ViewGroup) parent;
+ if (vgParent.getTouchscreenBlocksFocus()) {
+ container = vgParent;
+ break;
+ }
+ parent = vgParent.getParent();
+ }
+ if (container != null) {
+ container.setTouchscreenBlocksFocus(false);
+ }
+ if (toolbar != null) {
+ toolbar.setTouchscreenBlocksFocus(false);
+ }
+ viewGroup.requestFocus();
+ final View focused = viewGroup.findFocus();
+ if (focused != null) {
+ focused.setOnFocusChangeListener(new FollowOutOfActionBar(viewGroup,
+ container, toolbar));
+ } else {
+ if (container != null) {
+ container.setTouchscreenBlocksFocus(true);
+ }
+ if (toolbar != null) {
+ toolbar.setTouchscreenBlocksFocus(true);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Listener interface for ActionBar navigation events.
*
* @deprecated Action bar navigation modes are deprecated and not supported by inline
@@ -1388,4 +1446,43 @@
encoder.addProperty("gravity", gravity);
}
}
+
+ /**
+ * Tracks the focused View until it leaves the ActionBar, then it resets the
+ * touchscreenBlocksFocus value.
+ */
+ private static class FollowOutOfActionBar implements OnFocusChangeListener, Runnable {
+ private final ViewGroup mFocusRoot;
+ private final ViewGroup mContainer;
+ private final ViewGroup mToolbar;
+
+ public FollowOutOfActionBar(ViewGroup focusRoot, ViewGroup container, ViewGroup toolbar) {
+ mContainer = container;
+ mToolbar = toolbar;
+ mFocusRoot = focusRoot;
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (!hasFocus) {
+ v.setOnFocusChangeListener(null);
+ final View focused = mFocusRoot.findFocus();
+ if (focused != null) {
+ focused.setOnFocusChangeListener(this);
+ } else {
+ mFocusRoot.post(this);
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ if (mContainer != null) {
+ mContainer.setTouchscreenBlocksFocus(true);
+ }
+ if (mToolbar != null) {
+ mToolbar.setTouchscreenBlocksFocus(true);
+ }
+ }
+ }
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4ed2fd7..61fd952 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -816,6 +816,7 @@
SharedElementCallback mExitTransitionListener = SharedElementCallback.NULL_CALLBACK;
private boolean mHasCurrentPermissionsRequest;
+ private boolean mEatKeyUpEvent;
/** Return the intent that started this activity. */
public Intent getIntent() {
@@ -2827,9 +2828,25 @@
// Let action bars open menus in response to the menu key prioritized over
// the window handling it
- if (event.getKeyCode() == KeyEvent.KEYCODE_MENU &&
+ final int keyCode = event.getKeyCode();
+ if (keyCode == KeyEvent.KEYCODE_MENU &&
mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+ // Capture the Alt-up and send focus to the ActionBar
+ final int action = event.getAction();
+ if (action == KeyEvent.ACTION_DOWN) {
+ if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
+ final ActionBar actionBar = getActionBar();
+ if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) {
+ mEatKeyUpEvent = true;
+ return true;
+ }
+ }
+ } else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) {
+ mEatKeyUpEvent = false;
+ return true;
+ }
}
Window win = getWindow();
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 9d12803..4b6e7e4 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -29,10 +29,14 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
+import android.view.ViewParent;
import android.view.Window;
import android.view.WindowCallbackWrapper;
import android.widget.SpinnerAdapter;
import android.widget.Toolbar;
+
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.widget.DecorToolbar;
@@ -499,6 +503,12 @@
}
}
+ /** @hide */
+ @Override
+ public boolean requestFocus() {
+ return requestFocus(mDecorToolbar.getViewGroup());
+ }
+
private class ToolbarCallbackWrapper extends WindowCallbackWrapper {
public ToolbarCallbackWrapper(Window.Callback wrapped) {
super(wrapped);
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 05cfd81..c6bf1b4 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -18,6 +18,8 @@
import android.animation.ValueAnimator;
import android.content.res.TypedArray;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Toolbar;
@@ -950,6 +952,12 @@
return false;
}
+ /** @hide */
+ @Override
+ public boolean requestFocus() {
+ return requestFocus(mDecorToolbar.getViewGroup());
+ }
+
/**
* @hide
*/